Drag and drop in winforms - c#

I need to drag 6 images, which are in PictureBoxes, to 6 answer panels, one at a time and if the correct image is dragged to the correct spot it adds 1 to the score which is in a class called 'score'. There is code below to show one of the pcitures working but the form lags alot and if the image is dragged anywhere above the panel, it will snap into place. is there a way to stop this?
namespace DragAndDropQuiz
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void pcBxLiverpool_MouseEnter(object sender, EventArgs e)
{
this.Cursor = Cursors.Hand;
}
private void pcBxLiverpool_MouseLeave(object sender, EventArgs e)
{
this.Cursor = Cursors.Default;
}
private int xPos;
private int yPos;
private void pcBxGeneral_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
xPos = e.X;
yPos = e.Y;
}
}
private void pcBxGeneral_MouseMove(object sender, MouseEventArgs e)
{
if (sender != null && sender.GetType() == typeof(PictureBox))
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
((PictureBox)sender).Top += (e.Y - yPos);
((PictureBox)sender).Left += (e.X - xPos);
this.Refresh();
}
}
}
private void pcBxGeneral_MouseUp(object sender, MouseEventArgs e)
{
if (sender != null && sender.GetType() == typeof(PictureBox))
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
PictureBox answer = (PictureBox)sender;
if (answer.Location.X < pnlAnswer.Location.X)
{
if (answer.Location.X + answer.Width > pnlAnswer.Location.X)
{
if ((answer.Location.X + answer.Width) < pnlAnswer.Location.X + pnlAnswer.Width)
{
answer.Location = pnlAnswer.Location;
}
}
}
else if (answer.Location.X > pnlAnswer.Location.X)
{
if (answer.Location.X < (pnlAnswer.Location.X + pnlAnswer.Width))
{
answer.Location = pnlAnswer.Location;
}
}
}
}
}
private void Form2_Paint(object sender, PaintEventArgs e)
{
}
private void groupBox2_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawRectangle(new Pen(Color.Red), pnlAnswer.Location.X, pnlAnswer.Location.Y, pnlAnswer.Width, pnlAnswer.Height);
}
}
}

Related

Custom scrollbar for panel does not scroll smoothly

customBtn1 is the custom scrollbar. The below code sample works, but the scrolling action is jittery and stuttery. It does not scroll smoothly. Any idea why this could be happening and how to fix it?
int PreviousBarLoc;
private void MainForm_Load(object sender, EventArgs e)
{
PreviousBarLoc= customBtn1.Location.Y;
}
//move the scrollbar up and down when the user drags it
private void customBtn1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{ MouseDownLocation = e.Location; }
}
private Point MouseDownLocation;
private void customBtn1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
customBtn1.Top = e.Y + customBtn1.Top - MouseDownLocation.Y;
}
}
//scroll the panel
private void customBtn1_LocationChanged(object sender, EventArgs e)
{
int locDifference = customBtn1.Location.Y - PreviousBarLoc;
if (steamSrvListPnl.VerticalScroll.Value + locDifference <= 255 && steamSrvListPnl.VerticalScroll.Value + locDifference >= 0)
{
steamSrvListPnl.VerticalScroll.Value += locDifference;
}
PreviousBarLoc= customBtn1.Location.Y;
}
Your deltas are not quite right. The way it is currently written, if you drag the mouse down and then start dragging back up, it will not scroll back up because your current e.Y is still below the original MouseDownLocation.Y. I'm not entirely sure of your setup, but below is an example of how to get smooth scrolling to work when the left mouse button is pressed and dragged on a button:
private int _prevY = 0;
private bool _mouseDown = false;
private void button1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_mouseDown = true;
_prevY = e.Y;
}
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (_mouseDown)
{
panel1.VerticalScroll.Value = Math.Max(panel1.VerticalScroll.Minimum, Math.Min(panel1.VerticalScroll.Maximum, panel1.VerticalScroll.Value + e.Y - _prevY));
_prevY = e.Y;
}
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
if (_mouseDown)
{
_mouseDown = false;
_prevY = 0;
}
}

Unable to drag and drop text from DataGridView to TextBox C#

