Can't save Button Position in XML file - c#

I have a user control with 10 small buttons (20 x 20). I am using the following code to allow the user to drag each button along the x axis only.
I then want to save its X location to a list which can be saved as part of an XML file and then be loaded with the same button locations the next time the app runs. For some reason, I can't save button location. Even the message box doesn't show. What am I doing wrong?
private Point p;
private void button2_mousedown(object sender, MouseEventArgs e)
{
string buttonName = ((Button)sender).Name;
Button b1 = ((Button)sender);
if (e.Button == MouseButtons.Left)
{
p = e.Location;
}
}
private void button2_mousemove(object sender, MouseEventArgs e)
{
string buttonName = ((Button)sender).Name;
Button b1 = ((Button)sender);
if (e.Button == MouseButtons.Left)
{
b1.Left = e.X + b1.Left - p.X;
}
int idx = int.Parse(buttonName) - 1;
scriptIconLocation[idx] = b1.Left;
//MessageBox.Show(scriptIconLocation[idx].ToString(), "saved location");
savedSettings.ScriptIconLocation = scriptIconLocation;
saveSettingsXML(savedSettings);
}

To move buttons use the following code. Subscribe each button on this event handler.
private void Button_MouseMove(object sender, MouseEventArgs e)
{
var button = (Button)sender;
if (e.Button == MouseButtons.Left)
{
button.Left = PointToClient(Cursor.Position).X;
}
}
The MouseDown event is not necessary.
Do not save data in xml with every mouse movement, because it's very inefficient.
Do this, for example, when the form is closed. And read the data when the form is loaded.
private void Form1_Load(object sender, EventArgs e)
{
// Array of your buttons.
var buttons = userControl.Controls.OfType<Button>().ToArray();
var xml = XElement.Load("buttons.xml").Elements("X").ToArray();
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].Left = (int)xml[i];
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
var buttons = userControl.Controls.OfType<Button>();
var xml = new XElement("Buttons",
buttons.Select(b => new XElement("X", b.Left)));
xml.Save("buttons.xml");
}

Related

How does it go to its first position if I don't drag the button where I want to drag it?

enter image description hereI have 9 buttons. Three are located above, 3 are located below them. All 3 buttons are on the right side. The antonyms of the words written on the buttons above are written on the buttons on the right. I would like to place the buttons with these antonyms on the buttons at the bottom. The buttons at the bottom are colored and their text is the same as the buttons on the right, but their text is not visible because it is the same as the button color. So the buttons on the bottom look like a colored box. That's what I want to do now; for example, button 1 = cold and button7 = hot. I want to place this button 7 on button 4 located below button 1, but if I want to place it on button 5 I want it to return to its original position. In the code I wrote, as soon as I press button7, it goes directly to button4, I can't try the other buttons. how can I try other buttons and return them to the first position in Visual studio form application?
enter code here
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace materyalll
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
startlocation = new Point(button7.Left, button7.Top);
startlocation2 = new Point(button8.Left, button8.Top);
startlocation3 = new Point(button9.Left, button9.Top);
}
Point location, location2, location3, startlocation, startlocation2, startlocation3;
private void button7_MouseDown(object sender, MouseEventArgs e)
{
location = e.Location;
}
private void button7_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
button7.Left += e.X - (location.X);
button7.Top += e.Y - (location.Y);
}
}
private void button7_MouseUp(object sender, MouseEventArgs e)
{
if (button7.Text == button4.Text)
button7.Location = button4.Location;
else if (button7.Text != button5.Text)
button7.Location = startlocation;
else if (button7.Text != button6.Text)
button7.Location = startlocation;
}
private void button8_MouseDown(object sender, MouseEventArgs e)
{
location2 = e.Location;
}
private void button8_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
button8.Left += e.X - (location2.X);
button8.Top += e.Y - (location2.Y);
}
}
private void button8_MouseUp(object sender, MouseEventArgs e)
{
if (button8.Text == button5.Text)
button8.Location = button5.Location;
else if (button8.Text != button4.Text)
button8.Location = startlocation2;
else if (button8.Text != button6.Text)
button8.Location = startlocation2;
}
private void button9_MouseDown(object sender, MouseEventArgs e)
{
location3 = e.Location;
}
private void button9_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
button9.Left += e.X - (location3.X);
button9.Top += e.Y - (location3.Y);
}
}
private void button9_MouseUp(object sender, MouseEventArgs e)
{
if (button9.Text == button6.Text)
button9.Location = button6.Location;
else if (button9.Text != button4.Text)
button9.Location = startlocation3;
else if (button9.Text != button5.Text)
button9.Location = startlocation3;
}
}
}
Store the original location of the Button in the .Tag property of the Button itself. When the user releases the mouse, see if the RECTANGLES of the correct target button and the current button INTERSECT. If they don't, snap back to the stored location in the Tag; otherwise snap to the location of the correct button.
Here it is with button7:
public Form1()
{
InitializeComponent();
button7.Tag = button7.Location;
button8.Tag = button8.Location;
button9.Tag = button9.Location;
}
private void button7_MouseUp(object sender, MouseEventArgs e)
{
if (button7.Bounds.IntersectsWith(button4.Bounds)) {
button7.Location = button4.Location;
}
else
{
button7.Location = (Point)button7.Tag;
}
}
The code for the other two buttons would be very similar.
Try something like this:
Dictionary<string, Point> originalPoints = new Dictionary<string, Point>();
originalPoints.Add(nameof(button1), new Point(button1.Left, button1.Top));
// repeat this for all buttons
void SetToOriginalPosition(Button button)
{
Point p = originalPoints[nameof(button)];
button.Left = p.X;
button.Top = p.Y;
}

