So I have a bit of a problem with moving Ovalshapes around a form. The goal is to have a circle move within the bounds of two other circles, one placed inside the other and the moving circle essentially moving around them.
I am having trouble moving the circle with the mouse. Whenever I click and hold the circle, the circle moves to the coordinates of the location I clicked on the circle, such that if I click in the middle of an Ovalshape of size 10, it would set the circle's location to (5,5).
Here is what I have:
public partial class Form1 : Form
{
int smallRadius;
int largeRadius;
int movingRadius;
int distanceFromCenterToLocation;
bool mouseDown;
Point movingCenter;
Point returnPoint;
public Form1()
{
mouseDown = false;
InitializeComponent();
smallRadius = (ovalShape1.Right - ovalShape1.Left) / 2;
largeRadius = (ovalShape2.Right - ovalShape2.Left) / 2;
Point center = new Point(ovalShape1.Left + smallRadius, ovalShape1.Top + smallRadius);
ovalShape3.Height = largeRadius - smallRadius;
ovalShape3.Width = largeRadius - smallRadius;
movingRadius = (ovalShape3.Right - ovalShape3.Left) / 2;
ovalShape3.Location = new Point(center.X - (movingRadius), center.Y - largeRadius);
movingCenter = new Point(ovalShape3.Left + movingRadius, ovalShape3.Top + movingRadius);
distanceFromCenterToLocation = Convert.ToInt32(Math.Sqrt(Math.Pow(movingRadius, 2.0) + Math.Pow(movingRadius, 2.0)));
int middleRadius = center.X - movingCenter.X;
}
private void ovalShape3_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
private void ovalShape3_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
}
private void ovalShape3_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown)
{
ovalShape3.Location = e.Location;
}
}
}
For some reason OvalShape isn't derived from Control and doesn't behave like a control.
When a control receives a mouse event the Location property of the MouseEventArgs holds the coordinates relative to the upper-left corner of the form. Shapes however receive the coordinates relative to their own upper-left corner.
When a mouse button is pressed over a control it will capture the mouse so that subsequent events are sent to the same control until you release the button. Shapes only receive mouse events if the mouse is over the shape no matter if a mouse button is pressed. Once you move the mouse to the top or left the shape doesn't receive any mouse events. Therefore the shape doesn't follow the mouse and also the MouseUp event is not handled.
All shapes in a form are embedded in a single control of type ShapeContainer. This is created automatically when you add a shape to a form in the Visual Studio designer. To get the expected behavior you need to find that ShapeContainer (probably called shapeContainer1) and handle its mouse events instead:
public Form1()
{
InitializeComponent();
// do your initialization
...
// assign the events to the ShapeContainer
// don't forget to remove the handlers from ovalShape3 in the designer!!!
ShapeContainer container = ovalShape3.Parent;
container.MouseUp += ovalShape3_MouseUp;
container.MouseDown += ovalShape3_MouseDown;
container.MouseMove += ovalShape3_MouseMove;
}
Related
I am working on transformations with the cube in open tk. The pan operations are set on the right mouse button. Select the right mouse button and drag. The cube moves according to changes in screen x and y coordinates correctly. The only issue I am facing is, when button is released and again the right mouse button the clicked, the cube is shifted to original position which should not happen. The next pan operation should start from the previous pan position.
The mouse event and pan code is shared.
internal new void MouseDown(object sender, System.Windows.Forms.MouseEventArgs mouse)
{
MouseStartPosition = new Vector2(mouse.X, mouse.Y);
}
internal new void MouseMove(object sender, System.Windows.Forms.MouseEventArgs mouse)
{
if (mouse.Button == MouseButtons.Right)
{
MouseNewPosition = new Vector2(mouse.X, mouse.Y);
Pan();
}
internal void Pan()
{
CubeRender.translateX = MouseNewPosition.X - MouseStartPosition.X;
CubeRender.translateY = MouseStartPosition.Y - MouseNewPosition.Y;
this.Invalidate();
this.Refresh();
}
I am creating a small game that resizes the main window to fit a growing board. I want to re-position the window to keep the button that was clicked under the mouse after resizing. Currently, when clicked the board gets wider and moves the button away from the mouse.
How do I define the button as the anchor point when I move the window?
I don't know if there is a way to use the button as an anchor point. But after a little thinking, i came up with a code that can work for you.
Basically, i'm using the mouse relative to the button position before and after the resize to move the window accordingly. I hope it helps.
private void Btn1Click(object sender, RoutedEventArgs e)
{
int widthGrowth = 50;
int heightGrowth = 80;
Button btn = sender as Button;
Point oldMousePosition = Mouse.GetPosition(btn);
Width += widthGrowth;
Height += heightGrowth;
Point newMousePosition = Mouse.GetPosition(btn);
Left += newMousePosition.X - oldMousePosition.X;
Top += newMousePosition.Y - oldMousePosition.Y;
}
I am working in my own editor for making WPF forms. My issue is that I am having the worst time selecting multiple controls (buttons, labels, etc) and dragging them smoothly across the main window. My application chokes when I try to drag, oh say, 20 selected buttons at the same time.
I found that the culprit is the fact that I am drawing multiple rectangles for each object as they are being dragged and this function is being called in the MouseMove event.
void ControlObjectControl_MouseMove(object sender, MouseEventArgs e)
{
if (newPosition != oldPosition)
{
DragSelection(newPosition);
}
}
private void DragSelection(Point newPosition)
{
foreach (FrameworkElement item in designer.SelectionService.CurrentSelection)
{
if (item is ObjectControl)
(item as ObjectControl).m_ParentControlObject.Position = new System.Drawing.Rectangle() { X = X, Y = Y, Width = (int)item.Width, Height = (int)item.Height };
//..There's code that calculates the item's position and dimensions
}
}
How do I make it to where it only draws the rectangle once and I am still able to see my selected object(s) move smoothly when I drag them?
I did something similar in my application except I used a TranslateTransform to move my elements. Each "frame" (every mouse move) that I was dragging, I got the position of the mouse and compared that to the previous position of the mouse. I would then set a new TranslateTransform X/Y values equal to the X/Y mouse position change and then would give that to the RenderTransform of each object I wanted to move. Something like:
void ControlObjectControl_MouseMove(object sender, MouseEventArgs e)
{
if (dragging)
{
// Get the change in Location
mouseLocation = Mouse.GetPosition();
Point deltaLocation = mouseLocation - previousLocation;
// Make a new transform
TranslateTransform transform = new TranslateTransform();
transform.X = deltaLocation.X;
transform.Y = deltaLocation.Y;
// Apply the transform
// foreach thing
thing.RenderTransform = transform;
// set previous location
previousLocation = mouseLocation;
}
}
Now your objects only get drawn once and only their positions get changed. Hope this helps
So I'm trying to make a slider. I'm using my cursor to move a button's x position.
I have 3 functions, the mouseDown, mouseUp and the mouseMove function. In the mouseUp and mouseDown functions I set a variable to true and false to tell the program that the mouse is clicked or not. In the mouseMove function I tell the program to set the button's x position to the x position of the mouse when the mouse is clicked. This works but has 2 problems.
The first problem is that when I press the button and move it, the button moves along with the mouse's x but it has a space between the mouse and the button. It looks a bit like this:
CURSOR.......BUTTON
The space between the cursor and button change when I change the resolution of the form.
The second problem is that when I move the button it flickers a bit. It only does this at higher speeds but it is a problem in my case.
My code looks like this:
bool mouseDown = false;
private void volumeGrabBT_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mouseDown = true;
}
}
private void volumeGrabBT_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mouseDown = false;
}
}
private void volumeGrabBT_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown == true)
{
Point volumeBTPoint = new Point();
volumeBTPoint.X = Cursor.Position.X;
volumeBTPoint.Y = volumeGrabBT.Location.Y;
volumeGrabBT.Location = volumeBTPoint;
}
}
The volumeGrabBT is the button I'm trying to move along with the mouse.
The volumeBTPoint is the point of the button I'm trying to set the button's position to.
I hope someone can help me fix these problems. Thanks in advance!
I believe that flickering can be fixed by setting some additional form styles: SetStyle(ControlStyles.AllPaintingInWmPaint |ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
in form's constructor. It will use double buffering and generally just draws faster.
For the Cursor class, it's relative to the screen, not your form. You can use this.PointToClient() function to get client's space position of cursor, like this:
Point clientCursor = this.PointToClient(Cursor.Position);
and then use clientCursor to get exact X in your client space.
You have to translate screen coordinates to client coordinates.
Point volumeBTPoint = new Point();
Point point = this.PointToClient(Cursor.Position);
volumeBTPoint.X = point.X;
volumeBTPoint.Y = volumeGrabBT.Location.Y;
volumeGrabBT.Location = volumeBTPoint;
Instead of this you should use button's parent control (Panel, GroupBox, etc).
My problem is that within my Windows Form Application, I want to draw an Ellipse everytime the mouse is clicked within a specific picture box, and I want the previously drawn ellipses to remain present in the picture box.
In its current state, once the mouse is clicked, the previously drawn ellipse will be replaced with the new one drawn at the cursor's new location.
Ball.Paint draws an ellipse.
Here is the relevant code to the problem:
private Ball b;
private void pbField_Paint(object sender, PaintEventArgs e)
{
if (b != null)
b.Paint(e.Graphics);
}
private void pbField_MouseClick(object sender, MouseEventArgs e)
{
int width = 10;
b = new Ball(new Point(e.X - width / 2, e.Y - width / 2), width);
Refresh();
}
If there is any more needed code or information I am able to provide it.
You need some sort of data structure to store prior ellipses. One possible solution is below:
private List<Ball> balls = new List<Ball>(); // Style Note: Don't do this, initialize in the constructor. I know it's legal, but it can cause issues with some code analysis tools.
private void pbField_Paint(object sender, PaintEventArgs e)
{
if (b != null)
{
foreach(Ball b in balls)
{
b.Paint(e.Graphics);
}
}
}
private void pbField_MouseClick(object sender, MouseEventArgs e)
{
int width = 10;
b = new Ball(new Point(e.X - width / 2, e.Y - width / 2), width);
balls.Add(b);
Refresh();
}
If you want more than one ball to be painted, you need to keep track of a list of balls, rather than just b. Every time the control is refreshed, it is expected to redraw all its contents. That means that in pbField_Paint, you need to be ready to draw as many balls as have been added to the scene.