C# GUI -- Make Shape Follow Mouse and Place On Click - c#

I'm developing a basic GUI Windows Form Application. It allows the user to change colors using sliding bars, change the size of shapes using scroll bars, and click a check box to determine if the shape should be filled, clear the screen if the clear button is clicked, and switch between shapes with buttons. I'm currently using the MouseMove event to cause the shape to follow the mouse around inside of the panel. I also have an event for a MouseClick. When there is a mouseclick, I want it to "place" that shape so that the graphic persists. I've been able to move a single shape to where the user clicks and make it follow the mouse, I just don't know how to combine both.
This is what I have so far:
void DrawShape()
{
//g.Clear(Color.White);
p.Color = Color.FromArgb(r, gr, b);
if (IsChecked) // If checkbox is checked for fill
{
if (IsRect)
{
g.FillRectangle(myBrush, left, top, wid, ht); // Filled Rectangle
}
else if (IsEllipse)
{
g.FillEllipse(myBrush, left, top, wid, ht); // Filled Ellipse
}
}
else // not filled
{
if (IsRect)
{
g.DrawRectangle(p, left, top, wid, ht); // empty rectangle
}
else if (IsEllipse)// empty ellipse
{
g.DrawEllipse(p, left, top, wid, ht);
}
}
}
private void panel1_MouseMove(object sender, MouseEventArgs e) // when mouse moves
{
left = e.X;
top = e.Y;
DrawShape();
}
private void panel1_MouseClick(object sender, MouseEventArgs e) //when mouse clicks
{
left = e.X;
top = e.Y;
IsClick = true;
DrawShape();
IsClick = false;
}

Related

MS Chart Control: prevent zoom when clicking

I'm using a MS Chart Control that sets a cursor when the chart is clicked and that enables the user to zoom in and out. When the user tries to click into the chart it accidentally happens that he drags a very small zoom rectangle and the chart zooms in instead of handling the click.
What can be done to prevent zooming in when trying to click? Is there something like a minimum rectangle size for zooming?
Here's how I handle the click:
_area = new ChartArea();
private void chart1_MouseClick(object sender, MouseEventArgs e)
{
try
{
_area.CursorX.SetCursorPixelPosition(new Point(e.X, e.Y), true);
}
catch (Exception ex)
{
}
}
And this is how I setup the zoom and cursor settings:
_area.AxisX.ScaleView.Zoomable = true;
_area.CursorX.IsUserSelectionEnabled = true;
_area.CursorX.IntervalType = DateTimeIntervalType.Seconds;
_area.CursorX.Interval = 1D;
_area.CursorY.IsUserSelectionEnabled = true;
_area.CursorY.Interval = 0;
You can manually handle zooming yourself. You can use the MouseDown event to capture the start X and start Y. Then use the MouseUp event to capture the end X and end Y. Once you have your start and end points you can determine if you want to zoom or not. If you want to zoom you can use the helper function below to manually zoom.
private void set_chart_zoom(ChartArea c, double xStart, double xEnd, double yStart, double yEnd)
{
c.AxisX.ScaleView.Zoom(xStart, xEnd);
c.AxisY.ScaleView.Zoom(yStart, yEnd);
}
Based on #Baddack's answer here's a complete solution. The key is to disable the zoom feature of the chart and zoom manually (like Baddack suggested) by using MouseUp/MouseDown events. The user selection feature of the chart is kept enabled to use the selection rectangle for setting the zoom interval.
This sample code checks if the zoom retangle is at least 10 pixels wide and high. Only if that's the case the zoom is initiated:
private ChartArea _area;
private Point _chartMouseDownLocation;
...
private void MainForm_Load(object sender, EventArgs e)
{
...
// Disable zooming by chart control because zoom is initiated by MouseUp event
_area.AxisX.ScaleView.Zoomable = false;
_area.AxisY.ScaleView.Zoomable = false;
// Enable user selection to get the interval/rectangle of the selection for
// determining the interval for zooming
_area.CursorX.IsUserSelectionEnabled = true;
_area.CursorX.IntervalType = DateTimeIntervalType.Seconds;
_area.CursorX.Interval = 1D;
_area.CursorY.IsUserSelectionEnabled = true;
_area.CursorY.Interval = 0;
}
private void chart1_MouseDown(object sender, MouseEventArgs e)
{
_chartMouseDownLocation = e.Location;
}
private void chart1_MouseUp(object sender, MouseEventArgs e)
{
// Check if rectangle has at least 10 pixels with and hright
if (Math.Abs(e.Location.X - _chartMouseDownLocation.X) > 10 &&
Math.Abs(e.Location.Y - _chartMouseDownLocation.Y) > 10)
{
// Zoom to the Selection rectangle
_area.AxisX.ScaleView.Zoom(
Math.Min(_area.CursorX.SelectionStart, _area.CursorX.SelectionEnd),
Math.Max(_area.CursorX.SelectionStart, _area.CursorX.SelectionEnd)
);
_area.AxisY.ScaleView.Zoom(
Math.Min(_area.CursorY.SelectionStart, _area.CursorY.SelectionEnd),
Math.Max(_area.CursorY.SelectionStart, _area.CursorY.SelectionEnd)
);
}
// Reset/hide the selection rectangle
_area.CursorX.SetSelectionPosition(0D, 0D);
_area.CursorY.SetSelectionPosition(0D, 0D);
}

