How to limit dragging an image inside a Panel? - c#

Good evening. I'm currently working on an interactive map editor. I'm trying to keep the map image from being dragged out of view by using this code
if (currentPosition.X > 0)
currentPosition.X = 0;
else if (currentPosition.X < -mapSize.Width + Size.Width )
currentPosition.X = -mapSize.Width + Size.Width ;
if (currentPosition.Y > 0)
currentPosition.Y = 0;
else if (currentPosition.Y < -mapSize.Height + Size.Height)
currentPosition.Y = -mapSize.Height + Size.Height;
However I can't drag it to the limits Size-mapSize.
The currentPosition corresponds to the upper left location of the image. Here's the full code of the class
namespace GameMaps
{
public class MapPanel : Panel
{
private Bitmap shownMap = null;
private Point mapLocation;
private Size mapSize;
private bool dragging;
private Point currentPosition;
//private Point newPosition;
private Point initialPosition;
private Point initialMousePosition;
private Form1 parentForm;
public MapPanel(Form1 parentForm) : base()
{
this.DoubleBuffered = true;
this.parentForm = parentForm;
}
public MapPanel(Panel targetPanel) : this(new Form1())
{
}
public void ShowMap(Map map)
{
if (map == null) return;
shownMap = map.MapTexture;
mapLocation = new Point(0, 0);
mapSize = shownMap.Size;
currentPosition = new Point();
initialPosition = new Point();
initialMousePosition = new Point(); //mapLocation;
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.PageUnit = GraphicsUnit.Pixel;
e.Graphics.PageScale = 1.0F;
// base.OnPaint(e);
if (shownMap == null)
{
base.OnPaint(e);
return;
}
e.Graphics.DrawImage(shownMap, currentPosition.X, currentPosition.Y);
}
protected override void OnMouseDown(MouseEventArgs e)
{
// base.OnMouseDown(e);
if (shownMap == null)
{
base.OnMouseDown(e);
return;
}
if (dragging)
{
dragging = false;
return;
}
else dragging = true;
initialPosition.X = currentPosition.X;
initialPosition.Y = currentPosition.Y;
initialMousePosition = e.Location;
}
protected override void OnMouseMove(MouseEventArgs e)
{
/*parentForm.label7.Text = currentPosition.X.ToString();
parentForm.label8.Text = currentPosition.Y.ToString();
parentForm.label9.Text = mapSize.Width.ToString();
parentForm.label10.Text = mapSize.Height.ToString();
parentForm.label11.Text = Size.Width.ToString();
parentForm.label12.Text = Size.Width.ToString();*/
//base.OnMouseMove(e);
if (!dragging) return;
currentPosition.X = e.X - initialMousePosition.X + initialPosition.X;
currentPosition.Y = e.Y - initialMousePosition.Y + initialPosition.Y;
if (currentPosition.X > 0)
currentPosition.X = 0;
else if (currentPosition.X < -mapSize.Width + Size.Width )
currentPosition.X = -mapSize.Width + Size.Width ;
if (currentPosition.Y > 0)
currentPosition.Y = 0;
else if (currentPosition.Y < -mapSize.Height + Size.Height)
currentPosition.Y = -mapSize.Height + Size.Height;
//if (currentPosition.X + mapSize.Width < this.Size.Width)
// currentPosition.X = this.Size.Width - mapSize.Width;
Invalidate();
// (e.X - initialPosition.X + xinit, e.Y - init_loc.Y + yinit);
}
protected override void OnMouseLeave(EventArgs e)
{
// base.OnMouseLeave(e);
dragging = false;
// F*! if I hold the mouse down this does not work
}
protected override void OnMouseUp(MouseEventArgs e)
{
//base.OnMouseUp(e);
dragging = false;
}
}
}

Well, it seems there was no bad logic except for the fact that I was using the Panel's Size instead of its DisplayRectangle (Size.Width == DisplayRectangle.Width-2). The whole problem was that the images I was using had been exported from Photoshop and had a resolution of 72dpi instead of 96dpi: Same Size, but on using DrawImage they were scaled up. Here's my solution. There are still this to correct but this is the solution regarding my original question. Also some variable names were changed.
namespace GameMaps
{
public class MapPanel : Panel
{
private Map sourceMap;
private Bitmap mapTexture;
private Size mapSize;
private Point mapPosition;
private float dpiX, dpiY;
private Point initialPosition;
private Point initialMousePosition;
private bool dragging;
/* Constructors */
public MapPanel() : base()
{
this.DoubleBuffered = true;
this.sourceMap = null;
this.dpiX = 96.0F; this.dpiY = 96.0F; // For now, this Application won't be DPI aware
}
public MapPanel(Panel targetPanel) : this()
{
// TO DO
}
/* Show a Map */
public void ShowMap(Map map)
{
if (map == null)
return;
sourceMap = map;
mapTexture = new Bitmap(map.MapTexture);
mapTexture.SetResolution(dpiX, dpiY);
mapSize = mapTexture.Size; // ?
mapPosition = new Point(0, 0);
}
protected override void OnPaint(PaintEventArgs e)
{
// base.OnPaint(e);
e.Graphics.PageUnit = GraphicsUnit.Pixel; // ?
e.Graphics.PageScale = 1.0F; // ?
if (sourceMap == null)
{
base.OnPaint(e);
return;
}
e.Graphics.DrawImage(mapTexture, mapPosition.X, mapPosition.Y);
}
protected override void OnMouseDown(MouseEventArgs e)
{
// base.OnMouseDown(e);
if (sourceMap == null)
{
base.OnMouseDown(e);
return;
}
if (dragging)
{
dragging = false;
return;
}
else dragging = true;
initialPosition.X = mapPosition.X;
initialPosition.Y = mapPosition.Y;
initialMousePosition.X = e.Location.X;
initialMousePosition.Y = e.Location.Y;
}
protected override void OnMouseMove(MouseEventArgs e)
{
//base.OnMouseMove(e);
if (!dragging) return;
mapPosition.X = e.X - initialMousePosition.X + initialPosition.X;
mapPosition.Y = e.Y - initialMousePosition.Y + initialPosition.Y;
if (mapPosition.X > 0)
mapPosition.X = 0;
else if (mapPosition.X < DisplayRectangle.Width - mapSize.Width)
mapPosition.X = DisplayRectangle.Width - mapSize.Width;
if (mapPosition.Y > 0)
mapPosition.Y = 0;
else if (mapPosition.Y < DisplayRectangle.Height - mapSize.Height)
mapPosition.Y = DisplayRectangle.Height - mapSize.Height;
Invalidate(); // Force Repaint
}
protected override void OnMouseLeave(EventArgs e)
{
// base.OnMouseLeave(e);
dragging = false;
// TO DO: Correct this
}
protected override void OnMouseUp(MouseEventArgs e)
{
//base.OnMouseUp(e);
dragging = false;
}
}
}

