I'm trying to implement the Brushing function to my Paint project.
My idea is everywhen I move and press mouse left button on canvas, I'll add a ellipse to Free-brush (like MSPaint)
Everything was good until I move mouse faster. >> the brush print is separated.
Can anyone explain to me and give me some hints to solve this?
Here is my code:
Point _startPoint, _endPoint;
private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_startPoint = e.GetPosition(MyCanvas);
Ellipse MyBrush_Ellipse = new Ellipse();
MyBrushing.CreateBrush(_cl1, _cl2, ref MyBrush_Ellipse, Mybrush_type);
Canvas.SetTop(MyBrush_Ellipse, _startPoint.Y);
Canvas.SetLeft(MyBrush_Ellipse, _startPoint.X);
}
private void MyCanvas_MouseMove(object sender, MouseEventArgs e)
{
_endPoint = e.GetPosition(MyCanvas);
if (e.LeftButton == MouseButtonState.Pressed)
{
Ellipse MyBrush_Ellipse = new Ellipse();
MyBrushing.CreateBrush(_cl1, _cl2, ref MyBrush_Ellipse, Mybrush_type);
Canvas.SetTop(MyBrush_Ellipse, _endPoint.Y);
Canvas.SetLeft(MyBrush_Ellipse, _endPoint.X);
MyCanvas.Children.Add(MyBrush_Ellipse);
MyCanvas.CaptureMouse();
_myUndoRedo.PushToStackForBrush(MyBrush_Ellipse);
}
}
private void MyCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
MyCanvas.ReleaseMouseCapture();
}
The mouse is not moving constantly over the screen. When moving faster from A to B the mouse actually does not neccessarily move over every part of the screen in between.
To solve your problem draw a line instead of drawing an ellipse at the mouse's position. Therefore you have to store the point the mouse has been before. After a movement draw a line from the stored, last known point to the actual point.
Related
Help please elegantly solve a couple of problems in my small project. I'm developing a small program in c # (WinForms), which uses pictureboxes instead of buttons. I added a small feature like an 'animation' to them: when you mouse over them they decrease in size, when the mouse goes away they return to their original state. Actually, I have two problems here:
If the mouse is brought to the very edge, the picturebox will be decreased, but if the mouse is out of the current size of the picturebox, it's size will be returned back. And so on. Such a kind of 'blinking' turns out.
And more importantly, I have tooltips attached to these pictureboxes. And if you move the mouse over the picturebox, it will decrease in size and the tooltip will not be called. It will take to move the cursor a little without going beyond the picturebox so the tooltip will appear. And this behavior is counterintuitive.
Here's the code:
private void IconReduce(PictureBox picturebox)
{
originalLocation = picturebox.Location;
originalSize = picturebox.Size;
picturebox.Location = new Point(picturebox.Location.X + 2, picturebox.Location.Y + 2);
picturebox.Size = new Size(picturebox.Size.Width - 4, picturebox.Size.Height - 4);
}
private void IconNormal(PictureBox picturebox)
{
picturebox.Location = new Point(originalLocation.X, originalLocation.Y);
picturebox.Size = new Size(originalSize.Width, originalSize.Height);
}
private void pb_MouseEnter(object sender, EventArgs e)
{
IconReduce(sender as PictureBox);
}
private void pb_MouseLeave(object sender, EventArgs e)
{
IconNormal(sender as PictureBox);
}
The point I need help is that when I try to do a click event, a different point of a picture box object should be positioned, not the top left corner.
Is there a way to change the reference moving point of an object?
Example:
The point shown as "Yellow Circle" is the reference point where the "pictureBoxRed" object is located in any mouse click event.
The point shown as "Black Star" is a point indicating the position to be clicked for example.
If the sample point shown as "Black Star" is clicked with the left cursor, it must be moved from the "Yellow Circle" point of the "pictureBoxRed" object, not the upper left corner point of the "pictureBoxRed" object.
Thanks for your aid.
Here Example Gif Animation About This Problem
private void Exmp(object sender, MouseEventArgs e)
{
GeneralClick(e.Button, e.X, e.Y);
}
PictureBox picRed = new PictureBox();
PictureBox picBlue = new PictureBox();
private void GeneralClick(MouseButtons sender, int X, int Y)
{
if (sender == MouseButtons.Left)
{
picRed.Location = new Point(X, Y);
var arrayer = this.PointToScreen(picRed.Location);
arrayer = picBlue.PointToClient(arrayer);
picRed.Parent = picBlue;
}
}
public Form1()
{
InitializeComponent();
picBlue.MouseClick+= new MouseEventHandler(Exmp);
}
I am having a problem with this code. When I start the program Ruler is in the center of the page. When I mousemove when MouseDown is true, the Rectangle (Ruler) is dragable as I want. However, this only works on the first drag. The next time I go to drag it the Ruler jumps back to it's original position, then when you mouse over it the distance from where it was to where it jumped back is calculated and it jumps off the screen as the mouseup event doesn't fire as the rectangle has moved. I basically want to be able to drag the object around the screen however many times I want, but the XStart and YStart need to take the new rendered values on each click.
I think the reason has to do with the e.GetPosition(this).X; as 'this' refers to the Grid that is the rulers parent.
Do I need to commit the RenderTransform to the program? or is there an error in my logic?
It would honestly make more sense if it didn't work at all, but to work perfectly once, then screw up makes no sense.
Here is the code:
private void Rectangle_MouseDown(object sender, MouseButtonEventArgs e)
{
XStart = e.GetPosition(this).X;
YStart = e.GetPosition(this).Y;
Console.WriteLine("X: " + XStart + ", Y: " + YStart);
MouseDown = true;
}
private void Rectangle_MouseMove(object sender, MouseEventArgs e)
{
if(MouseDown)
{
X = e.GetPosition(this).X - XStart;
Y = e.GetPosition(this).Y - YStart;
Ruler.RenderTransform = new TranslateTransform(X, Y);
}
}
private void Ruler_MouseUp(object sender, MouseButtonEventArgs e)
{
MouseDown = false;
}
Looks like Mouse.GetPosition doesn't work when dragging like you would expect.
This example seems relevant, but he uses the DragOver event instead of MouseMove, so I'm not entirely sure if it's the same situation.
In my program I added this code so when I move my mouse all over the screen I will get the mouse cursor coordinates in real time:
Form1 Load:
private void Form1_Load(object sender, EventArgs e)
{
System.Windows.Forms.Timer t1 = new System.Windows.Forms.Timer();
t1.Interval = 50;
t1.Tick += new EventHandler(timer1_Tick);
t1.Enabled = true;;
}
Then the method that get the mouse position:
public static Point GetMousePosition()
{
var position = System.Windows.Forms.Cursor.Position;
return new Point(position.X, position.Y);
}
Then the timer1 tick event:
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text = string.Format("X={0}, Y={1}", GetMousePosition().X, GetMousePosition().Y);
}
Then I ran some application and moved the mouse over a specific location on the screen where the application window is and I found this coordinates:
358, 913
Now I have in my program a listBox with items each item present application screenshot. And if I click on the pictureBox for example in this case on the BATTLEFIELD 3 area I get the mouse cursor coordinates according to the pictureBox area.
So I did:
Point screenCoordinates;
Point pictureBoxSnapCoordinates;
private void pictureBoxSnap_MouseDown(object sender, MouseEventArgs e)
{
screenCoordinates = pictureBoxSnap.PointToScreen(e.Location);
pictureBoxSnapCoordinates = e.Location;
}
Now when I click in the pictureBox at the same location as I found the coordinates 358, 913 but on the pictureBox so the results are:
screenCoordinates 435, 724
pictureBoxSnapCoordinates 23,423
The screenCoordinates isn't the same coordinates as I found with the mouse move 358, 913 it's not even close. There is a big difference between 358,913 and 437,724
e.Location is relative to the Control's top left corner. If you want to use e.Location to get the screen coordinates, then you have to first do pictureBoxSnap.PointToScreen(Point.Empty); and then offset by the e.Location.
Also, Cursor.Position returns a Point object, so making a new Point(...) is pointless.
I must add, if you are dealing with images, and you need to interact with mouse, and do any task related with offset, scroll, etc, I recommend you that library, it is open source and have a lot of examples and methods that will help you
https://github.com/cyotek/Cyotek.Windows.Forms.ImageBox
Inside the Paint event for panel, I have a code, that should draw a blue line between 2 points.
private void panel1_Paint(object sender, PaintEventArgs e)
{
panel1.AllowDrop = true;
listBox1.AllowDrop = true;
if (!s.IsEmpty && !f.IsEmpty)
{
e.Graphics.DrawLine(new Pen(Color.Blue, 5f), f, s);
s = Point.Empty;
f = Point.Empty;
}
}
Im Invalidating the panel in SetPoint method:
void setPoint(Point p)
{
if (f.IsEmpty)
f = p;
else
{
s = p;
panel1.Invalidate();
}
}
That is triggered by clicking on a button.
It will draw a line, but the problem is, that when one line already exists. It will overwrite it. I thought problem is in Invalidate. But I dont know how to fix it because Refresh() or Update() Doesn't work.
What I'm doing wrong?
You need to save all your points in some structure.
In Paint method you will loop through the structure and draw all the lines.
That's because when Paint is activated it redraws all the control once again, and it can't "remember" what was there before, it is only doing what you wrote inside.