Mouse_move event is fired but updateChart function inside of it is called only once. Why?

I have issue with windows form. Working on mouse move event which gets fired when mouse moves over chart and attempts to scroll the chart. When user click on chart it will call mouseDown event and grab point clicked. I am using this clicked point along with e.X(current point when mouse moves) in mouse move event to check if mouse is moving right or left. I can see change in values when mouse moves but that change is applied only once. i.e. When mouse is moved chart should scroll along with mouse. but all I get is just one shift in chart when I lift the mouse up. It does not scroll when mouse is moving instead it changes value when mouse mouse moves up.
Following is the code for mouse move and mouse up event.
Variable that I declared to use in following functions
bool isMousepressed = false; //used to relate mouse event with zoom buttons
bool isZoomed = false;
bool isMoving = false; //allow scrolling of chart after zooming in
bool isMouseDown = false; //used to relate mouse events occured in zoomed in chart
int pointClicked;
MouseDown
private void chart_MouseDown(object sender, MouseEventArgs e)
{
isMouseDown = true;
//if mouse is clicked after first zoom in it will scroll chart
if (isZoomed)
{
this.Cursor = csrHand;
pointClicked = e.X;
isMoving = true;
return;
}
//******when left click is made and we have some points in beginSelection
//******i.e. start point for zoom, then only you show the rectangle selection frame
if (e.Button == System.Windows.Forms.MouseButtons.Left && !isMousepressed)
{
//do something
isMousepressed = true;
}
else
{
//do something
}
}
Mouse up event
private void chart_MouseMove(object sender, MouseEventArgs e)
{
if (!isMouseDown) return;
//checking for zoom
if (isZoomed && isMoving)
{
double offset = 0;
//checks if mouse moved to left side after clicking --> scroll chart from right to left --> adding points at the end of chart
if (e.X < pointClicked)
{
double xmax = lastmaxT;
xmax = xmax + (0.20 * xmax);
offset = xmax - lastmaxT;
if (!isMouseEventOccured) { xStart = lastminT; }
//after increasing value of xmax if it exceeds max x value then s
if (xmax >= maxNumChartPointZoomOut) { isMoving = false; return; }
updateChart(lastSelectedProfile, lastSelectedWeldIndex, (xStart + offset), xmax);
}
//checks if mouse moved to right side after clicking --> scroll chart from left to right --> adding points at the beginning
if (e.X > pointClicked)
{
//lastminT is xStart value after zoom in
double xmin = lastminT;
xmin = xmin - (0.20 * xmin);
offset = lastminT - lastminT;
if (!isMouseEventOccured) { xEnd = chartA.BottomMax; }
//if after decreasing value of
if (xmin <= 0) { isMoving = false; return; }
updateChart(lastSelectedProfile, lastSelectedWeldIndex, xmin, (xEnd - offset));
}
return;
}
//checks if left mouse button is clicked or not to capture beginning point and then end point for drawing selection rectangle
if (e.Button == System.Windows.Forms.MouseButtons.Left && beginSelectionPoint != Point.Empty)
{
//do something
}
else
{
//do something
}
}
here is the code for mouse up event
private void chart_MouseUp(object sender, MouseEventArgs e)
{
if (isZoomed)
{
this.Cursor = System.Windows.Forms.Cursors.Default;
isMouseDown = false;
return;
}
Point p1, p2;
//when mouse up occurs it first checks, with isMousePressed, if mouse was pressed or not
if (isMousepressed)
{
isMousepressed = false;
isMouseEventOccured = true;
isMouseDown = false;
//do something... here I get the value of xStart and xEnd
if (!isZoomed) { isZoomed = true; }
//call updatechart() with start and end points on graph being p1/p2 or beginselection/endselection
updateChart(lastSelectedProfile, lastSelectedWeldIndex, xStart, xEnd);
lastminT = xStart;
lastmaxT = xEnd;
beginSelectionPoint = endSelectionPoint = Point.Empty;
}
else return;
}
As per my search and understanding mouse move event fires when mouse is moved over given control and executes code continuously (including calling of any function like I have updateChart()). Any explanation about mouse move event is appreciated if my understanding sounds wrong from mouse move event.
Note: my chart is not using MSChart and no DataVisualization package. I am new to development so I will try to provide as much info as I can to solve and any help is much appreciated. Thank you