Related

How to draw a Rectangle in any direction after MouseDown using C#?

How can I draw a rectangle in all directions? Current code:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
// Starting point of the selection:
if (e.Button == MouseButtons.Left)
{
_selecting = true;
_selection = new Rectangle(new Point(e.X, e.Y), new Size());
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
// Update the actual size of the selection:
if (_selecting)
{
_selection.Width = e.X - _selection.X;
_selection.Height = e.Y - _selection.Y;
pictureBox1.Refresh(); // redraw picturebox
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && _selecting)
{
_selecting = false;
}
}
This allows me to MouseDown and then draw down and to the right, but I am unable to draw in any other direction beyond the anchor point. How can I draw a rectangle in any direction like e.g. Microsoft Paint?
I first tried:
_selection.Width = Math.Abs(e.X - _selection.X);
_selection.Height = Math.Abs(e.Y - _selection.Y);
But this creates a funny mirror effect (which is not what I want). I then tried a simple shift:
_selection.X = _selection.Left - 5;
This did what I expected and moved a static rectangle 5 units left, so I thought it would be a simple matter of continuously shifting the anchor point during the Paint event:
private void UpdateRectange(Point newPos)
{
var width = newPos.X - _selection.X;
var height = newPos.Y - _selection.Y;
_selection.Width = Math.Abs(width);
_selection.Height = Math.Abs(height);
if (width < 0 && height > 0) // move down (+) and left (-)
{
//_selection.X = _selection.Left + width;
_selection.Offset(width, 0);
}
uxScreenGrab.Refresh(); // redraw picturebox
}
But this resulted in pushing a vertical line across the screen towards the left, when moving to the left of the original anchor point.The width does not properly update for some reason.
Here's another snippet to draw a selection rectangle on a PictureBox:
//...
private Point startPoint;
private Point endPoint;
private readonly Pen P1 = new Pen(Color.SteelBlue, 2) {
Alignment = PenAlignment.Center, DashStyle = DashStyle.Dash};
//...
Set the startPoint in the MouseDown event and reset the endPoint variables:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
startPoint = new Point(e.X, e.Y);
endPoint = Point.Empty;
}
}
Set the endPoint and call Invalidate() method in the MouseMove event:
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
var p = new Point(e.X, e.Y);
if (e.Button == MouseButtons.Left &&
!p.Equals(startPoint))
{
endPoint = p;
pictureBox1.Invalidate();
}
}
Also call Invalidate() in the MouseUp event to remove the selection rectangle:
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
pictureBox1.Invalidate();
}
Draw the selection rectangle:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if(MouseButtons == MouseButtons.Left &&
!startPoint.Equals(endPoint) &&
!endPoint.Equals(Point.Empty))
{
var g = e.Graphics;
var rect = Rectangle.Empty;
if(startPoint.X < endPoint.X)
{
rect.X = startPoint.X;
rect.Width = endPoint.X - startPoint.X;
}
else
{
rect.X = endPoint.X;
rect.Width = startPoint.X - endPoint.X;
}
if(startPoint.Y < endPoint.Y)
{
rect.Y = startPoint.Y;
rect.Height = endPoint.Y - startPoint.Y;
}
else
{
rect.Y = endPoint.Y;
rect.Height = startPoint.Y - endPoint.Y;
}
g.DrawRectangle(P1, rect);
}
}
And don't forget to clean up:
private void YourForm_FormClosing(object sender, FormClosingEventArgs e)
{
P1.Dispose();
}
Keep it simple.
Related Posts
How to call a method that uses PaintEventArgs and coordinates variables
The solution proposed in the question looks good:
_selection.Width = Math.Abs(e.X - initiallySelectedX);
_selection.Height = Math.Abs(e.Y - initiallySelectedY);
...but You have to move the origin of the rectangle when (e.X - initiallySelectedX) < 0
So probably You want to add something like this to Your code:
var diffX = e.x - initiallySelectedX;
if (diffX < 0) _selection.X = initiallySelectedX - diffX;
var diffY = e.y - initiallySelectedY;
if (diffY < 0) _selection.Y = initiallySelectedY - diffY;
Where initiallySelectedX and initiallySelectedY are variables set onMouseDown.
this is only a rough idea.
The idea behind is that the Width and Height of the Rectangle cannot be NEGATIVE !!
UPDATE:
Keeping track of the starting point on the MouseDown event allows the anchor point to correctly update:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
// Starting point of the selection:
if (e.Button == MouseButtons.Left)
{
_selecting = true;
_selection = new Rectangle(new Point(e.X, e.Y), new Size());
_startingPoint = e.Location;
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
// Update the actual size of the selection:
if (_selecting)
{
UpdateRectange(e.Location);
}
}
private void UpdateRectange(Point newPos)
{
var diffX = newPos.X - _startingPoint.X;
var diffY = newPos.Y - _startingPoint.Y;
var newSize = new Size(Math.Abs(diffX), Math.Abs(diffY));
if (diffX > 0 && diffY > 0)
{
_selection = new Rectangle(_startingPoint, newSize);
}
else if (diffX < 0 && diffY < 0)
{
_selection = new Rectangle(newPos, newSize);
}
else if (diffX > 0 && diffY < 0)
{
_selection = new Rectangle(new Point(_startingPoint.X, _startingPoint.Y + diffY), newSize);
}
else
{
_selection = new Rectangle(new Point(_startingPoint.X + diffX, _startingPoint.Y), newSize);
}
uxScreenGrab.Invalidate();
}
UPDATE 2:
Re-wrote UpdateRectangle to simply move the anchor point, instead of instantiating at every call:
private void UpdateRectange(Point newPos)
{
var diffX = newPos.X - _startingPoint.X;
var diffY = newPos.Y - _startingPoint.Y;
var newSize = new Size(Math.Abs(diffX), Math.Abs(diffY));
if (diffX > 0 && diffY > 0)
{
_selection.Size = newSize;
}
else if (diffX < 0 && diffY < 0)
{
_selection.Location = newPos;
_selection.Size = newSize;
}
else if (diffX > 0 && diffY < 0)
{
_selection.Y = _startingPoint.Y + diffY;
_selection.Size = newSize;
}
else
{
_selection.X = _startingPoint.X + diffX;
_selection.Size = newSize;
}
uxScreenGrab.Invalidate();
}

