I'm trying to develop my applications to create buttons like so:
private void button1_Click(object sender, EventArgs e)
{
int top = 150;
int left = 150;
for (int i = 0; i < 1; i++)
{
Button button = new Button();
button.Left = left;
button.Top = top;
this.Controls.Add(button);
top += button.Height + 2;
}
}
This is working how I intend, to an extent. I want to be able to create these buttons with certain properties, but I don't know how to access individual buttons.
Now, I also want to be able to move these buttons by holding down the mouse button and dragging them, then releasing them where I want. Here's what I've got from certain online resources and whatnot.
public Form3()
{
InitializeComponent();
button1.MouseDown += button1_MouseDown;
}
private Point MouseDownLocation;
private void button1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
MouseDownLocation = e.Location;
}
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
button1.Left = e.X + button1.Left - MouseDownLocation.X;
button1.Top = e.Y + button1.Top - MouseDownLocation.Y;
}
}
Any help would be appreciated.
If you want to have access to individual buttons you can try to make global list:
List<button> buttons = new List<button>();
And add them in for like:
Button button = new Button();
button.Left = left;
button.Top = top;
this.Controls.Add(button);
top += button.Height + 2;
buttons.add(button);
Next, looking at function button1_MouseMove - it works only if mouse cursor is inside the button? Should it work like this?
If button is clicked you can look at the list to find which button is clicked and move it - your method looks ok.
Related
I'm hooking my form with middle click. And for now i middle click to hook my form then middle click again to trigger my method to draw on my picturebox (which is on my form).
I'd like to middle click once and instantly draw on my picturebox instead of two middle click. I tried MouseHover and MouseEnter with this code :
private void PbxDrawing_MouseEnter(object sender, EventArgs e)
{
bMoving = true;
Point pos = PbxDrawing.PointToClient(Cursor.Position);
x = pos.X;
y = pos.Y;
}
Mouse move :
private void PbxDrawing_MouseMove(object sender, MouseEventArgs e)
{
if(bMoving && x!=-2 && y != -2)
{
g.DrawLine(pen,new Point(x,y), e.Location);
x = e.X;
y = e.Y;
}
}
It allows me to know the position of the cursor and draw but to draw i've to release middle click .
How can i draw from 1 middle click if my middle click was made outside of my form ?
Edit : Clarify question
Just check if the Middle Button is down in the MouseMove event:
private void PbxDrawing_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle)
{
x = e.X;
y = e.Y;
}
}
private void PbxDrawing_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle)
{
g.DrawLine(pen, new Point(x, y), e.Location);
x = e.X;
y = e.Y;
}
}
Your use of g is a red flag, though. Is g created with PbxDrawing.CreateGraphics()? If yes, this is wrong and should be refactored to use the e.Graphics from the Paint() event of the PictureBox.
How to move a pictureBox inside a Panel by Mouse.
Visual Studio 2015 C# Winsows Forms Application.
I've made a primitive slider to control the volume of my WindowsMediaPlayer.
A panel as the background and a pictureBox inside as the slider-knopf.
And it works well.
But purely visually it does not work that good.
I'v searched all around, but can't I find an answer to this little funny problem.
Here is my code:
int posY;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
posY = e.Y; ;
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
PictureBox box = sender as PictureBox;
if (e.Button == MouseButtons.Left)
{
box.Top += e.Y - posY;
}
if (box.Top < 0)
{
box.Top = 0;
}
if (box.Top > 100)
{
box.Top = 100;
}
int n = box.Top;
n = n * - 1 + 100;
label1.Text = n.ToString();
}
When I move the pictureBox out of the edge of the little panel, the pictureBox somehow 'shrinks' in the panel.
But when I release the mouse, the pictureBox restore its size.
Slider.gif
Why is that.?
And how can I avoid it.?
Thanks.
I found a solution.
It's not optimal, but it can be used.
I changed the code to:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
dragging = true;
startPoint = e.Location;
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (dragging)
{
Debug.WriteLine("mousemove X: " + e.X + " Y: " + e.Y);
pictureBox1.Location = new Point(0, pictureBox1.Top + e.Location.Y - startPoint.Y);
if (pictureBox1.Location.Y < 0)
{
pictureBox1.Location = new Point(0, 0);
dragging = false;
}
if (pictureBox1.Location.Y > 100)
{
pictureBox1.Location = new Point(0, 100);
dragging = false;
}
this.Refresh();
}
int n = pictureBox1.Location.Y;
n = n * -1 + 100;
label1.Text = n.ToString();
mediaPlayer1.settings.volume = n;
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
dragging = false;
}
gif
I still need to put an 'if' to correct, when the pictureBox1 is pulled out of the panel.
And to avoid flicker, I have had to put a 'dragging = false'.
However, it results in the pictureBox1 is getting frozen to the edge, so I have to release the mouse, and re-click to continue.
But well - it's to live with.
Thanks.
I have a picture in PNG with transparent and normal color.
I use this for one Button:
this.Button1.BackColor = System.Drawing.Color.Transparent;
this.Button1.BackgroundImage = Image;
this.Button1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.Button1.FlatAppearance.BorderSize = 0;
this.Button1.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Transparent;
this.Button1.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Transparent;
this.Button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.Button1.Location = new System.Drawing.Point(0, 0);
this.Button1.Margin = new System.Windows.Forms.Padding(0);
this.Button1.Name = "Skin";
this.Button1.Size = new System.Drawing.Size(294, 194);
this.Button1.TabIndex = 7;
this.Button1.UseVisualStyleBackColor = false;
And I when I click at transparent area, it still counts as a click on the Button.
How can I make this Button only call click event when I click at the colored area?
And when I click at the transparent area, I want it to count as a click on the object behind this button.
You have two options:
Use a Button with a Region.
Use a Button with a BackgroundImage and check what the user hits with each Click
Option one is only feasible if you can create a Region, which takes a GraphicsPath, which means that you need to create the shape you need from the Graphics primitves like lines and curves etc..
If you only have a Bitmap with transparency, you are better off not using a Button with a Region.
Instead you can use your Button1 and on every click you check the transparency of the clicked pixel.
If it is transparent you call the click event of the control below it..
private void Button1_MouseClick(object sender, MouseEventArgs e)
{
Size r = Button1.BackgroundImage.Size;
// check that we have hit the image and hit a non-transparent pixel
if ((e.X < r.Width && e.Y < r.Height) &&
((Bitmap)Button1.BackgroundImage).GetPixel(e.X, e.Y).A != 0)
{
Console.WriteLine("BUTTON clicked"); // test
// do or call your click actions here!
}
// else pass the click on..
else
{
// create a valid MouseEventArgs
MouseEventArgs ee = new MouseEventArgs(e.Button, e.Clicks,
e.X + Button1.Left, e.Y + Button1.Top, e.Delta);
// pass it on to the stuff below us
pictureBox1_MouseClick(pictureBox1, ee);
Console.WriteLine("BUTTON NOT clicked"); // test
}
}
Note that the check assumes that you have a normal layout, with the button image at the top left and no scaling. If you need to scale the image you should keep a scaled bitmap to do the checks on.. But if you can use an unscale image you should do so, as this will look better.
Note how I create a correct MouseEventArgs parameter for the control below, so you can access the button or the location of the mouse there as well..
Also note that it is easier to use the MouseClick event instead of the Click event as it has the mouse location already..
If you need/want to use the Click event instead, you can skip creating the EventArgs, as it doesn't have meaningful data; just pass out the e from the click..
Here is how the Click event could start:
private void Button1_Click(object sender, EventArgs e)
{
// we need the location of the clicked pixel:
Point clickLocation = Button1.PointToClient(Control.MousePosition);
// the rest can proceed as above, just with simple EventArgs..
If you want to the check on all mouse clicking event and pass each of them down to the parent you will have to code them all.
First let's look at the order of events on MSDN
MouseDown event.
Click event.
MouseClick
MouseUp event.
So we need to start at the MouseDown. We can do the test in a helper function hitTest, so we can re-use it..:
Button clickedButton = null;
MouseEventArgs ee = null;
void hitTest(Button btn, MouseEventArgs e)
{
Size r = btn.BackgroundImage.Size;
// check that we have hit the image and hit a non-transparent pixel
if ((e.X < r.Width && e.Y < r.Height) &&
((Bitmap)btn.BackgroundImage).GetPixel(e.X, e.Y).A != 0)
{
clickedButton = btn;
ee = new MouseEventArgs(e.Button, e.Clicks, e.X + btn.Left, e.Y + btn.Top, e.Delta);
}
else clickedButton = null;
}
Now we code all four events. We need to call hitTest only once and we pass the simple, unmodified e parameter in the Click event:
private void Button1_MouseDown(object sender, MouseEventArgs e)
{
hitTest(sender as Button, e);
if (sender != clickedButton)
yourParent_MouseDown((sender as Button).Parent, ee);
else // do your stuff
}
private void Button1_Click(object sender, EventArgs e)
{
if (sender != clickedButton)
yourParent_Click((sender as Button).Parent, e);
else // do your stuff
}
private void Button1_MouseClick(object sender, MouseEventArgs e)
{
if (sender != clickedButton)
yourParent_MouseClick((sender as Button).Parent, ee);
else // do your stuff
}
private void Button1_MouseUp(object sender, MouseEventArgs e)
{
if (sender != clickedButton)
yourParent_MouseUp((sender as Button).Parent, ee);
else // do your stuff
}
Of course you need to code all four events for yourParent also..
I have a panel with 07 buttons that can move them left or right without problems using "drag and drop". My problem is that when I put a button on top of an existing one. I put the button where it already existed 43 button 45 and button 43 is below 45 as shown.
This is my code
private void panelAtalhos_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void panelAtalhos_DragDrop(object sender, DragEventArgs e)
{
//create the button - treeview item selected
Button bt = new Button();
if (createbutton) // createbutton is a global variable
{
bt.Width = 38;
bt.Height = 34;
bt.Top = 2;
bt.Left = panelAtalhos.Controls.Count * (bt.Width);
bt.FlatAppearance.BorderSize = 0;
DateTime data = DateTime.Now;
bt.Text = data.ToString("ss");
bt.FlatStyle = FlatStyle.Flat;
panelAtalhos.Controls.Add(bt);
bt.MouseDown += button_MouseDown;
createbutton = false;
}
else
{
int resto = (int)(System.Windows.Forms.Cursor.Position.X / 38);
((Button)e.Data.GetData(typeof(Button))).Left = resto * 38;
}
}
private void button_MouseDown(object sender, MouseEventArgs e)
{
(sender as Button).DoDragDrop(sender as Button, DragDropEffects.Move);
criarbotao = false;
}
What is missing in the code?
int resto = (int)(System.Windows.Forms.Cursor.Position.X / 38);
You have two problems. One is the Z-order, the other is this statement. It is not correct, you must map the absolute cursor position to the relative position for the button. Relative from the client area of its parent, the panel. Right now you're sending it off into the weeds, too far to the right. Easily far enough that it won't be visible anymore. Code ought to resemble:
var btn = (Button)e.Data.GetData(typeof(Button));
var pos = btn.Parent.PointToClient(Cursor.Position);
btn.Left = (pos.X / 38) * 38;
btn.BringToFront();
Hello I have found this code that might help me with following issue, I'm trying to make drag, drop and move label in my Form by mouse.
private Point MouseDownLocation;
private void MyControl_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
MouseDownLocation = e.Location;
}
}
private void MyControl_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
this.Left = e.X + this.Left - MouseDownLocation.X;
this.Top = e.Y + this.Top - MouseDownLocation.Y;
}
}
But when I assing mousemove and mousedown as events to label and i try to grab the label and move with mouse it moves with the whole Form.
May I ask where is should the code be improved?
Thank you for your time.
Instead of using this.Left (which is the form), you need to move your control:
private void MyControl_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
MyControl.Left = e.X + MyControl.Left - MouseDownLocation.X;
MyControl.Top = e.Y + MyControl.Top - MouseDownLocation.Y;
}
}
In addition, you may want to capture the mouse on button down, and release it on button up. That will prevent very fast movements from "breaking" your logic. For details, see Mouse Capture in Windows Forms.