Drawing a straight line in visual studio C# by the user along with the line moving along with the mouse?

the user should be able to draw a straight line on a panel similar to drawing a straight line in paint .
the user clicks on the panel and when he moves the mouse the line should also move along with the mouse (i.e similar to drawing a staright line in paint) and when the user releases the mouse the line should have been drawn from the original point of click to this release point .
i.e not a free hand line.
is there any animation for this ?
How about this? :
public class LinePanel : Panel
{
public LinePanel()
{
this.MouseDown += (src, e) => { LineStartPos = LineEndPos = e.Location; Capture = true; Invalidate(); };
this.MouseMove += (src, e) => { if (Capture) { LineEndPos = e.Location; Invalidate(); } };
this.MouseUp += (src, e) => { if (Capture) { LineEndPos = e.Location; } Capture = false; Invalidate(); };
}
private Point LineStartPos, LineEndPos;
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (LineStartPos != LineEndPos)
e.Graphics.DrawLine(new Pen(Color.Black, 2), LineStartPos, LineEndPos);
}
}
To test you can just add a new LinePanel() to the Controls collection of your form, and set location/size or anchor / dock paramaters to size it.

rectangle drawn in different point when canvas is zoomed

I have a canvas which has a zooming function. There are a lot of elements inside of it so, for selection I was going to use a selection box which I create dynamically when selection box is clicked. On clicking the button, I add the rectangle to the canvas and again, on clicking the button, I remove it.
I have the following xaml code:
<Viewbox x:Name="vbCanvas">
<Grid x:Name="theGrid"
MouseDown="Grid_MouseDown"
MouseUp="Grid_MouseUp"
MouseMove="Grid_MouseMove"
Background="Transparent">
<Canvas Name="canvasWaSNA" Margin="0,10,10,10" Height="720" Width="1280">
</Canvas>
</Grid>
</Viewbox>
mouse events of theGrid draws the rectangle on runtime on the canvas. The codes for those events are:
bool mouseDown = false;
Point mouseDownPos;
Point mouseUpPos;
private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{
mouseDown = true;
mouseDownPos = e.GetPosition(theGrid);
theGrid.CaptureMouse();
// Initial placement of the drag selection box.
Canvas.SetLeft(sBox, mouseDownPos.X);
Canvas.SetTop(sBox, mouseDownPos.Y);
sBox.Width = 0;
sBox.Height = 0;
// Make the drag selection box visible.
sBox.Visibility = Visibility.Visible;
}
}
private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
{
// Release the mouse capture and stop tracking it.
mouseDown = false;
mouseUpPos = e.GetPosition(theGrid);
theGrid.ReleaseMouseCapture();
// Show the drag selection box.
sBox.Visibility = Visibility.Visible;
MessageBox.Show(mouseDownPos.ToString() + " " + mouseUpPos.ToString());
}
private void Grid_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown)
{
// When the mouse is held down, reposition the drag selection box.
Point mousePos = e.GetPosition(theGrid);
if (mouseDownPos.X < mousePos.X)
{
Canvas.SetLeft(sBox, mouseDownPos.X);
sBox.Width = mousePos.X - mouseDownPos.X;
}
else
{
Canvas.SetLeft(sBox, mousePos.X);
sBox.Width = mouseDownPos.X - mousePos.X;
}
if (mouseDownPos.Y < mousePos.Y)
{
Canvas.SetTop(sBox, mouseDownPos.Y);
sBox.Height = mousePos.Y - mouseDownPos.Y;
}
else
{
Canvas.SetTop(sBox, mousePos.Y);
sBox.Height = mouseDownPos.Y - mousePos.Y;
}
}
}
To create a Rectangle at runtime, I have to click a button. The event of that button is as follows:
private void select_Click_1(object sender, RoutedEventArgs e)
{
if (!canvasWaSNA.Children.Contains(sBox))
{
sBox.Name = "selectionBox";
sBox.StrokeThickness = 1.5 / zoomfactor;
sBox.StrokeDashArray = new DoubleCollection { 1, 2 };
sBox.Visibility = System.Windows.Visibility.Collapsed;
sBox.Stroke = Brushes.Gray;
canvasWaSNA.Children.Add(sBox);
}
else
{
sBox.Visibility = System.Windows.Visibility.Collapsed;
canvasWaSNA.Children.Remove(sBox);
}
}
I am using the following code to zoom into the canvas:
double zoomfactor = 1.0;
void window_MouseWheel(object sender, MouseWheelEventArgs e)
{
Point p = e.MouseDevice.GetPosition(canvasWaSNA); //gets the location of the canvas at which the mouse is pointed
Matrix m = canvasWaSNA.RenderTransform.Value;
if (e.Delta > 0)
{ //the amount of wheel of mouse changed. e.Delta holds int value.. +ve for uproll and -ve for downroll
m.ScaleAtPrepend(1.1, 1.1, p.X, p.Y);
zoomfactor *= 1.1;
}
else
{
m.ScaleAtPrepend(1 / 1.1, 1 / 1.1, p.X, p.Y);
zoomfactor /= 1.1;
}
canvasWaSNA.RenderTransform = new MatrixTransform(m);
}
When my canvas is on original size, The rectangle is drawn perfectly but as I zoom in or zoom out, rectangle is drawn abnormally. It starts to draw from other points. What might be the problem? Please help
Well, I wasnot supposed to capture the mouse position with respect to theGrid, as I had to create the rectangle with respect to canvas. So, I have to get the position as e.GetPosition(canvasWaSNA) and the intended result was shown. It captured the mouse position on the canvas. Now, the rectangle is drawn perfectly even when zoomed in or zoomed out.
Also, I improved the StrokeThickness of the rectangle drawn by referencing it with the zoomfactor of the canvas.
private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{mouseDown = true;
mouseDownPos = e.GetPosition(canvasWaSNA);
theGrid.CaptureMouse();
sBox.StrokeThickness = 1.5 / zoomfactor;
// Initial placement of the drag selection box.
Canvas.SetLeft(sBox, mouseDownPos.X);
Canvas.SetTop(sBox, mouseDownPos.Y);
sBox.Width = 0;
sBox.Height = 0;
// Make the drag selection box visible.
sBox.Visibility = Visibility.Visible;
}