Updating a value on another Class

I have this code that draws a rectangle using the ShapeClass.cs. But I want to update the Rectangle parameters using a button event in the mainform. How do I do that? The PaintRectangle class only gets the initial value on the textbox from the main form. ......................................................................................................................................................................
MAin Class
#region //Passing of values
public string ShapeWidth() { return textBox_Shape_Width.Text;}
public string ShapeHeight() { return textBox_Shape_Height.Text; }
#endregion
private void btn_Draw_Click(object sender, EventArgs e)
{
ShapeClass s = new ShapeClass();
var value = s.diffVar[0];
MessageBox.Show(value.ToString());
pictureBox_Canvas.Paint += paintRect;
pictureBox_Canvas.Refresh();
}
#region //Methods for Hide and Show
public void HideButtons()
{
btn_Rectangle.Visible = false;
btn_Square.Visible = false;
btn_Ellipse.Visible = false;
btn_Circle.Visible = false;
btn_Triangle.Visible = false;
}
public void ShowButtons()
{
btn_Rectangle.Visible = true;
btn_Square.Visible = true;
btn_Ellipse.Visible = true;
btn_Circle.Visible = true;
btn_Triangle.Visible = true;
}
public void HideSettings()
{
btn_Draw.Visible = false;
btn_Accept.Visible = false;
btn_Cancel.Visible = false;
btn_Reset.Visible = false;
btn_Accept.Visible = false;
trackBar_Size.Visible = false;
trackBar_Stroke.Visible = false;
trackBar_Corner.Visible = false;
label_Corner.Visible = false;
label_Height.Visible = false;
label_Size.Visible = false;
label_Stroke.Visible = false;
rb_Both.Visible = false;
rb_Height.Visible = false;
rb_Width.Visible = false;
textBox_Shape_Height.Visible =false;
textBox_Shape_Width.Visible = false;
lbl_Width.Visible = false;
}
public void ShowSettings()
{
btn_Draw.Visible = true;
btn_Accept.Visible = true;
btn_Cancel.Visible = true;
btn_Reset.Visible = true;
btn_Accept.Visible = true;
trackBar_Size.Visible = true;
trackBar_Stroke.Visible = true;
trackBar_Corner.Visible = true;
label_Corner.Visible = true;
label_Height.Visible = true;
label_Size.Visible = true;
label_Stroke.Visible = true;
rb_Both.Visible = true;
rb_Height.Visible = true;
rb_Width.Visible = true;
textBox_Shape_Height.Visible = true;
textBox_Shape_Width.Visible = true;
lbl_Width.Visible = true;
}
#endregion
#region //Rectangle Creation and Scaling
private void btn_Rectangle_Click(object sender, EventArgs e)
{
HideButtons();
ShowSettings();
}
public void paintRect(object sender, PaintEventArgs e)
{
ShapeClass s = new ShapeClass();
s.paintRectangle(e);
}
#endregion
#region //Show and Hide Grid (Checkbox Event)
//Drawing the Grid
private void checkBox_Grid_CheckedChanged(object sender, EventArgs e)
{
if (checkBox_Grid.Checked == true)
{
DrawGrid();
}
else if (!checkBox_Grid.Checked == true)
{
pictureBox_Canvas.Refresh();
HideGrid();
}
else
return;
}
private void DrawGrid()
{
Graphics grid = Graphics.FromImage(bm);
int numOfCells = 301;
int cellSize = 5;
Pen p = new Pen(Color.LightSlateGray);
p.Width = 0.5F;
for (int y = 0; y < numOfCells; ++y)
{
grid.DrawLine(p, 0, y * cellSize, numOfCells * cellSize, y * cellSize);
}
for (int x = 0; x < numOfCells; ++x)
{
grid.DrawLine(p, x * cellSize, 0, x * cellSize, numOfCells * cellSize);
}
pictureBox_Canvas.Image = bm;
}
//Hides the Grid
private void HideGrid()
{
Graphics grid = Graphics.FromImage(bm);
Pen p = new Pen(Color.White);
p.Width = 0.5F;
int numOfCells = 301;
int cellSize = 5;
for (int y = 0; y < numOfCells; ++y)
{
grid.DrawLine(p, 0, y * cellSize, numOfCells * cellSize, y * cellSize);
}
for (int x = 0; x < numOfCells; ++x)
{
grid.DrawLine(p, x * cellSize, 0, x * cellSize, numOfCells * cellSize);
}
pictureBox_Canvas.Image = bm;
}
#endregion
#region //Square Creation and Scaling
private void btn_Square_Click(object sender, EventArgs e)
{
HideButtons();
ShowSettings();
}
#endregion
#region //Circle Creation and Scaling
private void btn_Circle_Click(object sender, EventArgs e)
{
HideButtons();
ShowSettings();
}
#endregion
#region //Ellipse Creation and Scaling
private void btn_Ellipse_Click(object sender, EventArgs e)
{
HideButtons();
ShowSettings();
}
#endregion
#region //Triangle Creation and Scaling
private void btn_Triangle_Click(object sender, EventArgs e)
{
HideButtons();
ShowSettings();
}
#endregion
#region //Accept Button
private void btn_Accept_Click(object sender, EventArgs e)
{
HideSettings();
ShowButtons();
}
#endregion
#region //Reset Button
private void btn_Reset_Click(object sender, EventArgs e)
{
HideSettings();
ShowButtons();
}
#endregion
#region //Cancel Button
private void btn_Cancel_Click(object sender, EventArgs e)
{
HideSettings();
ShowButtons();
}
#endregion
#region //VALIDATIONS
private void textBox_Shape_Width_TextChanged(object sender, EventArgs e)
{
if(Convert.ToInt32(textBox_Shape_Width.Text)>128)
{
MessageBox.Show("Width cannot exceed 128.");
textBox_Shape_Width.Text = 128.ToString();
}
}
private void textBox_Shape_Height_TextChanged(object sender, EventArgs e)
{
if (Convert.ToInt32(textBox_Shape_Height.Text) > 128)
{
MessageBox.Show("Height cannot exceed 128");
textBox_Shape_Height.Text = 128.ToString();
}
}
#endregion
private void trackBar_Size_ValueChanged(object sender, EventArgs e)
{
}
}
}
Shape Class
namespace SealCreator2._0
{
public class ShapeClass :Form1
{
Form1 f1 = new Form1();
public double w1,h1, Rect_Width;
public List<object> diffVar = new List<object>();
public void paintRectangle(PaintEventArgs e)
{
int x, y;
w1 = Convert.ToDouble((Convert.ToInt32(f1.ShapeWidth()) * 96) / 25.4);
h1 = Convert.ToDouble((Convert.ToInt32(f1.ShapeHeight()) * 96) / 25.4);
x = ((484 / 2) - (Convert.ToInt32(w1) / 2)); // Positions the Shape in the center of the PictureBox
y = ((484 / 2) - (Convert.ToInt32(h1) / 2));// Positions the Shape in the center of the PictureBox
//Draws a Rectangle
Pen red = new Pen(Color.Red, 3);
Rectangle rect = new Rectangle(x, y, Convert.ToInt32(w1), Convert.ToInt32(h1));
e.Graphics.DrawRectangle(red, rect);
diffVar.Add(w1);
diffVar.Add(h1);
}
}
}
You can create other class which contain both PaintEventArgs and your params. Ex:
public class DrawArgs
{
// parameter which you can modify base on your logic
public int width;
public int height;
public int x;
public int y;
//your paint event
public PaintEventArgs e;
}
And modify your ShapeClass.paintRectangle() method:
public class ShapeClass
{
public void paintRectangle(DrawArgs drawArgs)
{
//w1 = Convert.ToDouble((Convert.ToInt32(f1.ShapeWidth()) * 96) / 25.4);
//h1 = Convert.ToDouble((Convert.ToInt32(f1.ShapeHeight()) * 96) / 25.4);
//x = ((484 / 2) - (Convert.ToInt32(w1) / 2));
//y = ((484 / 2) - (Convert.ToInt32(h1) / 2));
// get your params
var x = drawArgs.x;
var y = drawArgs.y;
var w1 = drawArgs.width;
var h1 = drawArgs.height;
Pen red = new Pen(Color.Red, 3);
Rectangle rect = new Rectangle(x, y, Convert.ToInt32(w1), Convert.ToInt32(h1));
drawArgs.e.Graphics.DrawRectangle(red, rect);
}
}
And you can call it from paintRect method():
public void paintRect(object sender, PaintEventArgs e)
{
ShapeClass s = new ShapeClass();
var drawArg = new DrawArgs
{
e = e,
// and add your params here
x = something,
y = something,
///.....
};
s.paintRectangle(drawArg);
}
P/S: it is just an example. You can modify the DrawArgs class base on your logic
Add a anothe function to change the parameters.
For example:
void UpdateParameters()
{
ChangeParameters();
}
Give you another suggestion: You can edit this question to add Codes.