Drag and drop an to TextBox in a specific mouse position - Show caret or position indicator

I am pasting an item from a TreeView to a TextBox, but I want to paste that item in the mouse's current position and also show a caret like the image below.
Image with caret:
Here is my code:
private void tvOperador_ItemDrag(object sender, ItemDragEventArgs e)
{
var node = (TreeNode)e.Item;
if (node.Level > 0)
{
DoDragDrop(node.Text, DragDropEffects.Copy);
}
}
private void txtExpresion_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string))) e.Effect = DragDropEffects.Copy;
}
private void txtExpresion_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
string Item = (System.String)e.Data.GetData(typeof(System.String));
string[] split = Item.Split(':');
txtExpresion.Text += split[1];
}
}
This is tricky as the Drag&Drop operation keeps the mouse captured, so you can't use the mouse events..
One way is to set up a Timer to do the work..:
Timer cursTimer = new Timer();
void cursTimer_Tick(object sender, EventArgs e)
{
int cp = txtExpresion.GetCharIndexFromPosition(
txtExpresion.PointToClient(Control.MousePosition));
txtExpresion.SelectionStart = cp;
txtExpresion.SelectionLength = 0;
txtExpresion.Refresh();
}
The Timer uses the Control.MousePosition function to determined the cursor position every 25ms or so, sets the caret and updates the TextBox.
In your events you initialize it and make sure the TextBox has focus; finally you add the string at the current selection:
private void txtExpresion_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string)))
{
e.Effect = DragDropEffects.Copy;
txtExpresion.Focus();
cursTimer = new Timer();
cursTimer.Interval = 25;
cursTimer.Tick += cursTimer_Tick;
cursTimer.Start();
}
}
private void txtExpresion_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
cursTimer.Stop();
string Item = (System.String)e.Data.GetData(typeof(System.String));
string[] split = Item.Split(':');
txtExpresion.SelectedText = split[1]
}
}
A different way to solve it would be to not use normal Drag&Drop and only code the mouse events but this one worked ok a my first tests.
Update
While the above solution does work, using a Timer seems not exactly elegant. Much better to use the DragOver event, as seen in Reza's answer. But instead of painting a cursor, why not do the real thing, i.e. take control of the actual I-beam..?
The DragOver event is called all the time during the move so it works pretty much like MousMove would: So here is a merger of the two solutions, which I believe is the best way to do it:
private void txtExpresion_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
string Item = (System.String)e.Data.GetData(typeof(System.String));
string[] split = Item.Split(':');
txtExpresion.SelectionLength = 0;
txtExpresion.SelectedText = split[1];
}
}
private void txtExpresion_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string)))
{
e.Effect = DragDropEffects.Copy;
txtExpresion.Focus();
}
}
private void txtExpresion_DragOver(object sender, DragEventArgs e)
{
int cp = txtExpresion.GetCharIndexFromPosition(
txtExpresion.PointToClient(Control.MousePosition));
txtExpresion.SelectionStart = cp;
txtExpresion.Refresh();
}
You can draw a caret over TextBox in DragOver event. Also set the SelectionStart to the char index you get from mouse position. Then in DragDrop event, just set SelectedText.
private void textBox1_DragOver(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
var position = textBox1.PointToClient(Cursor.Position);
var index = textBox1.GetCharIndexFromPosition(position);
textBox1.SelectionStart = index;
textBox1.SelectionLength = 0;
textBox1.Refresh();
using (var g = textBox1.CreateGraphics())
{
var p = textBox1.GetPositionFromCharIndex(index);
g.DrawLine(Pens.Black, p.X, 0, p.X, textBox1.Height);
}
}
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
string txt = (System.String)e.Data.GetData(typeof(System.String));
textBox1.SelectedText = txt;
}
}