C# Drawing Rectangle On the mouse event

I want to draw a rectangle. Thing what I want is that show the user to rectangle on the mouse event.
Like in the image. This is for C# .net Forms application.
Help me to achieve this. Any help is appreciated.
Thank You
Yohan
You can do that in three steps:
First check if mouse is pressed down
If it is then on mouse move event keep initializing the rectangle with new positions while mouse is being dragged
Then on paint event draw the rectangle. (It will be raised for almost every mouse event, depends mouse refresh rate and dpi)
You can do somthing like this (in your Form):
public class Form1
{
Rectangle mRect;
public Form1()
{
InitializeComponents();
//Improves prformance and reduces flickering
this.DoubleBuffered = true;
}
//Initiate rectangle with mouse down event
protected override void OnMouseDown(MouseEventArgs e)
{
mRect = new Rectangle(e.X, e.Y, 0, 0);
this.Invalidate();
}
//check if mouse is down and being draged, then draw rectangle
protected override void OnMouseMove(MouseEventArgs e)
{
if( e.Button == MouseButtons.Left)
{
mRect = new Rectangle(mRect.Left, mRect.Top, e.X - mRect.Left, e.Y - mRect.Top);
this.Invalidate();
}
}
//draw the rectangle on paint event
protected override void OnPaint(PaintEventArgs e)
{
//Draw a rectangle with 2pixel wide line
using(Pen pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, mRect);
}
}
}
later if you want to check if Buttons (shown in diagram) are in rectangle or not , you can do that by checking the Button's region and check if they lie in your drawn rectangle.
The solution by Shekhar_Pro draws a rectangle just in one direction (top to bottom, left to right) if you want to draw a rectangle regardless of the mouse position and the direction of the movement the solution is:
Point selPoint;
Rectangle mRect;
void OnMouseDown(object sender, MouseEventArgs e)
{
selPoint = e.Location;
// add it to AutoScrollPosition if your control is scrollable
}
void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point p = e.Location;
int x = Math.Min(selPoint.X, p.X)
int y = Math.Min(selPoint.Y, p.Y)
int w = Math.Abs(p.X - selPoint.X);
int h = Math.Abs(p.Y - selPoint.Y);
mRect = new Rectangle(x, y, w, h);
this.Invalidate();
}
}
void OnPaint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.Blue, mRect);
}
Those blue rectangles look a lot like controls. Drawing a line on top of a control is hard to do in Winforms. You have to create a transparent window that overlays the design surface and draw the rectangle on that window. This is also the way the Winforms designer works. Sample code is here.

Categories