C# Why is the Form Location Reseting to (0, 0)

Whenever I move the form in its maximum state and move the form, the form location will default (0, 0). I use a MouseDown, MouseMove, and MouseUp event.
private void TopPanel_MouseDown(object sender, MouseEventArgs e)
{
AdjustingTheForm = true;
}
private void TopPanel_MouseMove(object sender, MouseEventArgs e)
{
if (AdjustingTheForm)
{
scr = Screen.FromControl(this).WorkingArea;
LastLocation = e.Location;
if (FormNormalSize == false)
{
FormNormalSize = true;
CustomForm_Resize(sender, e);
this.Location = new Point(e.X - 400, e.Y - 15);
this.Update();
}
AdjustingTheForm = false;
MovingTheForm = true;
Console.WriteLine("1. " + this.Location);
}
if(MovingTheForm)
{
this.Location = new Point((this.Location.X - LastLocation.X) + e.X, (this.Location.Y - LastLocation.Y) + e.Y);
this.Update();
Console.WriteLine("2. " + this.Location + " " + e.Location);
}
}
private void TopPanel_MouseUp(object sender, MouseEventArgs e)
{
scr = Screen.FromControl(this).WorkingArea;
MovingTheForm = false;
Here is where I put the private instance members:
namespace CustomForm_Practice_1
{
public partial class CustomForm : Form
{
bool minimizeB1MouseDown, maximizeB1MouseDown, exitB1MouseDown;
bool FormNormalSize;
bool AdjustingTheForm, MovingTheForm;
Point LastLocation;
Rectangle scr;
.......
Here are the results when I move the form (UPDATED):
1. this.Location: {X=1100,Y=6}
2. LastLocation: {X=1100,Y=6}
3. e.Location: {X=1100,Y=6}
1. this.Location: {X=0,Y=0}
2. LastLocation: {X=1100,Y=6}
3. e.Location: {X=0,Y=0}
1. this.Location: {X=0,Y=0}
2. LastLocation: {X=1100,Y=6}
3. e.Location: {X=1100,Y=6}
1. this.Location: {X=0,Y=2}
2. LastLocation: {X=1100,Y=6}
3. e.Location: {X=1100,Y=8}
OLD I don't know why x jumps from 703 to 0 and y from 8 to 0. This problem, however, only occurs when the size of the form changes and the form is moved. When the form is at normal size (800, 600). Here is the form resize event:
New This time this.Location started at X = 1100 and Y = 6 and then it went to (0, 0). e.Location did the same thing. Here is the form resize event:
private void CustomForm_Resize(object sender, EventArgs e)
{
if (FormNormalSize == false)
//Maximized Window
{
scr = Screen.FromControl(this).WorkingArea;
this.Location = new Point(scr.X, scr.Y);
this.Size = new Size(scr.Width, scr.Height);
this.Update();
//Panel Heights
TopPanel.Height = 30;
BottomPanel.Height = scr.Height - 32;
//Panel Widths
TopPanel.Width = scr.Width - 2;
BottomPanel.Width = scr.Width - 2;
}
else if (FormNormalSize)
//Normal Window
{
this.Size = new Size(800, 600);
//Panel Heights
TopPanel.Height = 30;
BottomPanel.Height = this.Height - 32;
//Panel Widths
TopPanel.Width = this.Width - 2;
BottomPanel.Width = this.Width - 2;
}
//Panel Locations
TopPanel.Location = new Point(1, 1);
BottomPanel.Location = new Point(1, TopPanel.Height + 1);
The question is, why does the form location go to (0, 0) when this line
this.Location = new Point(e.X - 400, e.Y - 15); changes the location that was previously set this.Location = new Point(scr.X, scr.Y);?
Moving/resizing a form like this can be somewhat fiddly, because the mouse location in MouseEventArgs is given relative to the top left of the form rather than in screen coords.
A better way to track mouse coords when you need screen coords is to use the MousePosition class along with mouse capture via Control.Capture = true.
The easiest way for me to demonstrate this is through a sample app:
Create a default Windows Forms app. I'm going to assume that the main form is called Form1.
Drop onto the main form a Panel called panel1 and set its Dock
property to Fill.
Add to panel1 the following handlers: panel1_MouseDown, panel1_MouseMove and panel1_MouseUp.
Change the code in Form1.cs as follows:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool moving;
Point offset;
Point original;
void panel1_MouseDown(object sender, MouseEventArgs e)
{
moving = true;
panel1.Capture = true;
offset = MousePosition;
original = this.Location;
}
void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (!moving)
return;
int x = original.X + MousePosition.X - offset.X;
int y = original.Y + MousePosition.Y - offset.Y;
this.Location = new Point(x, y);
}
void panel1_MouseUp(object sender, MouseEventArgs e)
{
moving = false;
panel1.Capture = false;
}
}
Compile and run the application then click and drag on the main window to move it around. It should follow the mouse as you move it around.
Once you have that working, you should be able to apply the same logic to your application.
I figured it out. PointToClient help me get the LastLocation value. Here is the new code:
private void TopPanel_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Left)
{
AdjustingTheForm = true;
}
else if (e.Button == MouseButtons.Right)
{
AdjustingTheForm = false;
}
LastLocation = PointToClient(e.Location);
}
private void TopPanel_MouseMove(object sender, MouseEventArgs e)
{
scr = Screen.FromControl(this).WorkingArea;
if (AdjustingTheForm)
{
if (FormNormalSize == false)
{
FormNormalSize = true;
CustomForm_Resize(sender, e);
this.Location = new Point(Cursor.Position.X - 400, Cursor.Position.Y - 15);
this.Update();
LastLocation = PointToClient(e.Location);
MovingFormMaximized = true;
}
else
{
MovingFormMinimized = true;
}
AdjustingTheForm = false;
}
if ((MovingFormMinimized && this.Location.Y > 0) || (MovingFormMinimized && this.Location.Y <= 0 && e.Y > 32))
{
mouseHuggingWall = false;
this.Location = new Point(this.Location.X - LastLocation.X + e.X,
this.Location.Y - LastLocation.Y + e.Y);
this.Update();
}
else if (MovingFormMinimized && this.Location.Y <= 0)
{
mouseHuggingWall = true;
this.Location = new Point(this.Location.X - LastLocation.X + e.X, 0);
this.Update();
}
if ((MovingFormMaximized && this.Location.Y > 0) || (MovingFormMaximized && this.Location.Y <= 0 && e.Y > 32))
{
mouseHuggingWall = false;
this.Location = new Point(this.Location.X -LastLocation.X + e.X,
this.Location.Y - LastLocation.Y + e.Y);
this.Update();
}
else if (MovingFormMaximized && this.Location.Y <= 0)
{
mouseHuggingWall = true;
this.Location = new Point(this.Location.X - LastLocation.X + e.X, 0);
this.Update();
}
}
private void TopPanel_MouseUp(object sender, MouseEventArgs e)
{
scr = Screen.FromControl(this).WorkingArea;
if(mouseHuggingWall == true)
{
FormNormalSize = false;
CustomForm_Resize(sender, e);
}
MovingFormMinimized = false;
MovingFormMaximized = false;
mouseHuggingWall = false;
}
I added more to the code but the main fix is in the code.

