I have two panels on a form.
One panel has some controls like buttons or images and second panel is empty. I want to drag a control from panel 1 and drop it to panel 2, but it should create a copy of control, and while dragging a rectangle should be shown of same size as control and when dropped in panel 2 the dragged shape should appear there at mouse position
Actually I want to create a simulator like thing. That has some tools in panel 1 and when someone drag and drop a tool on panel 2 it should appear there at mouse position.
Language doesn't matter may be C# or VB.NET
Did you try something like this ?
private void Form5_Load(object sender, EventArgs e)
{
this.panel1.AllowDrop = true;
foreach (Control c in this.panel1.Controls)
{
c.MouseDown += new MouseEventHandler(c_MouseDown);
}
this.panel1.DragOver += new DragEventHandler(panel1_DragOver);
this.panel1.DragDrop += new DragEventHandler(panel1_DragDrop);
}
void c_MouseDown(object sender, MouseEventArgs e)
{
Control c = sender as Control;
c.DoDragDrop(c, DragDropEffects.Move);
}
void panel1_DragDrop(object sender, DragEventArgs e)
{
Control c = e.Data.GetData(e.Data.GetFormats()[0]) as Control;
if (c != null)
{
c.Location = this.panel1.PointToClient(new Point(e.X, e.Y));
this.panel1.Controls.Add(c);
}
}
void panel1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
VB.NET
Private Sub Form5_Load(sender As Object, e As EventArgs)
Me.panel1.AllowDrop = True
For Each c As Control In Me.panel1.Controls
c.MouseDown += New MouseEventHandler(AddressOf c_MouseDown)
Next
Me.panel1.DragOver += New DragEventHandler(AddressOf panel1_DragOver)
Me.panel1.DragDrop += New DragEventHandler(AddressOf panel1_DragDrop)
End Sub
Private Sub c_MouseDown(sender As Object, e As MouseEventArgs)
Dim c As Control = TryCast(sender, Control)
c.DoDragDrop(c, DragDropEffects.Move)
End Sub
Private Sub panel1_DragDrop(sender As Object, e As DragEventArgs)
Dim c As Control = TryCast(e.Data.GetData(e.Data.GetFormats()(0)), Control)
If c IsNot Nothing Then
c.Location = Me.panel1.PointToClient(New Point(e.X, e.Y))
Me.panel1.Controls.Add(c)
End If
End Sub
Private Sub panel1_DragOver(sender As Object, e As DragEventArgs)
e.Effect = DragDropEffects.Move
End Sub
Source
Am changing a little of code of #Shim.
Here is the updated code in which a copy of your control will be placed in another panel
Random rnd = new Random();
private void Form5_Load(object sender, EventArgs e)
{
this.panel1.AllowDrop = true;
foreach (Control c in this.panel1.Controls)
{
c.MouseDown += new MouseEventHandler(c_MouseDown);
}
this.panel1.DragOver += new DragEventHandler(panel1_DragOver);
this.panel1.DragDrop += new DragEventHandler(panel1_DragDrop);
}
void c_MouseDown(object sender, MouseEventArgs e)
{
Control c = sender as Control;
c.DoDragDrop(c, DragDropEffects.Move);
}
void panel1_DragDrop(object sender, DragEventArgs e)
{
Control c = e.Data.GetData(e.Data.GetFormats()[0]) as Control;
// Here, you get a copy of your drag drop button and dynamically new button is created
Button btn = new Button();
btn.Name = "Button" + rnd.Next();
btn.Size = c.Size;
if (c != null)
{
// Add the newly created button to you Panel
btn.Location = this.panel1.PointToClient(new Point(e.X, e.Y));
this.panel1.Controls.Add(btn);
}
}
void panel1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
this solution will drag the button(or any other component selected) while moving the mouse and place it on the place where you drop it
private SimpleButton selectedButton;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
xtraScrollableControl2.AllowDrop = true;
xtraScrollableControl2.DragEnter += XtraScrollableControl_DragEnter;
xtraScrollableControl2.DragDrop += XtraScrollableControl_DragDrop;
xtraScrollableControl2.DragOver += XtraScrollableControl_DragOver;
}
private void XtraScrollableControl_DragEnter(object sender, DragEventArgs e)
{
e.Effect = e.Data.GetDataPresent(typeof(Bitmap)) ? DragDropEffects.Copy : DragDropEffects.None;
}
private void XtraScrollableControl_DragDrop(object sender, DragEventArgs e)
{
var simpleButton = e.Data.GetData(e.Data.GetFormats()[0]) as SimpleButton;
if (simpleButton == null) return;
if (simpleButton.Parent != sender)
{
var btn = new SimpleButton
{
Dock = DockStyle.None,
Size = new Size(125, 50),
Text = simpleButton.Text,
Location = ((XtraScrollableControl) sender).PointToClient(new Point(e.X, e.Y)),
ImageList = simpleButton.ImageList,
ImageIndex = simpleButton.ImageIndex,
ImageLocation = simpleButton.ImageLocation,
Parent = ((XtraScrollableControl)sender)
};
btn.MouseDown += simpleButton_MouseDown;
((XtraScrollableControl)sender).Controls.Add(btn);
}
else
{
((XtraScrollableControl)sender).Controls.Remove(simpleButton);
simpleButton.Location = ((XtraScrollableControl)sender).PointToClient(new Point(e.X, e.Y));
((XtraScrollableControl)sender).Controls.Add(simpleButton);
}
selectedButton = null;
}
private void XtraScrollableControl_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
selectedButton.Location = ((XtraScrollableControl)sender).PointToClient(new Point(e.X, e.Y));
}
private void simpleButton_MouseDown(object sender, MouseEventArgs e)
{
var btn = sender as SimpleButton;
if (btn == null) return;
selectedButton = btn;
btn.DoDragDrop(btn, DragDropEffects.Copy);
}
hope this will help some
i used DevExpress components
but for the standart
DevExpress
XtraScrollableControl
SimpleButton
Microsoft
Panel
Button
Related
This may be a basic question but I just started using WPF and I am having troubles trying to do a simple drag and drop.
I created this ToolboxButton class:
public class ToolboxButton : Button
{
private bool _isDragging = false;
private Point _startPoint;
public ToolboxButton(string content)
{
Content = content;
HorizontalAlignment = HorizontalAlignment.Stretch;
Height = 30;
Loaded += ToolboxButton_Loaded;
}
void ToolboxButton_Loaded(object sender, RoutedEventArgs e)
{
PreviewMouseLeftButtonDown += ToolboxButton_PreviewMouseLeftButtonDown;
PreviewMouseMove += ToolboxButton_PreviewMouseMove;
}
void ToolboxButton_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && !_isDragging)
{
Point position = e.GetPosition(null);
if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
{
StartDrag(e);
}
}
}
void ToolboxButton_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_startPoint = e.GetPosition(null);
}
private void StartDrag(MouseEventArgs e)
{
_isDragging = true;
DataObject data = new DataObject(System.Windows.DataFormats.Text.ToString(), "abcd");
DragDrop.DoDragDrop(e.Source as ToolboxButton, data, DragDropEffects.Move);
_isDragging = false;
}
}
This button is added in a stackpanel like so:
ToolboxButton btnAddButton = new ToolboxButton("Button");
_toolboxView.Children.Add(btnAddButton); // _toolboxView is a stackpanel
And I have a Canvas with the following code:
public class DesignerView : Canvas
{
public DesignerView()
{
AllowDrop = true;
DragOver += DesignerView_DragOver;
Drop += DesignerView_Drop;
PreviewDragOver += DesignerView_PreviewDragOver;
}
void DesignerView_PreviewDragOver(object sender, DragEventArgs e)
{
MessageBox.Show("previewdragover");
}
void DesignerView_DragOver(object sender, DragEventArgs e)
{
MessageBox.Show("dragover");
if (!e.Data.GetDataPresent(typeof(ToolboxButton)))
{
e.Effects = DragDropEffects.None;
e.Handled = true;
}
}
void DesignerView_Drop(object sender, DragEventArgs e)
{
MessageBox.Show("drop");
if (e.Data.GetDataPresent(typeof(ToolboxButton)))
{
ToolboxButton droppedThingie = e.Data.GetData(typeof(ToolboxButton)) as ToolboxButton;
MessageBox.Show("You dropped: " + droppedThingie.Content);
}
}
public UIElement GetView()
{
return this;
}
}
Both Canvas and StackPanel are added in the main window like so:
Grid contentGrid = new Grid();
Content = contentGrid;
contentGrid.Children.Add(_toolboxView.GetView());
contentGrid.Children.Add(_designerView.GetView());
None of the MessageBoxes ever fire and I can't find out why. The cursor changes to the "Cannot pin", a dark circle with a diagonal line inside.
Am I missing something ? I want everything to be done in the code without XML.
Maybe I have to do something on the StackPanel but I tried the code of ToolboxButton there and it didn't work either.
As I can see you done all job, just DesignerView_drop left to correct.
use sender object to grab dragged object (in this example button)
void DesignerView_Drop(object sender, DragEventArgs e)
{
MessageBox.Show("drop");
Button btn = (Button)sender;
contentGrid.Children.Add(btn);
}
I'm currently implementing drag & drop function in C# Window Forms. I've created multiple pictures box on left navigation, so user can drag and drop to right side panel.
But it does look like pictures box can not drop to the panel directly.
When i compile, it runs. But, when I drag and drop it makes following error:
"unable to cast object of type 'System.Windows.Forms.Panel' to type 'System.Windows.Forms.PictureBox'."
Please suggest how can i make drag and drop "picutre 1, 2, 3" to the panel accordingly.?
private void Form3_Load(object sender, EventArgs e)
{
pictureBox4.DragEnter += new DragEventHandler(pictureBox4_DragEnter);
pictureBox4.DragDrop += new DragEventHandler(pictureBox4_DragDrop);
pictureBox4.MouseDown += new MouseEventHandler(pictureBox4_MouseDown);
panel2.AllowDrop = true;
}
private void pictureBox4_DragDrop(object sender, DragEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.Image = (Image)e.Data.GetData(DataFormats.Bitmap);
}
private void pictureBox4_MouseDown(object sender, MouseEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.Select();
pb.DoDragDrop(pb.Image, DragDropEffects.Copy);
panel1.Show();
}
private void panel2_DragDrop(object sender, DragEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.Image = (Image)e.Data.GetData(DataFormats.Bitmap);
}
private void panel2_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Bitmap))
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.None;
}
}
I suppose in this code your sender is actually a Panel. Check it's type in the debugger:
private void panel2_DragDrop(object sender, DragEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.Image = (Image)e.Data.GetData(DataFormats.Bitmap);
}
As a good principle always do typecasting like this:
PictureBox pb = sender as PictureBox; // will give you null if it can't be cast to PictureBox
if(pb != null)
{
// do something...
}
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 creating a "cropping tool", and i need to make a panel that contains 2 buttons draggable.
Until now i've tried something like this, but the change location event happens only when i click the right button of the mouse...
this.MouseDown += new MouseEventHandler(onRightClickMouse);
private void onRightClickMouse(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
Point localMouseClickPoint = new Point(e.X, e.Y);
panel1.Location = localMouseClickPoint;
}
}
My question: How can i make that panel draggable in my form?(I mean click on the panel then drag it to a location).
Try something like this:
delegate void updatePanelCallback();
panel1.MouseDown += new MouseEventHandler(onMouseDown);
panel1.MouseUp += new MouseEventHandler(onMouseUp);
System.Timers.Timer runTimer = new System.Timers.Timer(100);
runTimer.Elapsed += new ElapsedEventHandler(onTimerElapsed);
private void onMouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Right)
{
return;
}
runTimer.Enabled = false;
}
private void onMouseUp(object sender, MouseEventArgs e)
{
runTimer.Enabled = false;
}
public void updatePanelLocation()
{
if (this.InvokeRequired)
{
this.Invoke(new updatePanelCallback(updatePanelLocation), new object[] {});
}
else
{
Cursor curs = new Cursor(Cursor.Current.Handle);
panel1.Location = curs.Position;
}
}
private void onTimerElapsed(object source, ElapsedEventArgs e)
{
updatePanelLocation();
}
You could try something in two steps, preparing the action on MouseDown event and finishing it on MouseUp.
I'm dragging and dropping the pictureBox in FlowlayoutPanel but the event return the position in form...I need this position in FlowLayoutPanel(the pictureBoxes are in FlowLayoutPanel and are dragging and drop there)
public Form1()
{
InitializeComponent();
flowLayoutPanel1.AllowDrop = true;
}
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
picBox = (PictureBox)sender;
if (picBox.Image != null)
{
var dragImage = new Bitmap((Bitmap)picBox.Image, picBox.Size);
IntPtr icon = dragImage.GetHicon();
Cursor.Current = new Cursor(icon);
DoDragDrop(picBox.Image, DragDropEffects.Copy);
}
}
}
void Form1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(Bitmap)))
e.Effect = DragDropEffects.Copy;
}
// Occurs when the user releases the mouse over the drop target
void Form1_DragDrop(object sender, DragEventArgs e)
{
MessageBox.Show("Posicao x " + e.Y + "Posicao Y " + e.Y);//reutrn the position in form, not in flowLayoutPanel
}
You have to use this method:
var point = flowLayoutPanel1.PointToClient(new Point(e.X, e.Y));
This translates screen position coordinates into control one, more info here.