C# Drawing Lines with TextBox

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();
}
}

Drag Drop Picturebox

I am trying to make an application in which i have 7 Pictureboxes and i want to drag drop one each time i click then move the mouse on the form. I did make it to some extend by moving the picture-box on the form but i cannot keep the original image. When i drag drop a picture box i want to drag drop just a copy not the whole picture box on the form. Any help will be greatly appreciated. Kind regards.
public Form1()
{
controller = Controller.getController();
InitializeComponent();
this.AllowDrop = true;
this.pbOR.MouseDown += pbOR_MouseUp;
}
private void pbOR_MouseDown(object sender, MouseEventArgs e)
{
downPoint = e.Location;
pbOR.Parent = this;
pbOR.BringToFront();
}
private void pbOR_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
pbOR.Left += e.X - downPoint.X;
pbOR.Top += e.Y - downPoint.Y;
}
}
private void pbOR_MouseUp(object sender, MouseEventArgs e)
{
Control c = GetChildAtPoint(new Point(pbOR.Left - 1, pbOR.Top));
if (c == null) c = this;
Point newLoc = c.PointToClient(pbOR.Parent.PointToScreen(pbOR.Location));
pbOR.Parent = c;
pbOR.Location = newLoc;
}

How to recognize if a rectangle contains a Text block within in

I'm creating this program in which the user drags/drops a text block into a rectangle, and then store the contents of that specific textblock when he/she drops it into the rectangle.
I figured out how to do the drag/drop, but I just can't figure out how to check if the rectangle contains the textblock.
Here's the code so far:
bool captured = false;
double x_shape, x_canvas, y_shape, y_canvas;
UIElement source = null;
private void shape_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
source = (UIElement)sender;
Mouse.Capture(source);
captured = true;
x_shape = Canvas.GetLeft(source);
x_canvas = e.GetPosition(LayoutRoot).X;
y_shape = Canvas.GetTop(source);
y_canvas = e.GetPosition(LayoutRoot).Y;
}
private void shape_MouseMove(object sender, MouseEventArgs e)
{
if (captured)
{
double x = e.GetPosition(LayoutRoot).X;
double y = e.GetPosition(LayoutRoot).Y;
x_shape += x - x_canvas;
Canvas.SetLeft(source, x_shape);
x_canvas = x;
y_shape += y - y_canvas;
Canvas.SetTop(source, y_shape);
y_canvas = y;
}
}
private void shape_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
captured = false;
}
private void rectangle1_MouseEnter(object sender, MouseEventArgs e)
{
if (Mouse.Capture(null))
{
textBox1.Text = "test";
}
}
The "Shape" events apply to the textblock by the way, just for clarification.
I tried to find a shortcut and make it so with the rectangle1_MouseEnter event that if the mouse isn't clicked, then store the values (didn't include the code for the storing values). However, the problem is, this idea doesn't work because textBox1.Text="test" isn't registered, and I don't see why it isn't.

Categories