I have many labels on a picturebox. I want to move a label with respect to cursor, but label should stop moving when there is another label in the moving direction
Here is my code
void lbl_MouseClick(object sender, MouseEventArgs e)
{
try
{
lblCutPaste = sender as Control;
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
void lbl_MouseDown(object sender, MouseEventArgs e)
{
try
{
activeControl = sender as Control;
previousLocation = e.Location;
// preloc = activeControl.Location;
Cursor = Cursors.Hand;
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
void lbl_MouseMove(object sender, MouseEventArgs e)
{
try
{
bool isCollide = false;
if (activeControl == null || activeControl != sender)
return;
var location = activeControl.Location;
location.Offset(e.Location.X - previousLocation.X, e.Location.Y - previousLocation.Y);
if (location.X >= 0 && location.X <= activeControl.Parent.Width - activeControl.Width && location.Y >= 0 && location.Y <= activeControl.Parent.Height - activeControl.Height)
{
activeControl.Location = location;
}
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
void lbl_MouseUp(object sender, MouseEventArgs e)
{
activeControl = null;
Cursor = Cursors.Default;
}
Here is a working example; you will have to adapt your code after studying it. It shouldn't be hard to pull out the lambda into your events.
It first creates 20 Labels and add them onto a PictureBox. It hooks up each Label with three events. It colors the active Label while it is being dragged.
Each Label is also added to a class level List<T> so we can easily do the check we need. The check is using LINQ to count all overlapping labels.
It makes use of the Rectangle.IntersectsWith and Point.Subtract methods ..
List<Label> myLabels = new List<Label>();
Label movingLabel = null;
Point mDown = Point.Empty;
private void button11_Click(object sender, EventArgs e)
{
Random R = new Random(8);
Size sz = pictureBox1.ClientSize;
for (int i = 0; i < 20; i++)
{
Label lbl = new Label() {Text = "L " + i};
lbl.Location = new Point(R.Next(sz.Width), R.Next(sz.Height));
lbl.Parent = pictureBox1;
myLabels.Add(lbl);
lbl.BorderStyle = BorderStyle.FixedSingle;
lbl.MouseDown += (ss, ee) =>
{
movingLabel = lbl;
lbl.BackColor = Color.Bisque;
mDown = ee.Location;
};
lbl.MouseMove += (ss, ee) =>
{
if (ee.Button == MouseButtons.Left)
{
Point nLoc = Point.Subtract(lbl.Location,
new Size(mDown.X - ee.X, mDown.Y - ee.Y));
Rectangle rlbNew = new Rectangle(nLoc, lbl.Size);
var overlapped = myLabels.Where(x => x != lbl &&
rlbNew.IntersectsWith(new Rectangle(x.Location, x.Size)));
if (overlapped.Count() == 0) lbl.Location = nLoc;
}
};
lbl.MouseUp += (ss, ee) =>
{
movingLabel = null;
lbl.BackColor = Color.Transparent;
};
}
}
Note that I didn't care whether the created Labels overlap, so some do and as they do can't be moved apart unless you keep dragging until reaches a 'legal' one; then it will jump over the overlapped label and to the new position..
If you wanted you could code logic to allow overlapping while moving, make the backcolor red to show that this is not ok and have it jump back on MouseUp if it still overlaps. You will need to store the original position for this.. But dragging to a legal position as it is may well be good enough, imo..
Related
I am doing a Windows Form Application in c# in which I create a panel for every click i do in "Panel_Inside".
But my problem is when I have to select one especific panel. I do not know how can I identify each panel.
Also I'm having problems when Dragging and Dropping for the same reason.
public void Coloco_Figura(string figura, int Punto_X, int Punto_Y)
{
panel_foto = new Panel();
panel_foto.BackColor = Color.Transparent; //saco fondo
panel_foto.BackgroundImage = Image.FromFile(figura); //asigno imagen al panel
panel_foto.BackgroundImageLayout = ImageLayout.Stretch;
panel_foto.Size = new Size(45, 45);
panel_foto.Location = new Point(Punto_X - 10, Punto_Y - 10);
panel_foto.BringToFront();
panel1.SendToBack();
panel_inside.Controls.Add(panel_foto);
dame_x = Punto_X;
this.panel_foto.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MouseDown);
this.panel_foto.MouseUp += new System.Windows.Forms.MouseEventHandler(this.MouseUp);
this.panel_foto.MouseMove += new System.Windows.Forms.MouseEventHandler(this.MouseMove);
}
here are mouse events
private void MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
# region Borrar Notas
if (Estado_Borro == true)
{
foreach (Panel p in panel_inside.Controls)
{
if (p is Panel)
{
panel_inside.Controls.Remove(p);
if (panel_inside.Controls.Count == 0)
{
listanotas.Clear();
}
else
{
for (int i = 0; i < listanotas.Count; i++)
{
Notas nota = listanotas[i];
if (nota.posX == dame_x)
{
listanotas.Remove(nota);
}
}
}
}
}
Estado_Borro = false;
}
if (e.Button == MouseButtons.Left)
{
drag = true;
x = e.X;
y = e.Y;
}
}
public void MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
drag = false;
}
public void MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (drag)
{
this.panel_foto.Location = new Point(Cursor.Position.X-this.Left, Cursor.Position.Y-this.Top);
}
To identify each panel, first you must set the Name or Tag property:
panel_foto.Name = "panel_foto1";
Then in your event handler,do something like this:
Panel p=(Panel)sender;
if (p.Name == "panel_foto1")
{
//Do your staff
}
How can I change the BackColor of a label in an array when I click on it? Since there are multiple elements, I cannot manually activate each event for each individual label.
for (int i = 0; i < 361; i++)
{
board[i] = new Label();
board[i].Parent = pictureBox1;
board[i].Location = new Point(x, y);
board[i].Name = "label" + i;
board[i].BackColor = Color.Black;
//set size of labels
board[i].Size = new Size(30, 30);
//initialize click event handler
this.board[i].Click += new System.EventHandler(this.labelClick);
}
private void labelClick (object sender, EventArgs e)
{
foreach (Label i in board)
{
if (iteration % 2 == 0)
{
i.BackColor = Color.Black;
iteration++;
}
else if(iteration % 2 == 1)
{
i.BackColor = Color.White;
iteration++;
}
}
}
There are a few ways you can handle this. One way is to wire each Labels Click event up to the same event:
this.label1.Click += new System.EventHandler(this.label_Click);
this.label2.Click += new System.EventHandler(this.label_Click);
this.label3.Click += new System.EventHandler(this.label_Click);
In the label_Click event you can set the BackColor of each label OR just the one you clicked on.
// This will set each label's BackColor to Red.
private void label_Click(object sender, EventArgs e)
{
foreach (Label label in labelArray)
{
label.BackColor = Color.Red;
}
}
// This will set just the clicked on Label's BackColor to Red.
private void label_Click(object sender, EventArgs e)
{
Label label = sender as Label;
if (label != null)
{
label.BackColor = Color.Red;
}
}
var labels = new[]
{
// labels here
};
foreach (var label in labels)
{
label.Click += (sender, args) =>
{
var lbl = sender as Label;
Debug.Assert(lbl != null);
lbl.BackColour = Colors.Pink;
};
}
I am pretty new to C# and struggle a lot with a small project I want to do.
I am busy with something like a collage maker where I have a list of pictures on the left hand side and I want to drag and drop multiple images to the right hand side where I want to be able to move them around to create my collage.
I wanted to show an image but I am not allowed to post images with less than 10 reputation points. But look here for the image:
I can't manage to get it to work. I've looked online for help but I can't really find what I'm looking for. The stuff I do find are too unclear and I struggle to understand.
This is what I have so far for the code to drag and drop from the left to the right but it doesn't work;
private void pictureBox1_DragEnter(object sender, DragEventArgs e)
{
int len = e.Data.GetFormats().Length - 1;
int i;
for (i = 0; i <= len; i++)
{
if (e.Data.GetFormats()[i].Equals("System.Windows.Forms.ListView+SelectedListViewItemCollection"))
{
//The data from the drag source is moved to the target.
e.Effect = DragDropEffects.Move;
}
}
}
private void pictureBox1_DragDrop(object sender, DragEventArgs e)
{
//Return if the items are not selected in the ListView control.
if (listView1.SelectedItems.Count == 0)
{
return;
}
ListViewItem dragitem = listView1.SelectedItems[0];
pictureBox2.Image = imageList1.Images[dragitem.ImageIndex];
listView1.Items.Remove(dragitem);
}
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
listView1.DoDragDrop(listView1.SelectedItems, DragDropEffects.Move);
}
And after I can add image to the left, how can I drag and move them around using the mouse coordinates?
Any help will be appreciated please.
Everything is done using C# in Windows Forms.
Here is a full example you may want to play with:
It uses a form with a ListView, an ImageList and a Panel to hold the PictureBoxes.
You could use a FlowLayoutPanel but this won't let you move the Pictureboxes later.
You also could use a grid of Panels and their BackgroundImage.
First we set up the form:
private void Form1_Load(object sender, EventArgs e)
{
KeyPreview = true;
FillLV(10);
AddPBs(36);
listView1.MouseMove += listView1_MouseMove;
}
void FillLV(int count)
{
for (int i = 0; i < count; i++) listView1.Items.Add("Item" + i, i);
}
void AddPBs(int count)
{
int iWidth = imageList1.ImageSize.Width;
int iHeight = imageList1.ImageSize.Height;
int cols = panel1.ClientSize.Width / iWidth;
for (int i = 0; i < count; i++)
{
PictureBox PB = new PictureBox();
PB.BackColor = Color.LightGray;
PB.Margin = new System.Windows.Forms.Padding(0);
PB.ClientSize = new System.Drawing.Size(iWidth , iHeight );
PB.Location = new Point(iWidth * (i % cols), iHeight * (i / cols));
PB.Parent = panel1;
PB.DragEnter += PB_DragEnter;
PB.DragDrop += PB_DragDrop;
PB.AllowDrop = true;
PB.MouseClick += (ss, ee) => { currentPB = PB; PB.Focus(); };
}
}
Note how we add events to the dynamically created PictureBoxes and how we set their hidden AllowDrop property.
Also note the little lambda to make the MouseClick prepare for moving them around with the keyboard.
For this we will also need a reference to the current box:
PictureBox currentPB = null;
Now we start the dragging. This should not be done in the MouseDown or else it will interfere with normal selection and also happen before the new selection is made..
Either you do it in the MouseMove:
void listView1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
if (listView1.SelectedItems.Count > 0)
{
listView1.DoDragDrop(listView1.SelectedItems[0], DragDropEffects.Move);
}
}
}
Or (Update) for ListViews better and much simpler (thanks Hans!) in their ItemDrag event:
private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
{
listView1.DoDragDrop(e.Item, DragDropEffects.Move);
}
Update: Both ways now use the dragged Item, not just its imageIndex, to make it simpler to remove the Item from the LV..
void PB_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(ListViewItem)))
e.Effect = DragDropEffects.Move;
else
e.Effect = DragDropEffects.None;
}
void PB_DragDrop(object sender, DragEventArgs e)
{
PictureBox pb = sender as PictureBox;
var item = (ListViewItem)e.Data.GetData(typeof(ListViewItem));
int index = item.ImageIndex;
pb.Image = imageList1.Images[index]; // make sure you have images for indices!!
}
Finally we use the keyboard to move the current box around. I have added code to bring it up and down in the z-order as well.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (currentPB == null) return;
if (e.KeyData == Keys.Left) currentPB.Left -= 1;
else if (e.KeyData == Keys.Right) currentPB.Left += 1;
else if (e.KeyData == Keys.Up) currentPB.Top -= 1;
else if (e.KeyData == Keys.Down) currentPB.Top += 1;
else
{
int z = panel1.Controls.GetChildIndex(currentPB);
if (e.KeyData == Keys.Home) panel1.Controls.SetChildIndex(currentPB, 0);
else if (e.KeyData == Keys.End)
panel1.Controls.SetChildIndex(currentPB, panel1.Controls.Count);
else if (e.KeyData == Keys.PageUp)
panel1.Controls.SetChildIndex(currentPB, z + 1);
else if (e.KeyData == Keys.PageDown)
{ if (z > 0) panel1.Controls.SetChildIndex(currentPB, z - 1); }
}
panel1.Invalidate();
}
For this to work the form must have : KeyPreview = true;
Note that the sizes in an ImageList are restricted to 256x256. So you may want to use only the index and use it to load larger images from disk..
I have an application where I can add a textBox on the screen and move it.
When I add more than two textBox, I double-click on top of two textbox and a line connects both.
My question is: How to make the line move along with the textBox?
code below:
public partial class principal : Form
{
int posMouseFormX, posMouseFormY;
int posMouseTXT_X, posMouseTXT_Y;
int posActTXT_X, posActTXT_Y;
bool txtPressionado = false;
int qntClick;
Pen myPen = new Pen(System.Drawing.Color.DarkGreen, 1);
Graphics Tela;
List<TextBox> listaNós = new List<TextBox>();
List<Point> origem = new List<Point>();
List<Point> destino = new List<Point>();
Point ponto1, ponto2;
ContextMenuStrip menu;
public principal()
{
InitializeComponent();
menu = new ContextMenuStrip();
menu.Items.Add("Remover");
menu.ItemClicked += new ToolStripItemClickedEventHandler(contextMenuStrip1_ItemClicked);
}
//TextBox event when the mouse moves over the TXT
private void txtMover_MouseMove(object sender, MouseEventArgs e)
{
TextBox textBox = sender as TextBox;
posMouseFormX = textBox.Location.X + e.Location.X;
posMouseFormY = textBox.Location.Y + e.Location.Y;
if (txtPressionado == true) moverTxt(textBox);
}
//Retrieve the X and Y coordinates where clicked within the component.
private void txtMover_MouseDown(object sender, MouseEventArgs e)
{
posMouseTXT_X = e.Location.X;
posMouseTXT_Y = e.Location.Y;
txtPressionado = true;
}
private void txtMover_MouseUp(object sender, MouseEventArgs e)
{
txtPressionado = false;
}
private void moverTxt(TextBox a)
{
a.Location = new System.Drawing.Point(posMouseFormX - posMouseTXT_X, posMouseFormY - posMouseTXT_Y);
posActTXT_X = a.Location.X;
posActTXT_Y = a.Location.Y;
System.Drawing.Graphics graphicsObj;
graphicsObj = this.CreateGraphics();
}
//insert new TextBox
private void sb_Inserir_No_Click(object sender, EventArgs e)
{
TextBox noFilho = new TextBox();
noFilho = new System.Windows.Forms.TextBox();
noFilho.Location = new System.Drawing.Point(379, 284);
noFilho.Size = new System.Drawing.Size(100, 30);
noFilho.TabIndex = 20;
noFilho.Text = "";
noFilho.BackColor = Color.White;
posActTXT_X = noFilho.Location.X;
posActTXT_Y = noFilho.Location.Y;
this.Controls.Add(noFilho);
noFilho.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
noFilho.DoubleClick += new System.EventHandler(this.textBox1_Click);
noFilho.MouseUp += new System.Windows.Forms.MouseEventHandler(txtMover_MouseUp);
noFilho.MouseDown += new System.Windows.Forms.MouseEventHandler(txtMover_MouseDown);
noFilho.MouseMove += new System.Windows.Forms.MouseEventHandler(txtMover_MouseMove);
noFilho.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textBox1_KeyDown);
noFilho.ContextMenuStrip = menu;
}
//event to resize the txt on the screen as the content.
private void textBox1_TextChanged(object sender, EventArgs e)
{
TextBox textBox1 = sender as TextBox;
Size size = TextRenderer.MeasureText(textBox1.Text, textBox1.Font);
textBox1.Width = size.Width + 10;
textBox1.Height = size.Height;
}
//Event to control the connection between two give us when double click on the textbox
private void textBox1_Click(object sender, EventArgs e)
{
TextBox textBox1 = sender as TextBox;
int meio = textBox1.Size.Width / 2;
Tela = CreateGraphics();
qntClick = qntClick + 1;
if (this.qntClick == 1)
{
origem.Add(ponto1);
ponto1 = new Point(textBox1.Location.X + meio, textBox1.Location.Y);
}
if (this.qntClick == 2)
{
qntClick = 0;
destino.Add(ponto2);
ponto2 = new Point(textBox1.Location.X + meio, textBox1.Location.Y);
DesenhaSeta(Tela, ponto1, ponto2);
}
}
//draw arrow between two TXT
void DesenhaSeta(Graphics Tela, Point x, Point y)
{
myPen.StartCap = LineCap.Triangle;
myPen.EndCap = LineCap.ArrowAnchor;
Tela.DrawLine(myPen, x, y);
}
private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
ContextMenuStrip menu = sender as ContextMenuStrip;
//recuperando o controle associado com o contextmenu
Control sourceControl = menu.SourceControl;
DialogResult result = MessageBox.Show("Tem Certeza que deseja remover o nó selecionado?", "Excluir", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if(result == DialogResult.Yes)
{
sourceControl.Dispose();
}
}
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
// Determine whether the key entered is the F1 key. Display help if it is.
if (e.KeyCode == Keys.Space)
{
TextBox textBox1 = sender as TextBox;
novoNó tela = new novoNó(textBox1.Text);
tela.Show();
}
}
}
Each control, TextBox included has a Move, event. Put an Invalidate() call there!
The lines should be drawn in the Paint event of the container that holds the TextBoxes, probably the Form; if it is the Form indeed call this.Invalidate().
Please move the line drawing code out of the DoubleClick event into the Paint event or else the lines will not persist, say minimize/maximize events or other situation, when the system has to redraw the application!
You probably will need to create a data structure to maintain information about which TextBox-pairs need to be connected, maybe a List<Tuple> or a List<someStructure>. This would get filled/modified in the DoubleClick event, then call this.Invalidate() and in the Form.Paint you have a foreach loop over the list of TextBox-pairs..
If you are drawing on the Form do make sure to turn DoubleBuffered on!
Update: To compare the reults here is a minimal example the expects two TextBoxes on a Form:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
this.DoubleBuffered = true;
pairs.Add(new Tuple<Control, Control>(textBox1, textBox2));
}
List<Tuple<Control, Control>> pairs = new List<Tuple<Control, Control>>();
Point mDown = Point.Empty;
private void Form2_Paint(object sender, PaintEventArgs e)
{
foreach (Tuple<Control, Control> cc in pairs)
drawConnection(e.Graphics, cc.Item1, cc.Item2);
}
void drawConnection(Graphics G, Control c1, Control c2)
{
using (Pen pen = new Pen(Color.DeepSkyBlue, 3f) )
{
Point p1 = new Point(c1.Left + c1.Width / 2, c1.Top + c1.Height / 4);
Point p2 = new Point(c2.Left + c2.Width / 2, c2.Top + c2.Height / 4);
G.DrawLine(pen, p1, p2);
}
}
void DragBox_MouseDown(object sender, MouseEventArgs e)
{
mDown = e.Location;
}
void DragBox_MouseMove(object sender, MouseEventArgs e)
{
TextBox tb = sender as TextBox;
if (e.Button == MouseButtons.Left)
{
tb.Location = new Point(e.X + tb.Left - mDown.X, e.Y + tb.Top - mDown.Y);
}
}
void DragBox_MouseUp(object sender, MouseEventArgs e)
{
mDown = Point.Empty;
}
private void DragBox_Move(object sender, EventArgs e)
{
this.Invalidate();
}
}
I am working on a C# project and I want to change the location of an arrow by pressing ENTER key with different size of iteration for different comboBox selections. Actually it works but the problem is that I can not refresh the Form before changing comboBox Selection. I want to see iteration step by step but it moves if I change the comboBox selection. Here is the code:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == 0)
{
this.BackColor = Color.Black;
label1.ForeColor = Color.Silver;
label1.Text = "Environment is Space";
pictureBox2.Image = list.Images[4];
t = 100; // iteration amount
}
else if (comboBox1.SelectedIndex == 1)
{
this.BackColor = Color.PaleTurquoise;
label1.Text = "Environment is Water";
pictureBox2.Image = list.Images[3];
t = 50; // iteration amount
}
else if (comboBox1.SelectedIndex == 2)
{
this.BackColor = Color.DarkGoldenrod;
label1.ForeColor = Color.Firebrick;
label1.Text = "Environment is Honey";
pictureBox2.Image = list.Images[2];
t = 20; // iteration amount
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
// Drawing arrow
Pen pen = new Pen(Color.FromArgb(255, 0, 0, 255), 8);
pen.StartCap = LineCap.ArrowAnchor;
pen.EndCap = LineCap.RoundAnchor;
e.Graphics.DrawLine(pen, x+50, 200, x, 200);
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
// pressed Enter => change x
if (e.KeyChar == (char)Keys.Return)
{
e.Handled = true;
if (x < y)
{
x += t;
}
}
}
To be more clear:
I want like: Click-> Enter + Move-> Arrow + Click->Enter + Move -> Arrow
Now it works like: Click-> Enter + Change-> comboBox + Move->Arrow
Thanks a lot!
Do you want a timer solution?
System.Timers.Timer timer = new System.Timers.Timer(500);
timer.Elapsed += (s, e) => {
this.Invoke((MethodInvoker)delegate { comboBox1.SelectedIndex = (comboBox1.SelectedIndex + 1) % comboBox1.Items.Count; });
};
timer.Start();
It's hard to understand what do you mean.