I have a PictureBox that is inside a TabPage, and of course this TabPage is part of a TabView and this TabView is inside a Form. I want users be able to move this picture box within the tab page. For this I am using the MouseDown, MouseMove and MouseUp events of the picture box:
private void pictureBoxPackageView_MouseDown(object sender, MouseEventArgs e)
{
if (!_mapPackageIsMoving)
{
_mapPackageIsMoving = true;
}
}
private void pictureBoxPackageView_MouseMove(object sender, MouseEventArgs e)
{
if(_mapPackageIsMoving)
{
pictureBoxPackageView.Location = MousePosition; //This is not exact at all!
return;
}
//Some other code for some other stuff when picturebox is not moving...
}
private void pictureBoxPackageView_MouseUp(object sender, MouseEventArgs e)
{
if (_mapPackageIsMoving)
{
_mapPackageIsMoving = false; //Mouse button is up, end moving!
return;
}
}
But my problem lies in the MouseMove event. As soon as I move mouse after button down, the picture box jumps out of tab page's visible area.
I need to know how to handle the move only within the rectangle of the tab page, and if picture box is being dragged out of tab view's visible area, it shouldn't move anymore unless user brings the mouse inside the tab view's visible rectangle.
Any helps/tips will be appriciated!
You need a variable to hold the original position of the PictureBox:
Modified from a HansPassant answer:
private Point start = Point.Empty;
void pictureBoxPackageView_MouseUp(object sender, MouseEventArgs e) {
_mapPackageIsMoving = false;
}
void pictureBoxPackageView_MouseMove(object sender, MouseEventArgs e) {
if (_mapPackageIsMoving) {
pictureBoxPackageView.Location = new Point(
pictureBoxPackageView.Left + (e.X - start.X),
pictureBoxPackageView.Top + (e.Y - start.Y));
}
}
void pictureBoxPackageView_MouseDown(object sender, MouseEventArgs e) {
start = e.Location;
_mapPackageIsMoving = true;
}
Related
While dragging rectangle object fast, dragging stops and cursor only moves. Without releasing button click button, moving the cursor on the rectangle object starts the dragging again. It is dragging fine when i drag on a constant speed.
My code is,
private void ConnectorMethod()
{
_draggedLine = new Rectangle();
_draggedLine.Width = 100;
_draggedLine.Height = 12;
_controlModel.PlayerCanvas.Children.Add(_draggedLine);
_draggedLine.PreviewMouseLeftButtonDown += copy_Connector;
_draggedLine.PreviewMouseLeftButtonUp += connector_leftUp;
}
private void copy_Connector(object sender, MouseButtonEventArgs e)
{
_connecting_Connector = (Rectangle)sender;
_Connector_position = e.GetPosition(_connecting_Connector);
_connecting_Connector.PreviewMouseMove += ConnectorMouseMove;
}
private void connector_leftUp(object sender, MouseButtonEventArgs e)
{
_connecting_Connector.PreviewMouseMove -= ConnectorMouseMove;
}
private void ConnectorMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Point canvasRelativePosition = e.GetPosition(_controlModel.PlayerCanvas);
Canvas.SetTop(_connecting_Connector, canvasRelativePosition.Y - _Connector_position.Y);
Canvas.SetLeft(_connecting_Connector, canvasRelativePosition.X - _Connector_position.X);
e.Handled = true;
}
}
Thanks in Advance.
I have fixed it with implementation canvas rectangle object in
I got myself drag and drop functionality in my little card game. I want just like in the windows card games to be able to drag and drop my cards. Now, I simply tried to make the drag and drop, but it's acting weird. The card is a custom control called Card.
I first will explain it:
1. I hold my mouse button on the card
2. It moves to another location (without me moving the mouse).
3. The card now moves correctly, but when I release the mouse button, the card will be at that position, but it won't be the position of my mouse since it was off when I clicked.
This is my code:
public void CardMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
cardClickInitLocation = ((Card)sender).Location;
}
}
public void CardMouseUp(object sender, MouseEventArgs e)
{
}
public void CardMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
((Card)sender).Left = e.X + ((Card)sender).Left - cardClickInitLocation.X;
((Card)sender).Top = e.Y + ((Card)sender).Top - cardClickInitLocation.Y;
}
}
I used my mouseup event before but it's not needed with this method. I cannot see what I could've done wrong.
Fixed it!
Added this to the class:
private Size mouseOffset;
private bool clicked = false;
The three events:
public void CardMouseDown(object sender, MouseEventArgs e)
{
mouseOffset = new System.Drawing.Size(e.Location);
clicked = true;
}
public void CardMouseUp(object sender, MouseEventArgs e)
{
clicked = false;
}
public void CardMouseMove(object sender, MouseEventArgs e)
{
if (clicked)
{
System.Drawing.Point newLocationOffset = e.Location - mouseOffset;
((Card)sender).Left += newLocationOffset.X;
((Card)sender).Top += newLocationOffset.Y;
((Card)sender).BringToFront();
}
}
I have a tableLayoutPanel with 16 cells. 15 of the cells have controls. I want to be able to move the controls from one cell to another at runtime.
I have used
private void button15_Click(object sender, EventArgs e)
{
tableLayoutPanel1.Controls.Remove(button15);
tableLayoutPanel1.Controls.Add(button15, 3, 3);
}
This works well but i want to know if there is any better way to do this???
In Winforms, you can only move a control inside its parent (of course there are some exceptions to some controls which in fact don't have any Parent). So the idea here is if you want to move a control of your TableLayoutPanel, you have to set its Parent to your Form of another container when mouse is held down, when moving, the position of the control is in the new parent, after mouse is released, we have to set the Parent of the control to the TableLayoutPanel back, of course we have to find the drop-down cell position and use SetCellPosition method to position the control on the TableLayoutPanel, here is the demo code for you (works great), I use 2 Buttons in this demo, you can replace them with any control you want:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
//This will prevent flicker
typeof(TableLayoutPanel).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(tableLayoutPanel1, true, null);
}
Point downPoint;
bool moved;
//This is used to store the CellBounds together with the Cell position
//so that we can find the Cell position later (after releasing mouse).
Dictionary<TableLayoutPanelCellPosition, Rectangle> dict = new Dictionary<TableLayoutPanelCellPosition, Rectangle>();
//MouseDown event handler for all your controls (on the tableLayoutPanel1)
private void Buttons_MouseDown(object sender, MouseEventArgs e) {
Control button = sender as Control;
button.Parent = this;
button.BringToFront();
downPoint = e.Location;
}
//MouseMove event handler for all your controls (on the tableLayoutPanel1)
private void Buttons_MouseMove(object sender, MouseEventArgs e) {
Control button = sender as Control;
if (e.Button == MouseButtons.Left) {
button.Left += e.X - downPoint.X;
button.Top += e.Y - downPoint.Y;
moved = true;
tableLayoutPanel1.Invalidate();
}
}
//MouseUp event handler for all your controls (on the tableLayoutPanel1)
private void Buttons_MouseUp(object sender, MouseEventArgs e) {
Control button = sender as Control;
if (moved) {
SetControl(button, e.Location);
button.Parent = tableLayoutPanel1;
moved = false;
}
}
//This is used to set the control on the tableLayoutPanel after releasing mouse
private void SetControl(Control c, Point position) {
Point localPoint = tableLayoutPanel1.PointToClient(c.PointToScreen(position));
var keyValue = dict.FirstOrDefault(e => e.Value.Contains(localPoint));
if (!keyValue.Equals(default(KeyValuePair<TableLayoutPanelCellPosition, Rectangle>))) {
tableLayoutPanel1.SetCellPosition(c, keyValue.Key);
}
}
//CellPaint event handler for your tableLayoutPanel1
private void tableLayoutPanel1_CellPaint(object sender, TableLayoutCellPaintEventArgs e) {
dict[new TableLayoutPanelCellPosition(e.Column, e.Row)] = e.CellBounds;
if (moved) {
if (e.CellBounds.Contains(tableLayoutPanel1.PointToClient(MousePosition))) {
e.Graphics.FillRectangle(Brushes.Yellow, e.CellBounds);
}
}
}
}
Remove Lock & set dock to none and move!
i have used this code to move picture box on the pictureBox_MouseMove event
pictureBox.Location = new System.Drawing.Point(e.Location);
but when i try to execute the picture box flickers and the exact position cannot be identified. can you guys help me with it. I want the picture box to be steady...
You want to move the control by the amount that the mouse moved:
Point mousePos;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
mousePos = e.Location;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
int dx = e.X - mousePos.X;
int dy = e.Y - mousePos.Y;
pictureBox1.Location = new Point(pictureBox1.Left + dx, pictureBox1.Top + dy);
}
}
Note that this code does not update the mousePos variable in MouseMove. Necessary since moving the control changes the relative position of the mouse cursor.
You have to do several things
Register the start of the moving operation in MouseDown and remember the start location of the mouse.
In MouseMove see if you are actually moving the picture. Move by keeping the same offset to the upper left corner of the picture box, i.e. while moving, the mouse pointer should always point to the same point inside the picture box. This makes the picture box move together with the mouse pointer.
Register the end of the moving operation in MouseUp.
private bool _moving;
private Point _startLocation;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
_moving = true;
_startLocation = e.Location;
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
_moving = false;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (_moving) {
pictureBox1.Left += e.Location.X - _startLocation.X;
pictureBox1.Top += e.Location.Y - _startLocation.Y;
}
}
Try to change SizeMode property from AutoSize to Normal
I am writing a game. Player can choose items (such as weapon) and drag them to the form. Items are on the side, in PictureBox controls. I have set Form.AllowDrop to True. When I drag one of the items pictureBoxes, the pictureBox doesn't drop, neither even drag.
I want to drag a pictureBox on the form, or at least know the position in the form which the player want to drag it in.
EDIT: look at the logo above. When you click it and drag (without release) it drags.
In Winforms you need to change the cursor. Here's a complete example, start a new forms project and drop a picturebox on the form. Set its Image property to a small bitmap. Click and drag to drop copies of the image on the form.
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.AllowDrop = true;
this.pictureBox1.MouseDown += pictureBox1_MouseDown;
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
var dragImage = (Bitmap)pictureBox1.Image;
IntPtr icon = dragImage.GetHicon();
Cursor.Current = new Cursor(icon);
DoDragDrop(pictureBox1.Image, DragDropEffects.Copy);
DestroyIcon(icon);
}
}
protected override void OnGiveFeedback(GiveFeedbackEventArgs e) {
e.UseDefaultCursors = false;
}
protected override void OnDragEnter(DragEventArgs e) {
if (e.Data.GetDataPresent(typeof(Bitmap))) e.Effect = DragDropEffects.Copy;
}
protected override void OnDragDrop(DragEventArgs e) {
var bmp = (Bitmap)e.Data.GetData(typeof(Bitmap));
var pb = new PictureBox();
pb.Image = (Bitmap)e.Data.GetData(typeof(Bitmap));
pb.Size = pb.Image.Size;
pb.Location = this.PointToClient(new Point(e.X - pb.Width/2, e.Y - pb.Height/2));
this.Controls.Add(pb);
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static bool DestroyIcon(IntPtr handle);
}
For the draggable items, you need to call the DoDragDrop method in the MouseDown event. Make sure your form (or target) has the AllowDrop property set to true.
For your target, you need to wire the dragging events:
private void Form1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
private void Form1_DragDrop(object sender, DragEventArgs e)
{
// Examine e.Data.GetData stuff
}