I have been using code that others online have supplied but for some reason it won't let me drag items from the datagridview to the textbox. I highlight a row in the dataGridView and try to drag it to the textbox but nothing happens. I have also enabled the drop property for the textBox but still no difference. Here's the code that I am using:
private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
DataGridView.HitTestInfo info = dataGridView1.HitTest(e.X, e.Y);
if (info.RowIndex >= 0)
{
if (info.RowIndex >= 0 && info.ColumnIndex >= 0)
{
string text = (String)
dataGridView1.Rows[info.RowIndex].Cells[info.ColumnIndex].Value;
if (text != null)
dataGridView1.DoDragDrop(text, DragDropEffects.Copy);
}
}
}
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
textBox1.Text = (System.String)e.Data.GetData(typeof(System.String));
}
}
private void textBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
Here is a small sample that i have done to give you an idea on how to do this... works perfectly for me. I used WinForms here. If WPF, there may be some more events you will need to register to in order for the drag+drop to register...
Note that you will want to add more code here and there to perform what you really want to do when you drag an item from one control to the other.
public partial class Form1 : Form
{
private Rectangle dragBoxFromMouseDown;
private int rowIndexFromMouseDown;
private int rowIndexOfItemUnderMouseToDrop;
private DataGridViewRow draggedrow;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
List<StringValue> Items = new List<StringValue>() { new StringValue("1"), new StringValue("2"), new StringValue("3"), new StringValue("4"), new StringValue("5"), new StringValue("6") };
this.dataGridView1.DataSource = Items;
}
private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
// If the mouse moves outside the rectangle, start the drag.
if (dragBoxFromMouseDown != Rectangle.Empty &&
!dragBoxFromMouseDown.Contains(e.X, e.Y))
{
// Proceed with the drag and drop, passing in the list item.
DragDropEffects dropEffect = dataGridView1.DoDragDrop(
dataGridView1.Rows[rowIndexFromMouseDown],
DragDropEffects.Move);
}
}
}
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
// Get the index of the item the mouse is below.
rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex;
if (rowIndexFromMouseDown != -1)
{
// Remember the point where the mouse down occurred.
// The DragSize indicates the size that the mouse can move
// before a drag event should be started.
Size dragSize = SystemInformation.DragSize;
// Create a rectangle using the DragSize, with the mouse position being
// at the center of the rectangle.
dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
e.Y - (dragSize.Height / 2)),
dragSize);
this.draggedrow = this.dataGridView1.CurrentRow;
}
else
// Reset the rectangle if the mouse is not over an item in the ListBox.
dragBoxFromMouseDown = Rectangle.Empty;
}
private void dataGridView1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void textBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
this.textBox1.Text = (string)this.draggedrow.Cells["Value"].Value;
}
}
public class StringValue
{
public StringValue(string s)
{
_value = s;
}
public string Value { get { return _value; } set { _value = value; } }
string _value;
}
can't you use DataGridViewCellMouseEventArgs e instead of hittest for getting row index in dataGridView1_CellMouseDown. below is your code modified hope this helps
private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (e.RowIndex >= 0)
{
if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
{
string text = (String)
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
if (text != null)
dataGridView1.DoDragDrop(text, DragDropEffects.Copy);
}
}
}
}
private void textBox1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(System.String)))
{
textBox1.Text = (System.String)e.Data.GetData(typeof(System.String));
}
}
private void textBox1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}

How to draw straight line to the mouse coordinates?

When user press the left button and move the mouse it should appears a straight line(not permanent line) from previous point to the current mouse moving position. Finally a real straight line will appear when the user releases the left mouse. please help me ..how do i do it?
List<Point> points = new List<Point>();
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
points.Add(e.Location);
pictureBox1.Invalidate();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (points.Count > 1)
e.Graphics.DrawLines(Pens.Black, points.ToArray());
}
This is what you're looking for
private Stack<Point> points = new Stack<Point>();
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
points.Clear();
points.Push(e.Location);
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (points.Count > 1)
{
points.Pop();
}
if (points.Count > 0 && e.Button == System.Windows.Forms.MouseButtons.Left)
{
points.Push(e.Location);
pictureBox1.Invalidate();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (points.Count > 1)
e.Graphics.DrawLines(Pens.Black, points.ToArray());
}
I used Stack for ease of use, you are free to change to whatever collection of your choice.
To draw several line you can do something like this
private Stack<Line> lines = new Stack<Line>();
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
lines.Push(new Line { Start = e.Location });
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (lines.Count > 0 && e.Button == System.Windows.Forms.MouseButtons.Left)
{
lines.Peek().End = e.Location;
pictureBox1.Invalidate();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
foreach (var line in lines)
{
e.Graphics.DrawLine(Pens.Black, line.Start, line.End);
}
}
class Line
{
public Point Start { get; set; }
public Point End { get; set; }
}
you can use mentioned code
Point currentPoint = new Point();
private void Canvas_MouseDown_1(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (e.ButtonState == MouseButtonState.Pressed)
currentPoint = e.GetPosition(this);
}
private void Canvas_MouseMove_1(object sender, System.Windows.Input.MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Line line = new Line();
line.Stroke = SystemColors.WindowFrameBrush;
line.X1 = currentPoint.X;
line.Y1 = currentPoint.Y;
line.X2 = e.GetPosition(this).X;
line.Y2 = e.GetPosition(this).Y;
currentPoint = e.GetPosition(this);
paintSurface.Children.Add(line);
}
}

How to draw a line on panel overlapped by other panel?

