I was using an Adobe product (If I remember correctly, it was a PDF Creator) the other day, and they have this cool feature where you can literally click anywhere inside the window and just start typing. And the text will appear as you type, whereever you clicked.
Can somebody please point me in the right direction where I can learn how to implement something like this?
Thank you
Edit:
Steps to Click & Type:
Capture MouseDown and store location where user clicked.
Handle KeyDown event to see what key was pressed.
Foreach key that is pressed, create a label and place it next to the last-typed character.
#Qua, in the last step, am I right in thinking that? If so, how would I account for the length of an individual character, so I know where to place the next one? I think I would need to somehow measure the type and size of the font in the label and adjust positioning accordingly...?
You could simply draw a new TextBox on your Windows Form when the user clicks. The MouseClick event will expose all the properties you need to draw the textbox right where they click.
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
TextBox txtBox = new TextBox();
txtBox.Location = new Point(e.X, e.Y);
this.Controls.Add(txtBox);
txtBox.Focus();
}
You could make the TextBox transparent or what not if you wanted to mask the fact that they're typing a normal TextBox.
Lets say that you wanted to implement this feature on a usercontrol that you were making. At first you would need to handle the mouse down event to register where the user clicked, and after this you should be able to handle the key down event to register which keys the user pressed.
To draw the actual text at the target location you have several options. You could use GDI+ to render the strings on the control or you could insert labels which would benefit you due to the amount of functionality that the labels come with.
Here's a prototype example of how it could be implemented using GDI:
private Point? lastSelected;
private Dictionary<Point, string> renderedText = new Dictionary<Point, string>();
private Point LastSelected
{
get
{
return (Point)lastSelected;
}
}
private void Form1_Load(object sender, EventArgs e)
{
this.MouseDown += Form1_MouseDown;
this.KeyDown += Form1_KeyDown;
this.Paint += Form1_Paint;
}
void Form1_Paint(object sender, PaintEventArgs e)
{
foreach (KeyValuePair<Point, string> pair in renderedText)
{
e.Graphics.DrawString(pair.Value, new Font("Arial", 12), Brushes.Black,
pair.Key);
}
}
void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (lastSelected != null)
{
if (!renderedText.ContainsKey(LastSelected))
{
renderedText.Add(LastSelected, "");
}
renderedText[LastSelected] = renderedText[LastSelected] + e.KeyCode;
this.Invalidate();
}
}
void Form1_MouseDown(object sender, MouseEventArgs e)
{
lastSelected = e.Location;
}
Reply to comment:
The above code captures the location of the mouse when the user clicks on the form and saves it in the lastSelected variable. At each subsequent key press on the form the key pressed is appended to the string representing that location. Furthermore the strings are being rendered on the screen at the captured location in the paint. The strings are rendered using GDI+, which means that you don't need to worry about the length of the individual characters.
Note that for a real application storing the locations and strings via a hashtabel (dictionary in C#) is not a great idea. You should rather create a custom class or structure that will hold the information such as location, text ect. This will allow you to further improve the functionality by adding options for stuff like bolding, italic, font sizes and so on.
Related
I have created a text box, inside a PictureBox, on mouse click at run time. Now I want to resize it using mouse drag. Is there some simple way to do this ?
Here is the code I have so far:
public partial class Form1 : Form
{
public static TextBox PTB; //declaring text box to be created
public static bool textOption; //stores the state of button , i.e whether or not text box button is clicked before or not
public Form1()
{
InitializeComponent();
this.pictureBox1.Click += new System.EventHandler(this.pictureBox1_Click);
}
private void pictureBox1_Click(object sender, EventArgs e)
{
if (textOption == true)//if user selected option to draw text box
{
MouseEventArgs eM = (MouseEventArgs)e; //create an instance of mouse event
PTB = new TextBox();//dynamically creating text box
PTB.Location = new System.Drawing.Point(eM.X, eM.Y);//settign position of textbox where mouse was clicked
PTB.Name = "textBox1";
PTB.Size = new System.Drawing.Size(100, 20);//size of text box
this.pictureBox1.Controls.Add(PTB);//adding the textbox to the picture box
}
}
Update
I'm sorry I have totally misread your question.
The reason is probably that you seem to be under the impression that Paint programs have TextBoxes sitting on their canvas. They don't. They draw text the same way as they draw lines or circles etc..
Also: Resizing the TextBox will not change the Font size, in case that's is what you want.
Finally: A TextBox will never be transparent, it will always sit on the PictureBox and look, well, like a TextBox. Not like anything in a Paint programm..
But: If you actually do want to resize the TextBox here are a few hints:
You need some way to show the user they are on the right spot by changing the cursor to the right icon
You need to store the mouse down point (attention: it will be inside the TextBox!) and keep track of the increments in the MouseMove. As long as the Button is down all rported e.Location will still be in the TextBox coordinates.
Use the increments (not the absolute values) to increase the size of the TextBox.
It is really hard to get the resizing right on the top and left sides. (Because it will involve moving at the same time), so better don't try!
Do include moving, which is easy and will suffice for all you need.
No, this is a good deal harder than increasing font size. 200-300 lines of code, the last time I did it..
But you may find another somewhat simpler answer; look for "Resize Control with Mouse winforms c#" on Google..
I leave the old answer in place, even if it not what you were looking for..
Old answer about changing font size while placing text:
It is not very hard but you need to get it right; it is basically the same as drawing a Rectangle
with a live preview. You need these things: four events, a Point or two, a Size and a font variable..
The events are:
MouseDown
MouseMove
MouseUp
Paint
You need to store a point for the placement (in the MouseDown event) and a size you update in the MouseMove.
From that size you can calculate the maximum Font size you can fit in the Rectangle.
On MouseUp you finalize things.
In the Paint event you draw string at the down Point with the current Font size.
In the MouseMove you call Invalidate on the PictureBox to trigger the Paint event.
in the MouseMouve you should check the Button to be the left one.
For extra good UI you can also check the keyboard for space and use it to move the DownPoint..
The Click event is rather useless, btw..
Here is a minimal code example to get you started:
Point mDown = Point.Empty;
float fSize = 12f;
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (Font font = new Font("Consolas", fSize))
e.Graphics.DrawString("Hello World", font, Brushes.Black, mDown);
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
mDown = e.Location;
pictureBox1.Invalidate();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
fSize = Math.Abs(e.Y - mDown.Y) / 2f + 1;
pictureBox1.Invalidate();
}
I left out the MouseUp. Here you would store the final state (font, location..) of the drawn string somewhere or persist it by drawing into a Bitmap etc..
I also didn't do a full Rectangle calculation but determined the font size by simply scaling the y-movement down a little.. You could improve with a little pythagoras ;-)
The ability to resize a window is innate behavior, provided by the default window procedure built into Windows. All you have to do is give the control a resizable border. Everything else is for free, you'll get the correct cursor and dragging a corner or edge resizes the control.
using System;
using System.Windows.Forms;
class ResizeableTextBox : TextBox {
protected override CreateParams CreateParams {
get {
var cp = base.CreateParams;
cp.Style |= 0x840000; // Turn on WS_BORDER + WS_THICKFRAME
return cp;
}
}
}
This sample will create the TextBox on the MouseDown event and start resizing, the final size of the TextBox will be where the mouse button is released on the MouseUp event. It will let you create multiple textboxes as well.
I realize this might not be exactly what you want but it might be a start.
private int _textBoxCounter;
private TextBox _textBoxCurrentResizing;
public Form1()
{
InitializeComponent();
pictureBox1.MouseDown += PictureBox1OnMouseDown;
pictureBox1.MouseUp += PictureBox1OnMouseUp;
pictureBox1.MouseMove += PictureBox1OnMouseMove;
}
public Point RelativeMousePosition { get { return PointToClient(MousePosition); } }
private void PictureBox1OnMouseMove(object sender, MouseEventArgs mouseEventArgs)
{
ResizeTextBox();
}
private void PictureBox1OnMouseUp(object sender, MouseEventArgs mouseEventArgs)
{
EndResizeTextBox();
}
private void PictureBox1OnMouseDown(object sender, MouseEventArgs mouseEventArgs)
{
var tb = CreateTextBox();
StartResizeTextBox(tb);
}
private TextBox CreateTextBox()
{
var tb = new TextBox
{
Location = RelativeMousePosition,
Size = new Size(100, 20),
Multiline = true,
Name = "textBox" + _textBoxCounter++,
};
pictureBox1.Controls.Add(tb);
return tb;
}
private void StartResizeTextBox(TextBox tb)
{
_textBoxCurrentResizing = tb;
}
private void ResizeTextBox()
{
if (_textBoxCurrentResizing == null) return;
var width = Math.Abs(_textBoxCurrentResizing.Left - RelativeMousePosition.X);
var height = Math.Abs(_textBoxCurrentResizing.Top - RelativeMousePosition.Y);
_textBoxCurrentResizing.Size = new Size(width, height);
}
private void EndResizeTextBox()
{
_textBoxCurrentResizing = null;
}
My son and I are working on a hobby project together (Winform app) for the dice game of Farkle and need guidance on handling dragdrop events for the dice. Please note we are not looking for the answer, or the code; just some general ideas on solution attack.
Here are the constructs:
RolledDice
—We have a single form with two panels. One panel contains 6 PictureBoxes which display dice images from an ImageList based on a DiceRoller class we built to generate random integers from 1 to 6. We are using a backing PictureBox array to iterate over each of the PictureBoxes. The click event for a “Roll Dice” button displays the rolled dice—all is good, this works great.
PlayerDice
—The second panel is configured identically to the first one and accepts user selected dice dragged from the Rolled Dice panel. Our use case requires the ability for the user to drag dice from the Rolled Dice panel to the Player Dice panel, and back again if the user changes their mind about the dice they want to keep—all is good, this works great.
Problem Statement
—Although we can drag dice from the Rolled Dice panel to the Player Dice panel (and update the backing PictureBox arrays in the process), it seems necessary to have three event handlers for each of the 6 PictureBoxes in both panels (MouseDown, DragEnter and DragDrop), and this amounts to a ton of code.
Question
—Is there an elegant way to have one set of these 3 event handlers for ALL Rolled Dice and one set of these event handlers for ALL Player Dice, rather than having a bunch of stringy code like we have now?
Again, we are not looking for the exact answer or the code, just some general ideas on solution attack.
EDITED:
Here is the code we have for ONE image.
#region Mouse and Drag Events
// Mouse and Drag Events for ONE Rolled Dice
void pbRolled1_MouseDown(object sender, MouseEventArgs e)
{
PictureBox source = (PictureBox)sender;
DoDragDrop(source.Image, DragDropEffects.Move);
}
void pbRolled1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Bitmap))
e.Effect = DragDropEffects.Move;
}
void pbRolled1_DragDrop(object sender, DragEventArgs e)
{
PictureBox destination = (PictureBox)sender;
destination.Image = (Bitmap)e.Data.GetData(DataFormats.Bitmap);
}
// Mouse and Drag Events for ONE Player Dice
void pbPlayer1_MouseDown(object sender, MouseEventArgs e)
{
PictureBox source = (PictureBox)sender;
DoDragDrop(source.Image, DragDropEffects.Move);
}
void pbPlayer1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Bitmap))
e.Effect = DragDropEffects.Move;
}
void pbPlayer1_DragDrop(object sender, DragEventArgs e)
{
PictureBox destination = (PictureBox)sender;
destination.Image = (Bitmap)e.Data.GetData(DataFormats.Bitmap);
}
#endregion
You don't necessarily need to have a 1-to-1 relationship between controls and their events - events may be shared between controls.
Since you don't want a specific answer, I'll give you a general example. Take this simple form, with three buttons and a label:
Now, the code for this simple form is as follows (Form1.cs):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.button1.Click += new System.EventHandler(this.button_Click);
this.button2.Click += new System.EventHandler(this.button_Click);
this.button3.Click += new System.EventHandler(this.button_Click);
}
private void button_Click(object sender, EventArgs e)
{
Button button = (sender as Button);
if (button != null)
{
label1.Text = string.Format("You pressed {0}", button.Text);
}
}
}
You could add the events in Design mode, and select the same event for each. I hooked up the events in the constructor just to make it a little more obvious example.
Notice that all three button click handlers point to a single event handler. That handler will look at the sender of the event to see which button was pressed. It then just takes the caption of the button, and displays it in a message in the label.
You can do the similar things with the duplicate events you are creating now (especially after looking at the code you added to your question).
Well the mouse events are handled by the Windows form so that implementation will need to be done on the form but for the drag events you could have your picture boxes implement the IDropTarget interface so that code could be consolidated and give you some reuse and cleaner code.
I have a program that uses OpenTk.GLControl. Now on my listener, every time the mouse hovers to the said control, say "glControl1", I want to get the mouse coordinates.
Is that possible? sample code below.
private void glControl1_MouseHover(object sender, EventArgs e)
{
// get the current mouse coordinates
// .........
}
OpenTK.GLControl inherits from System.Windows.Forms.Control. You can use the following code snippet to get the mouse position:
private void glControl1_MouseHover(object sender, EventArgs e)
{
Control control = sender as Control;
Point pt = control.PointToClient(Control.MousePosition);
}
Please refer to the MSDN WinForms documentation for more information.
The problem is that you're using the wrong event. Many UI actions in WinForms trigger multiple events per action; Hover is used for things like popping up tooltips. You don't get a coordinate in Hover because it's unnecessary.
What you want is the MouseMove event. This is used to track the mouse position:
private void glControl1_MouseMove(object sender, MouseEventArgs e)
{
foo = e.X;
bar = e.Y;
}
I dont know, what is OpenTk.GLControl, but:
I was handling swipe events on Windows Phone and did this:
private void PhoneApplicationPage_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//string to save coordinates of tap
TapCoordinatesXBegin = e.GetPosition(LayoutRoot).X.ToString();
TapCoordinatesYBegin = e.GetPosition(LayoutRoot).Y.ToString();
}
And i dont remember such event MouseHover - maybe MouseEnter?
I have the following problem: I have a panel which has a specific color, say red.
When the user presses his mouse, the color of this panel gets stored in a variable. Then the user moves, his mouse still pressed, over to another panel. When he releases the mouse there, this panel should get the background color of the first that had been stored in the variable. My code looks something like this:
public Color currentColor;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
private void AttempsColorChanger(object sender, MouseEventArgs e)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
}
I need to identify the sender first because there are many possible panels that can trigger this event. The first MouseDown method works totally fine, the color is stored nicely in the variable. The secon one however doesn't even get triggered when the user does what I described above. When the ser clicks on the second panel, it works (there is an MouseUp part in a click aswell I guess).
What's wrong here? Why is the event not triggered when the user holds the mouse key down before?
(This answer assumes you are using Windows Forms.)
It could be that you need to capture the mouse by setting this.Capture = true in the MouseDown of the source control. (See Control.Capture)
If you did that, the source window would get the MouseUp event, and it would be the source window that had to determine the destination window under the mouse coords. You can do that using Control.GetChildAtPoint() (see this answer on Stack Overflow).
Use Windows Forms Drag and Drop Support Instead! <- Click for more info
I'm going to suggest you bite the bullet and use the .Net Drag and Drop methods to do this. It requires some reading up, but it will be much better to use it.
You start a drag in response to a MouseDown event by calling Control.DoDragDrop().
Then you need to handle the Control.DragDrop event in the drop target control.
There's a few more things you might need to do to set it up; see the Control.DoDragDrop() documentation for an example.
(For WPF drag and drop support, see here.)
when your mouse enter the target control , mouse down triggerd ang get target BackColor! you need add an boolean flag to your code :
public Color currentColor;
bool flag=false;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
if(flag==false)
{
flag=true
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
}
//assume mouse up for panles
private void AttempsColorChanger(object sender, MouseEventArgs e)
{
if(flag==true)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
flag=flase;
}
}
and also you need change your flag in mouseMove( if )
As I mentioned in my comment Mouse Events are captured by the originating control, You would probably be better off using the DragDrop functionality built into Windows Forms. Something like this should work for you. I assigned common event handlers, so they can be assigned to all of your panels and just work.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void panel_MouseDown(object sender, MouseEventArgs e)
{
((Control)sender).DoDragDrop(((Control)sender).BackColor,DragDropEffects.All);
}
private void panel_DragDrop(object sender, DragEventArgs e)
{
((Control)sender).BackColor = (Color)e.Data.GetData(BackColor.GetType());
}
private void panel_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
}
I know it's an old question but I had the same issue and none of the above answers worked for me. In my case I had to handle the MouseMove event in the target control and check for the mouse to be released. I did set 'BringToFront' on my target panel just in case that helped at all.
public Color currentColor;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
private void panelTarget_MouseMove(object sender, MouseEventArgs e)
{
//the mouse button is released
if (SortMouseLocation == Point.Empty)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
}
}
In my Windows forms application written in C# I have a bunch of buttons. When the user's mouse hovers over a button, I want the button's border to change.
Currently I have multiple instances of the following (a copy for each button):
private void btnStopServer_MouseEnter(object sender, EventArgs e)
{
oldColor = btnStopServer.FlatAppearance.BorderColor;
btnStopServer.FlatAppearance.BorderColor = mouseOverColor;
}
private void btnStopServer_MouseLeave(object sender, EventArgs e)
{
btnStopServer.FlatAppearance.BorderColor = oldColor;
}
Since I have a lot of buttons, the code to change the color of the button's border takes up a lot of space.
Is there any simpler way that I could do this?
You should wire-up a single MouseEnter and MouseLeave to each control that needs this functionality (rather than writing a new version of each method for each control). Assuming you're using Visual Studio, this can be done by changing the target method name for the event, in each Button's property pane. If you write the following code first, then this method will appear in the property's MouseEnter and MouseLeave events' drop-down lists.
The code would then need to check which button from which the event was fired, as follows:
private void btnWithHoverBorder_MouseEnter(object sender, EventArgs e)
{
Button eventButton = (Button) sender;
oldColor = eventButton.FlatAppearance.BorderColor;
eventButton.FlatAppearance.BorderColor = mouseOverColor;
}
private void btnWithHoverBorder_MouseLeave(object sender, EventArgs e)
{
Button eventButton = (Button) sender;
eventButton.FlatAppearance.BorderColor = oldColor;
}
I presume oldColor is a global? This might get out of sync if something "odd" happens where your MouseEnter event is fired for another button, before the corresponding MouseLeave is caught. To make this more robust, I'd consider storing the old color on the Button's .tag property, so that it's self-contained.
Eg:
private void btnWithHoverBorder_MouseEnter(object sender, EventArgs e)
{
Button eventButton = (Button) sender;
eventButton.tag = eventButton.FlatAppearance.BorderColor;
eventButton.FlatAppearance.BorderColor = mouseOverColor;
}
private void btnWithHoverBorder_MouseLeave(object sender, EventArgs e)
{
Button eventButton = (Button) sender;
eventButton.FlatAppearance.BorderColor = (Color)eventButton.tag;
}
(The tag is basically a hook on which to tag "anything" relevant to a specific instance of a control, that there is not already a property for. It's of type Object which means you can tag anything there, but when you read from it, you need to cast it back to whatever type you put there in the first place. But because it's an Object you can put anything there, including eg a custom class that contains multiple properties, or an array, etc if you need to tag a control with more than one thing).