I've got 2 forms: A Parent and a supporting Child form.
When the Child form is initially displayed, I set something called my "Zero Point", which is where the Child form should be positioned relative to the Parent, and defined by one of the controls on the Parent:
private void miShowChild_Click(object sender, EventArgs e) {
if ((m_childForm == null) || m_childForm .IsDisposed) {
m_formLeft = this.Left + this.Control1.Left;
m_formTop = this.Top + this.Control1.Top;
m_childForm = new ChildForm1();
m_childForm.Show(this);
m_childForm.Parent_Shift(m_formTop, m_formLeft);
}
m_roleMap.TopLevel = true;
}
When the Parent form is moved somewhere else, that information is translated to the Child form:
private void Form1_MoveResize(object sender, EventArgs e) {
if ((m_childForm != null) && !m_childForm.IsDisposed) {
m_formLeft = this.Left + this.Control1.Left;
m_formTop = this.Top + this.Control1.Top;
m_childForm.Parent_Shift(m_formTop, m_formLeft);
}
}
That logic seems OK, right?
So, what happens in the Child form?
First, I've got these variables defined:
private bool m_automate;
private int m_left, m_top;
private Point m_zero;
private void ChildForm_Load(object sender, EventArgs e) {
m_left = 0;
m_top = 0;
m_zero = Point.Empty;
}
When the Child is set using Parent_Shift, I want to get where this "Zero Point" should be defined:
public void Parent_Shift(int parentTop, int parentLeft) {
m_automate = true;
if (m_zero != Point.Empty) {
this.Left = parentLeft - m_left;
this.Top = parentTop - m_top;
} else {
this.Left = parentLeft;
this.Top = parentTop;
}
m_zero = new Point(this.Left, this.Top);
m_automate = false;
}
When the Child form is repositioned, and not because of the Parent moving, then I want to record how far from my "Zero Point" this is:
private void Form_MoveResize(object sender, EventArgs e) {
if (!m_automate && this.Visible) {
if (m_zero != Point.Empty) {
m_left = m_zero.X - this.Left;
m_top = m_zero.Y - this.Top;
} else {
m_zero = new Point(this.Left, this.Top);
}
}
}
All of the methods are firing, but I can't seem to get the coordinate system figured out.
I can move the Child form around manually, then move the Parent form and the Child form warps to some other location - then moves proportional to the Parent.
I want the Child to remain at some (X, Y) coordinates relative to the Parent.
When the Child form is moved, that relative coordinate needs to be updated to be where ever the Child form was left.
Does anyone know how to fix my issue?
Put this code in your parent. You don't need any code in your child form.
public partial class ParentForm : Form
{
private bool updatingChildPosition = false;
private Point childFormOffset = Point.Empty;
private ChildForm child = null;
public ParentForm()
{
InitializeComponent();
this.child = new ChildForm();
child.Show();
child.Move += child_Move;
UpdateChildFormOffset();
}
void child_Move(object sender, EventArgs e)
{
// Child form is moved, store it's new offset
UpdateChildFormOffset();
}
private void UpdateChildFormOffset()
{
if (!updatingChildPosition)
{
this.childFormOffset = new Point(
this.child.Location.X - this.Location.X,
this.child.Location.Y - this.Location.Y);
}
}
private void ParentForm_Move(object sender, EventArgs e)
{
// Updating child position
this.updatingChildPosition = true;
child.Location = new Point(
this.Location.X + childFormOffset.X,
this.Location.Y + childFormOffset.Y);
this.updatingChildPosition = false;
}
}
Related
My problem is:
i want Form 2 to be moved only when I move form 1, and it will always stay beneath Form1.
i tried everything i could think of: Location point and set desktop position, i tried a timer of realtime moving , i just cant get it , this shouldn't be so difficult :(
i'm using a panel to move form 1
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
mov = 1;
movX = e.X;
movY = e.Y;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (mov == 1)
{
this.SetDesktopLocation(MousePosition.X - movX, MousePosition.Y - movY);
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
mov = 0;
}
i also tried to make One form and put panels in it and make the form transparent, but i get an issue when i'm trying to move the form via the panel.
i found solution on this:
Move Form1 when I move Form2 in C#
in first form:
protected override void OnLocationChanged(EventArgs e)
{
if (secondForm == null)
{
secondForm = new SecondForm();
}
if (secondForm.wasShown == true)
{
secondForm.Location = new Point(this.Left - parentOffset.X,
this.Top - parentOffset.Y);
}
base.OnLocationChanged(e);
}
in the second form:
public bool wasShown = false;
private void SecondForm_Load(object sender, EventArgs e)
{
this.StartPosition = FormStartPosition.Manual;
Location = new Point(topForm.lX -40, topForm.lY +85);
wasShown = true;
this.Owner = topForm;
}
I am doing a Windows Form Application in c# in which I create a panel for every click i do in "Panel_Inside".
But my problem is when I have to select one especific panel. I do not know how can I identify each panel.
Also I'm having problems when Dragging and Dropping for the same reason.
public void Coloco_Figura(string figura, int Punto_X, int Punto_Y)
{
panel_foto = new Panel();
panel_foto.BackColor = Color.Transparent; //saco fondo
panel_foto.BackgroundImage = Image.FromFile(figura); //asigno imagen al panel
panel_foto.BackgroundImageLayout = ImageLayout.Stretch;
panel_foto.Size = new Size(45, 45);
panel_foto.Location = new Point(Punto_X - 10, Punto_Y - 10);
panel_foto.BringToFront();
panel1.SendToBack();
panel_inside.Controls.Add(panel_foto);
dame_x = Punto_X;
this.panel_foto.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MouseDown);
this.panel_foto.MouseUp += new System.Windows.Forms.MouseEventHandler(this.MouseUp);
this.panel_foto.MouseMove += new System.Windows.Forms.MouseEventHandler(this.MouseMove);
}
here are mouse events
private void MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
# region Borrar Notas
if (Estado_Borro == true)
{
foreach (Panel p in panel_inside.Controls)
{
if (p is Panel)
{
panel_inside.Controls.Remove(p);
if (panel_inside.Controls.Count == 0)
{
listanotas.Clear();
}
else
{
for (int i = 0; i < listanotas.Count; i++)
{
Notas nota = listanotas[i];
if (nota.posX == dame_x)
{
listanotas.Remove(nota);
}
}
}
}
}
Estado_Borro = false;
}
if (e.Button == MouseButtons.Left)
{
drag = true;
x = e.X;
y = e.Y;
}
}
public void MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
drag = false;
}
public void MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (drag)
{
this.panel_foto.Location = new Point(Cursor.Position.X-this.Left, Cursor.Position.Y-this.Top);
}
To identify each panel, first you must set the Name or Tag property:
panel_foto.Name = "panel_foto1";
Then in your event handler,do something like this:
Panel p=(Panel)sender;
if (p.Name == "panel_foto1")
{
//Do your staff
}
Download the project
I am trying to make a panel with a background color which should be able to be drawn in runtime when the user holds down left mouse button and moves it around. All works find when the user is starting from top left and go to bottom right just like the image shows:
But I want the user to be able to make the panel from bottom right to top left. Just like when you select something on your computer with your mouse
Here is my code for now:
public void parent_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
Point tempLoc = e.Location;
this.Location = new Point
(
Math.Min(this.Location.X, tempLoc.X),
Math.Min(this.Location.Y, tempLoc.Y)
);
this.Size = new Size
(
Math.Abs(this.Location.X - tempLoc.X),
Math.Abs(this.Location.Y - tempLoc.Y)
);
this.Invalidate();
}
}
I think this is where I go wrong, and I simply can't find the right algorithm for it:
this.Size = new Size
(
Math.Abs(this.Location.X - tempLoc.X),
Math.Abs(this.Location.Y - tempLoc.Y)
);
But if I use a rectangle it works fine, but I want my panel to be able to do it as well.
You need to just check the minimums and maximums of your starting point versus your mousemoving point. The problem with the code is you are using the control location as a starting point, but if you move the mouse from bottom-right to top-left, your location needs to change. A control can't have a negative size.
Here is how I re-wrote it (I removed unnecessary stuff for testing):
public class SelectionTool : Panel {
Form parent;
Point _StartingPoint;
public SelectionTool(Form parent, Point startingPoint) {
this.DoubleBuffered = true;
this.Location = startingPoint;
//this.endingPoint = startingPoint;
_StartingPoint = startingPoint;
this.parent = parent;
this.parent.Controls.Add(this);
this.parent.MouseMove += new MouseEventHandler(parent_MouseMove);
this.BringToFront();
this.Size = new Size(0, 0);
}
public void parent_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
int minX = Math.Min(e.Location.X, _StartingPoint.X);
int minY = Math.Min(e.Location.Y, _StartingPoint.Y);
int maxX = Math.Max(e.Location.X, _StartingPoint.X);
int maxY = Math.Max(e.Location.Y, _StartingPoint.Y);
this.SetBounds(minX, minY, maxX - minX, maxY - minY);
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
this.BackColor = Color.Blue;
}
}
Here is the code I used to test it on a form:
private SelectionTool _SelectPanel = null;
private void Form1_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == System.Windows.Forms.MouseButtons.Left) {
if (_SelectPanel == null)
_SelectPanel = new SelectionTool(this, e.Location);
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e) {
if (_SelectPanel != null) {
_SelectPanel.Dispose();
_SelectPanel = null;
}
}
I am trying to move a drawn line by grabbing it with the mouse.
The line have already been drawn with Graphics.DrawLine(Pen P, Point A, Point B).
There is absolutely no problems with creating the Line and drawing it on the form.
I've tried:
Adding the line to a GraphicsPath - This does not even draw the line OnPaint.
Checking if MouseEventArgs e.Location is on the line with some basic algebra (calculations which I have thrown away as of now)
So to sum it up: I want to grab the line and drag it somewhere but I can't even check if e.Location even is on the Line, how do I do this?
EDIT: This is how the code looks when I'm using the GraphicsPath.
When I don't use the GraphicsPath I have:
if (s.thisShape == ShapeType.Line) {
g.DrawLine(pen, s.p1, s.p2);
} else { ... }`
in the drawingShapes method.
From the drawStuff : Usercontrol class:
private void drawStuff_MouseDown(object sender, MouseEventArgs e)
{
pointRegion = e.Location;
for (int i = 0; i < Shapes.Count; i++)
{
if (Shapes[i].Region.IsVisible(pointRegion))
{
isDragging = true;
count = i;
break;
}
}
}
private void drawStuff_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
Shapes[count].moveWithDiff(pointRegion, e.Location);
pointRegion = e.Location;
Refresh();
}
}
private void drawStuff_MouseUp(object sender, MouseEventArgs e)
{
isDragging = false;
Refresh();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
drawShapes(e.Graphics);
}
private void drawShapes(Graphics g)
{
temporaryPen = pennaLeft;
foreach (Shape s in Shapes)
{
g.FillRegion(temporaryPen, s.Region);
}
}
From the Shape : Usercontrol class:
public void moveWithDiff(Point pr, Point mp)
{
Point p = new Point();
if (this.thisShape == ShapeType.Line)
{
p.X = mp.X - pr.X;
p.Y = mp.Y - pr.Y;
this.p1.X += p.X;
this.p1.Y += p.Y;
this.p2.X += p.X;
this.p2.Y += p.Y;
}
RefreshPath();
}
private void RefreshPath()
{
gPath = new GraphicsPath();
switch (thisShape)
{
case ShapeType.Line:
gPath.AddLine(this.p1, this.p2);
break;
}
this.Region = new Region(gPath);
}
Now this doesn't even draw the line, however with said if statement in drawingShapes() It draws perfectly but I can not drag it somewhere else.
Let's start with the basics, getting a line on the screen. I created a custom class to handle some of the functions I want available to me for this process:
public class MyLine
{
public Pen pen { get; set; }
public Point Start { get; set; }
public Point End { get; set; }
public MyLine(Pen p, Point p1, Point p2)
{
pen = p;
Start = p1;
End = p2;
}
public float slope
{
get
{
return (((float)End.Y - (float)Start.Y) / ((float)End.X - (float)Start.X));
}
}
public float YIntercept
{
get
{
return Start.Y - slope*Start.X;
}
}
public bool IsPointOnLine(Point p, int cushion)
{
float temp = (slope * p.X + YIntercept);
if (temp >= (p.Y-cushion) && temp <=(p.Y+cushion))
{
return true;
}
else
{
return false;
}
}
}
This class provides a few helper functions that will make our life easier. We have properties that return the slope and the Y-intercept, so we can determine if a certain point is on the line. We then provide a helper function IsPointOnLine() that takes a point and a cushion. The cushion is used to simply allow for a user to click close enough to the line to get it to return true.
Next I am going to instantiate the line and draw it in the Form's paint event:
MyLine m;
private void Form1_Load(object sender, EventArgs e)
{
m= new MyLine(Pens.Black, new Point(20, 20), new Point(40, 40));
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(m.pen, m.Start, m.End);
}
Now you should be able to run your application and see a line that goes from 20,20 to 40,40 on the screen.
Now I want to handle the mouse interaction with the line, so on MouseDown, we will see if the click point intersects the line and if it is set a flag and keep our deltas from the endpoints. On the MouseMove event, we will see if the line has been clicked but not released and reset the coordinates appropriately. In the MouseUp event, we simple reset our flag:
Point deltaStart;
Point deltaEnd;
bool dragging = false;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left && m.IsPointOnLine(e.Location, 5))
{
dragging = true;
deltaStart = new Point(m.Start.X - e.Location.X, m.Start.Y - e.Location.Y);
deltaEnd = new Point(m.End.X - e.Location.X, m.End.Y - e.Location.Y);
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (dragging && deltaStart != null && deltaEnd != null )
{
m.Start = new Point(deltaStart.X + e.Location.X, deltaStart.Y + e.Location.Y);
m.End = new Point(deltaEnd.X + e.Location.X, deltaEnd.Y + e.Location.Y);
this.Refresh();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
dragging = false;
}
Now you should be able to click within 5 pixels of the line and have it move with your mouse.
Note, there are some spots in the code that need additional error handling, especially to handle division by 0 errors.
I suggest you create a rectangle that is the width of the line and the length of the line, then you can use
if(rectangle.Contains(Point p))
{
// do your move
}
You can also inflate the rectangle to make it easier to grab with:
rectangle.Inflate(1, 1);
i have a requirement in which my form is transparent,if my mouse enters into it the form
should became visible,if my mouse leaves out of the form it becomes transparent, i have three different controls placed in my form , each controls mouse leave and mouse enter is the same that of the form . if my mouse enters into the form and enters into a control
form_mouseleaveevent and control_mouseenterd gets fired so iam not able to achieve it,how to overcome this.
below is the piece of code for this:
private void TransToOpac()
{
if (!isTransparent)
return;
if (TtoOON == false )
{
TtoOON = true;
for (i = this.Opacity; i <= 1; i = i + 0.02)
{
this.Opacity = i;
Thread.Sleep(50);
}
isTransparent = false;
TtoOON = false;
}
}
private void OpacToTrans()
{
if (isTransparent)
return;
if (OtoTON == false )
{
OtoTON = true;
for (i = this.Opacity; i >= 0.5; i = i - 0.02)
{
this.Opacity = i;
Thread.Sleep(50);
}
isTransparent = true;
OtoTON = false;
}
}
private void OnMouseEntered(object sender, EventArgs e)
{
TransToOpac();
}
private void OnMouseLeft(object sender, EventArgs e)
{
OpacToTrans();
}
You can't get this done with MouseEnter/Leave events. The smaller problem is that the form's Leave event may never fire if a control is close to the edge. The bigger problem is that it will fire when the cursor moves into the non-client area (border, caption), you don't want to fade the form when the user tries to close or resize the window.
The crude but effective solution is to use a timer to check where the mouse is located:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.Opacity = 0.99; // Avoid flicker
mFadeTimer.Interval = 15;
mFadeTimer.Tick += new EventHandler(mFadeTimer_Tick);
mMouseTimer.Interval = 200;
mMouseTimer.Tick += new EventHandler(mMouseTimer_Tick);
mMouseTimer.Enabled = true;
}
void mMouseTimer_Tick(object sender, EventArgs e) {
if (this.Bounds.Contains(Control.MousePosition)) {
if (mFade <= 0) { mFade = 1; mFadeTimer.Enabled = true; }
}
else {
if (mFade >= 0) { mFade = -1; mFadeTimer.Enabled = true; }
}
}
void mFadeTimer_Tick(object sender, EventArgs e) {
double opaq = this.Opacity + mFade * 0.05;
if (opaq >= 0.99) { opaq = 0.99; mFadeTimer.Enabled = false; }
if (opaq <= 0.15) { opaq = 0.15; mFadeTimer.Enabled = false; }
this.Opacity = opaq;
}
private Timer mFadeTimer = new Timer();
private Timer mMouseTimer = new Timer();
private int mFade = 0;
}
You could also check in Form_MouseLeave whether the mouse pointer is still within the form's bounds and in that case not fade out.
EDIT
There are several ways to find out whether the mouse is still within form's bounds. Easiest would be to use the Mouse.GetPosition method to find the current mouse position. The result is the location of the mouse pointer in screen coordinates. You can then check, whether the form's bounding rectangle contains the location.