C# gui the mouse move event cannot select a list element?

This title might be a bit not precise, what I am really having is this issue. I plotted a few lines, each is stored in a list, as line path. Then I use IsOutlineVisible to measure if the mouse location is on any of them, if mouse is on one, draw it as a different color or do something.
But it only recognize the last line in the list.
I would attach only the relevant part of the code, but this I really am not too sure where is the problem, so here is the entire code
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
List<GraphicsPath> LineGroup = new List<GraphicsPath>();
Point Latest{get;set;}
List<Point> pointtemp = new List<Point>();
bool startdrawline = true;
bool selectlinestate = false;
int selectedline;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
// Save the mouse coordinates
Latest = new Point(e.X, e.Y);
// Force to invalidate the form client area and immediately redraw itself.
Refresh();
if (startdrawline == false)
{
selectedline = Linesel(LineGroup);
}
}
protected override void OnPaint(PaintEventArgs e)
{
this.DoubleBuffered = true;
var g = e.Graphics;
base.OnPaint(e);
Pen penb = new Pen(Color.Navy,2);
Pen peny=new Pen(Color.Yellow,2);
for (int i = 0; i < LineGroup.Count; i++)
{
if (i == selectedline)
{
g.DrawPath(peny, LineGroup[i]);
}
else
{
g.DrawPath(penb, LineGroup[i]);
}
}
penb.Dispose();
peny.Dispose();
if (startdrawline == true)
{
GraphicsPath tracepath = new GraphicsPath();
Pen penr = new Pen(Color.Red,2);
if (pointtemp.Count == 1)
{
tracepath.AddLine(pointtemp[0], Latest);
}
else if (pointtemp.Count > 1)
{
tracepath.AddLine(pointtemp[1], Latest);
}
g.DrawPath(penr, tracepath);
penr.Dispose();
}
Refresh();
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
startdrawline = false;
pointtemp.Clear();
}
else if (e.Button == MouseButtons.Left )
{
startdrawline = true;
Latest = new Point(e.X, e.Y);
if (pointtemp.Count < 2)
{
pointtemp.Add(Latest);
}
else
{
pointtemp[0] = pointtemp[1];
pointtemp[1] = Latest;
}
if (pointtemp.Count == 2)
{
LineP2P(pointtemp);
}
Refresh();
}
}
private void LineP2P(List<Point> pointtemp){
GraphicsPath path = new GraphicsPath();
path.AddLine(pointtemp[0], pointtemp[1]);
LineGroup.Add(path);
}
private int Linesel(List<GraphicsPath> LineGroup)
{
int selectedline=-1;
for (int i =0; i < LineGroup.Count; i++)
{
Pen pen = new Pen(Color.Navy, 8);
if (LineGroup[i].IsOutlineVisible(Latest, pen))
{
selectedline = i;
}
else if (!LineGroup[i].IsOutlineVisible(Latest, pen))
{
selectedline = -1;
}
label1.Text = selectedline.ToString();
}
return selectedline;
}
}
}
When I put the test label.Text under the if
if (LineGroup[i].IsOutlineVisible(Latest, pen))
{
selectedline = i;
label1.Text = selectedline.ToString();
}
it actually works (varies with lines)
Can anyone identify the cause? Lot of Thanks.
The problem is that you did not break out of the loop once you find your line
lets say the line your mouse is on is at index 0. You are going to call
selectedline = 0 on the first iteration
and then on the second iteration
if (LineGroup[1].IsOutlineVisible(Latest, pen))
would be false so
selectedline = -1;
Thus unless you are mouse is on the last line selectedline will always be -1
What you want to do is probably
selectedline = -1;
for (int i =0; i < LineGroup.Count; i++)
{
Pen pen = new Pen(Color.Navy, 8);
if (LineGroup[i].IsOutlineVisible(Latest, pen))
{
selectedline = i;
break;
}
}
label1.Text = selectedline.ToString();
return selectedline;