IDE: visual studio, c#, Windows from application
I am trying to draw a line on a panel. I am able to draw line on panel1 by clicking on it.
//Code
public partial class Form1 : Form
{
static int px=5, py=5;
public Form1()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(Pens.Red, 5, 5, px, py);
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
initilizeXY(e.X, e.Y);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
}
private void initilizeXY( int pxx, int pyy)
{
px = pxx;
py = pyy;
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
panel1.Refresh();
}
private void panel2_MouseDown(object sender, MouseEventArgs e)
{
initilizeXY(e.X, e.Y);
}
}
// by this code i am able to draw a line on mouse down on panel 1.
but due to some requirement changes there is another panel ( panel2) which is partially overlapping panel1.
Now i want to draw the same line on panel1 if the user click on panel1 or panel2.
Please suggest how make this work done?
This code works:
Point bgn1 = new Point(5, 5);
Point end1 = new Point(5, 5);
Point bgn2 = new Point(0, 0);
Point end2 = new Point(0, 0);
private void Form1_Load(object sender, EventArgs e)
{
Point pnt, pntscr;
pnt.X = 5;
pnt.Y = 5;
pntscr = Panel1.PointToScreen(pnt);
bgn2 = Panel2.PointToClient(pntscr);
end2 = bgn2;
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
end1.X = e.X;
end1.Y = e.Y;
Point pntscr;
pntscr = Panel1.PointToScreen(end1);
end2 = Panel2.PointToClient(pntscr);
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
panel1.Refresh();
panel2.Refresh();
}
private void panel2_MouseDown(object sender, MouseEventArgs e)
{
end2.X = e.X;
end2.Y = e.Y;
Point pntscr;
pntscr = Panel2.PointToScreen(end2);
end1 = Panel1.PointToClient(pntscr);
}
private void panel2_MouseUp(object sender, MouseEventArgs e)
{
panel1.Refresh();
panel2.Refresh();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(Pens.Red, bgn1, end1);
}
private void panel2_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(Pens.Red, bgn2, end2);
}
valter
EDIT: Fixed the code to work properly.
Tested in a scenario when panel2 overlaps panel1 on the right side of panel1, starting a little lower than panel1's top.
Writing this bit of code I assumed panel2's X and Y coords are greater than panel1's. Perhaps you should reverse the offset calculation if it's the other way around.
public partial class Form1 : Form
{
static int px = 5, py = 5;
static int p2x = 0, p2y = 0;
int offsetX;
int offsetY;
public Form1()
{
InitializeComponent();
offsetX = panel2.Location.X - panel1.Location.X;
offsetY = panel2.Location.Y - panel1.Location.Y;
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(Pens.Red, 5, 5, px, py);
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
initilizeXY(e.X, e.Y);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void initilizeXY(int pxx, int pyy)
{
px = pxx;
py = pyy;
}
private void initilizeXY2(int pxx, int pyy)
{
p2x = pxx;
p2y = pyy;
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
panel1.Refresh();
panel2.Refresh();
}
private void panel2_MouseDown(object sender, MouseEventArgs e)
{
initilizeXY(e.X+offsetX, e.Y+offsetY);
initilizeXY2(e.X, e.Y);
}
private void panel2_Paint(object sender, PaintEventArgs e)
{
if (px > offsetX && py > offsetY)
{
int p2start = findIntersectFromLineEquation(new Point(5, 5), new Point(px, py));
e.Graphics.DrawLine(Pens.Red, 0, p2start - offsetY, p2x, p2y);
}
}
private int findIntersectFromLineEquation(Point start, Point end)
{
if (start.X == end.X || start.Y == end.Y)
return 0;
double a = (double)(end.Y - start.Y) / (double)(end.X - start.X);
double b = (double)(start.Y) - (double)(a * start.X);
return (int)(a * offsetX + b);
}
}
Remember to subscribe the events accordingly.

Move form relative to location clicked

I have a form which can be moved when the user clicks and drags in a border area. The implementations I've seen all lock to the current mouse position, so that when the form is moved, the form jumps so that the mouse is in the upper-left corner. I'd like to change it so that it behaves like a normal windows form, and the form stays at the same position relative to the mouse when moved. My current code looks like this:
Point locationClicked;
bool isMouseDown = false;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
isMouseDown = true;
locationClicked = new Point(e.Location.X, e.Location.Y);
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
isMouseDown = false;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (isMouseDown && targetCell == new Point(-1, -1) && (mouseLocation.X < margin.X || mouseLocation.Y < margin.Y ||
mouseLocation.X > margin.X + cellSize.Width * gridSize.Width ||
mouseLocation.Y > margin.Y + cellSize.Height * gridSize.Height))
{
this.Location = new Point(e.Location.X - locationClicked.X, e.Location.Y - locationClicked.Y);
}
}
When I drag the window, it behaves similarly to what I want. The form flickers between two locations on the screen, one of which moves at about half the rate of the mouse. Is there a way I can fix this?
Try this out...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Point locationClicked;
bool dragForm = false;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
locationClicked = new Point(e.Location.X, e.Location.Y);
if (isMouseDown && targetCell == new Point(-1, -1) && (mouseLocation.X < margin.X || mouseLocation.Y < margin.Y ||
mouseLocation.X > margin.X + cellSize.Width * gridSize.Width ||
mouseLocation.Y > margin.Y + cellSize.Height * gridSize.Height))
{
dragForm = true;
}
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (dragForm)
{
this.Location = new Point(this.Location.X + (e.X - locationClicked.X), this.Location.Y + (e.Y - locationClicked.Y));
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
dragForm = false;
}
}

Categories

Resources