PictureBox loses resize option when in panel

I want to resize and move objects with mouse at runtime. I am using this code to move and resize controls. But when I put picturebox in panel it loses its resize option from right border and bottom border. What is happening and any solutions?
I got this code from some other forum:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
namespace ControlManager
{
internal class ControlMoverOrResizer
{
private static bool _moving;
private static Point _cursorStartPoint;
private static bool _moveIsInterNal;
private static bool _resizing;
private static Size _currentControlStartSize;
internal static bool MouseIsInLeftEdge { get; set; }
internal static bool MouseIsInRightEdge { get; set; }
internal static bool MouseIsInTopEdge { get; set; }
internal static bool MouseIsInBottomEdge { get; set; }
internal enum MoveOrResize
{
Move,
Resize,
MoveAndResize
}
internal static MoveOrResize WorkType { get; set; }
internal static void Init(Control control)
{
Init(control, control);
}
internal static void Init(Control control, Control container)
{
_moving = false;
_resizing = false;
_moveIsInterNal = false;
_cursorStartPoint = Point.Empty;
MouseIsInLeftEdge = false;
MouseIsInLeftEdge = false;
MouseIsInRightEdge = false;
MouseIsInTopEdge = false;
MouseIsInBottomEdge = false;
WorkType = MoveOrResize.MoveAndResize;
control.MouseDown += (sender, e) => StartMovingOrResizing(control, e);
control.MouseUp += (sender, e) => StopDragOrResizing(control);
control.MouseMove += (sender, e) => MoveControl(container, e);
}
private static void UpdateMouseEdgeProperties(Control control, Point mouseLocationInControl)
{
if (WorkType == MoveOrResize.Move)
{
return;
}
MouseIsInLeftEdge = Math.Abs(mouseLocationInControl.X) <= 2;
MouseIsInRightEdge = Math.Abs(mouseLocationInControl.X - control.Width) <= 2;
MouseIsInTopEdge = Math.Abs(mouseLocationInControl.Y ) <= 2;
MouseIsInBottomEdge = Math.Abs(mouseLocationInControl.Y - control.Height) <= 2;
}
private static void UpdateMouseCursor(Control control)
{
if (WorkType == MoveOrResize.Move)
{
return;
}
if (MouseIsInLeftEdge )
{
if (MouseIsInTopEdge)
{
control.Cursor = Cursors.SizeNWSE;
}
else if (MouseIsInBottomEdge)
{
control.Cursor = Cursors.SizeNESW;
}
else
{
control.Cursor = Cursors.SizeWE;
}
}
else if (MouseIsInRightEdge)
{
if (MouseIsInTopEdge)
{
control.Cursor = Cursors.SizeNESW;
}
else if (MouseIsInBottomEdge)
{
control.Cursor = Cursors.SizeNWSE;
}
else
{
control.Cursor = Cursors.SizeWE;
}
}
else if (MouseIsInTopEdge || MouseIsInBottomEdge)
{
control.Cursor = Cursors.SizeNS;
}
else
{
control.Cursor = Cursors.Default;
}
}
private static void StartMovingOrResizing(Control control, MouseEventArgs e)
{
if (_moving || _resizing)
{
return;
}
if (WorkType!=MoveOrResize.Move &&
(MouseIsInRightEdge || MouseIsInLeftEdge || MouseIsInTopEdge || MouseIsInBottomEdge))
{
_resizing = true;
_currentControlStartSize = control.Size;
}
else if (WorkType!=MoveOrResize.Resize)
{
_moving = true;
control.Cursor = Cursors.Hand;
}
_cursorStartPoint = new Point(e.X, e.Y);
control.Capture = true;
}
private static void MoveControl(Control control, MouseEventArgs e)
{
if (!_resizing && ! _moving)
{
UpdateMouseEdgeProperties(control, new Point(e.X, e.Y));
UpdateMouseCursor(control);
}
if (_resizing)
{
if (MouseIsInLeftEdge)
{
if (MouseIsInTopEdge)
{
control.Width -= (e.X - _cursorStartPoint.X);
control.Left += (e.X - _cursorStartPoint.X);
control.Height -= (e.Y - _cursorStartPoint.Y);
control.Top += (e.Y - _cursorStartPoint.Y);
}
else if (MouseIsInBottomEdge)
{
control.Width -= (e.X - _cursorStartPoint.X);
control.Left += (e.X - _cursorStartPoint.X);
control.Height = (e.Y - _cursorStartPoint.Y) + _currentControlStartSize.Height;
}
else
{
control.Width -= (e.X - _cursorStartPoint.X);
control.Left += (e.X - _cursorStartPoint.X) ;
}
}
else if (MouseIsInRightEdge)
{
if (MouseIsInTopEdge)
{
control.Width = (e.X - _cursorStartPoint.X) + _currentControlStartSize.Width;
control.Height -= (e.Y - _cursorStartPoint.Y);
control.Top += (e.Y - _cursorStartPoint.Y);
}
else if (MouseIsInBottomEdge)
{
control.Width = (e.X - _cursorStartPoint.X) + _currentControlStartSize.Width;
control.Height = (e.Y - _cursorStartPoint.Y) + _currentControlStartSize.Height;
}
else
{
control.Width = (e.X - _cursorStartPoint.X)+_currentControlStartSize.Width;
}
}
else if (MouseIsInTopEdge)
{
control.Height -= (e.Y - _cursorStartPoint.Y);
control.Top += (e.Y - _cursorStartPoint.Y);
}
else if (MouseIsInBottomEdge)
{
control.Height = (e.Y - _cursorStartPoint.Y) + _currentControlStartSize.Height;
}
else
{
StopDragOrResizing(control);
}
}
else if (_moving)
{
_moveIsInterNal = !_moveIsInterNal;
if (!_moveIsInterNal)
{
int x = (e.X - _cursorStartPoint.X) + control.Left;
int y = (e.Y - _cursorStartPoint.Y) + control.Top;
control.Location = new Point(x, y);
}
}
}
private static void StopDragOrResizing(Control control)
{
_resizing = false;
_moving = false;
control.Capture = false;
UpdateMouseCursor(control);
}
#region Save And Load
private static List<Control> GetAllChildControls(Control control, List<Control> list)
{
List<Control> controls = control.Controls.Cast<Control>().ToList();
list.AddRange(controls);
return controls.SelectMany(ctrl => GetAllChildControls(ctrl, list)).ToList();
}
internal static string GetSizeAndPositionOfControlsToString(Control container)
{
List<Control> controls = new List<Control>();
GetAllChildControls(container, controls);
CultureInfo cultureInfo = new CultureInfo("en");
string info = string.Empty;
foreach (Control control in controls)
{
info += control.Name + ":" + control.Left.ToString(cultureInfo) + "," + control.Top.ToString(cultureInfo) + "," +
control.Width.ToString(cultureInfo) + "," + control.Height.ToString(cultureInfo) + "*";
}
return info;
}
internal static void SetSizeAndPositionOfControlsFromString(Control container, string controlsInfoStr)
{
List<Control> controls = new List<Control>();
GetAllChildControls(container, controls);
string[] controlsInfo = controlsInfoStr.Split(new []{"*"},StringSplitOptions.RemoveEmptyEntries );
Dictionary<string, string> controlsInfoDictionary = new Dictionary<string, string>();
foreach (string controlInfo in controlsInfo)
{
string[] info = controlInfo.Split(new [] { ":" }, StringSplitOptions.RemoveEmptyEntries);
controlsInfoDictionary.Add(info[0], info[1]);
}
foreach (Control control in controls)
{
string propertiesStr;
controlsInfoDictionary.TryGetValue(control.Name, out propertiesStr);
string[] properties = propertiesStr.Split(new [] { "," }, StringSplitOptions.RemoveEmptyEntries);
if (properties.Length == 4)
{
control.Left = int.Parse(properties[0]);
control.Top = int.Parse(properties[1]);
control.Width = int.Parse(properties[2]);
control.Height = int.Parse(properties[3]);
}
}
}
#endregion
}
}
You can increase the values of edge tolerance to 5 or more:
MouseIsInLeftEdge = Math.Abs(mouseLocationInControl.X) <= 5;
MouseIsInRightEdge = Math.Abs(mouseLocationInControl.X - control.Width) <= 5;
MouseIsInTopEdge = Math.Abs(mouseLocationInControl.Y ) <= 5;
MouseIsInBottomEdge = Math.Abs(mouseLocationInControl.Y - control.Height) <= 5;
There is a tiny error in the Init routine:
internal static void Init(Control control, Control container)
{
_moving = false;
_resizing = false;
_moveIsInterNal = false;
_cursorStartPoint = Point.Empty;
MouseIsInLeftEdge = false;
MouseIsInLeftEdge = false;
MouseIsInRightEdge = false;
MouseIsInTopEdge = false;
MouseIsInBottomEdge = false;
WorkType = MoveOrResize.MoveAndResize;
control.MouseDown += (sender, e) => StartMovingOrResizing(control, e);
control.MouseUp += (sender, e) => StopDragOrResizing(control);
//control.MouseMove += (sender, e) => MoveControl(container, e); // wrong!!
control.MouseMove += (sender, e) => MoveControl(control, e); // right!
}

Categories