Can someone help me solve the question: How can I divide the figure into the fields, so depending on which area will be mouse click it will be carried out a specific event?
private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//if (!isDragging)
{
//creating of my user control element
NodePicture node = new NodePicture();
node.Width = 100;
node.Height = 100;
//use cursor position as the center of the figure
Point point = e.GetPosition(this);
node.SetValue(Canvas.TopProperty, point.Y - node.Height / 2);
node.SetValue(Canvas.LeftProperty, point.X - node.Width / 2);
node.MouseLeftButtonDown += controlReletionshipsLine;
LayoutRoot.Children.Add(node);
}
}
private void controlReletionshipsLine(object sender, MouseButtonEventArgs e)
{
//creating parant element of node
ParentNode parentNode = new ParentNode();
//creating connected element of the node
ConnectedNode connectedNode = new ConnectedNode();
//creating node element
NodePicture node = (NodePicture)sender;
//getting the relative position of the element
Point point = e.GetPosition(this);
You can either divide the object mathematically, using the mouse position "relative to the object" to decide where you clicked, or you can overlay a number of polygons, each with the colour alpha-channel set to 1% (so they can be hit-tested, but are not visible).
As you simply want to see which quarter of the circle you clicked in, call GetPosition on the LeftMouseButtonDown event args, passing the control itself as the parameter. This will give you back a Point object with the position relative to the top left corner of the control.
Then it is just a matter of seeing which quarter it is in:
private void ControlX_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Get the relative position of the element
Point point = e.GetPosition(sender as UIElement);
if (point.X > control.Width/2)
{
if (point.Y > control.Height/2)
{
// You are in the bottom right quarter
}
else
{
// You are in the top right quarter
}
}
else
{
if (point.Y > control.Height/2)
{
// You are in the bottom left quarter
}
else
{
// You are in the top left quarter
}
}
}
In the sample code you sent me (in controlReletionshipsLine) you have:
// getting the relative position of the element
Point point = e.GetPosition(this);
It should have been:
// getting the relative position of the element
Point point = e.GetPosition(sender as UIElement);
Related
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
I have a FlowLayoutPanel which can be scrolled by the user on the verticle axis. i have the following event handler which is used to see where the user has scrolled to and provides the position number within blocks of 405px:
private void ChangedParentFlowPanel_Scroll(object sender, ScrollEventArgs e)
{
int NewPos = e.NewValue;
int range = (NewPos - 1) / 405 + 1;
CurrentIndex_Changed = range;
tCounter.Text = CurrentIndex_Changed.ToString();
}
That works just fine and does exactly what i need when the user scrolls using the verticle bar. The problem i have is i need to update tCounter with the same value but this time when the user scrolls using the mouse wheel. I'Ve tried the following but this only ever seems to provide the Y axis value for the location of the mouse when it scrolls and not the location of the scroll itself:
private void ChangedParentFlowPanel_Wheel(object sender, MouseEventArgs e)
{
int NewPos = e.Location.Y;
MessageBox.Show(NewPos.ToString());
int range = (NewPos - 1) / 405 + 1;
CurrentIndex_Changed = range;
tCounter.Text = CurrentIndex_Changed.ToString();
}
The question is...how can i get the scroll position of the scroll in ChangedParentFlowPanel when a mousewheel is used?
Thanks to the comment by Hans Pasant here's the answer:
private void ChangedParentFlowPanel_Wheel(object sender, MouseEventArgs e)
{
int NewPos = Math.Abs(ChangedParentFlowPanel.AutoScrollPosition.Y);
int range = (NewPos - 1) / 405 + 1;
CurrentIndex_Changed = range;
tCounter.Text = CurrentIndex_Changed.ToString();
}
Math.Abs because the returned scroll Y value is minus and i need a positive value.
I have an X-Y plot in a .NET 4.0 WinForms chart control. I am trying to implement rubber-band selection, so that the user could click and drag the mouse to create a rectangle on the plot, thus selecting all the points that lie within this rectangle.
While I was able to code up the drawing of the rectangle, I am now trying to identify the Datapoints that lie within this rectangle. Here is the relevant code:
public partial class Form1 : Form
{
System.Drawing.Point _fromPosition;
Rectangle _selectionRectangle;
public Form1()
{
InitializeComponent();
}
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
// As the mouse moves, update the dimensions of the rectangle
if (e.Button == MouseButtons.Left)
{
Point p = e.Location;
int x = Math.Min(_fromPosition.X, p.X);
int y = Math.Min(_fromPosition.Y, p.Y);
int w = Math.Abs(p.X - _fromPosition.X);
int h = Math.Abs(p.Y - _fromPosition.Y);
_selectionRectangle = new Rectangle(x, y, w, h);
// Reset Data Point Attributes
foreach (DataPoint point in chart1.Series[0].Points)
{
point.BackSecondaryColor = Color.Black;
point.BackHatchStyle = ChartHatchStyle.None;
point.BorderWidth = 1;
}
this.Invalidate();
}
}
private void chart1_MouseDown(object sender, MouseEventArgs e)
{
// This is the starting position of the rectangle
_fromPosition = e.Location;
}
private void chart1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(new Pen(Color.Blue, 2), _selectionRectangle);
foreach (DataPoint point in chart1.Series[0].Points)
{
// Check if the data point lies within the rectangle
if (_selectionRectangle.Contains(???))))
{
// How do I convert DataPoint into Point?
}
}
}
}
What I am trying to do is query each DataPoint in the series and check if it lies within the Rectangle. Here, I am unable to transform each DataPoint into its corresponding Point. It seems pretty straightforward, so I am either missing something basic here or approaching the problem incorrectly.
I should also add that I referred to similar questions here and here, but they do not talk about how to actually identify DataPoints within the rectangle.
Any direction would be appreciated!
I have shown how to cheat the Chart into helping to get at the coordinates of DataPoints in the Paint event here.
But as you want to pick them up in the Paint event anyway, no cheating is needed..:
I define a List to collect the lassoed DataPoints:
List<DataPoint> dataPoints = new List<DataPoint>();
And I clear it on each new selection:
void chart1_MouseDown(object sender, MouseEventArgs e)
{
_fromPosition = e.Location;
dataPoints.Clear();
}
At the end I can write out the results:
void chart1_MouseUp(object sender, MouseEventArgs e)
{
foreach(DataPoint pt in dataPoints)
Console.WriteLine("found:" + pt.ToString() +
" at " + chart1.Series[0].Points.IndexOf(pt));
}
And in the Paint event we make use of the ValueToPixelPosition method of the two axes:
void chart1_Paint(object sender, PaintEventArgs e)
{
using (Pen pen = new Pen(Color.Blue, 2) // dispose of my Pen
{DashStyle = System.Drawing.Drawing2D.DashStyle.Dot})
e.Graphics.DrawRectangle(pen, _selectionRectangle);
foreach (DataPoint point in chart1.Series[0].Points)
{ // !! officially these functions are only reliable in a paint event!!
double x = chart1.ChartAreas[0].AxisX.ValueToPixelPosition(point.XValue);
double y = chart1.ChartAreas[0].AxisY.ValueToPixelPosition(point.YValues[0]);
PointF pt = new PointF((float)x,(float)y);
// Check if the data point lies within the rectangle
if (_selectionRectangle.Contains(Point.Round(pt)))
{
if (!dataPoints.Contains(point)) dataPoints.Add(point);
}
}
}
Im using winforms and GMap.NET in order to learn how to use it.
I have a mouse click action on the Gmap controller and when the user
clicks on some place on the map i'm getting the x y coordinates,
converting them to latitude and longtitude and then draw the marker
on the map.
But the marker is not placed in the real mouse cursor location,
it looks like the marker has a default place and that's it.
I tried to move the mouse to another place and when I clicked the marker
was also created at wrong place (it was the same as the first marker)
I tried to use gmap.Overlays.clear() before getting the coordinates
and place the marker but this wasn't helpful.
private void gmap_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
double lat = gmap.FromLocalToLatLng(e.X, e.Y).Lat;
double lng = gmap.FromLocalToLatLng(e.X, e.Y).Lng;
GMapOverlay markerOverlay = new GMapOverlay("markers");
GMarkerGoogle marker = new GMarkerGoogle(new
GMap.NET.PointLatLng(lat, lng),
GMarkerGoogleType.green_pushpin);
markerOverlay.Markers.Add(marker);
gmap.Overlays.Add(markerOverlay);
}
}
Add the overlay first, then add the marker. No need to do extra operations.
gmap.Overlays.Add(markerOverlay);
markerOverlay.Markers.Add(marker);
By switching around the statements you'll achieve the right positioning. The guess about a default position is somewhat true, I guess. The overlay has not been "hooked" to the map and gets a marker positioned in it beforehand. That's why the position is usually off initially.
Just use this code:
myMap.UpdateMarkerLocalPosition(marker)
This is how i do it and it works fine. The Obj.defaultOrigin is just LatLong location.
gm = new GoogleMap(Obj.defaultOrigin);
overlay = new GMapOverlay(gm, "mapIcon");
marker = new GoogleMap.GMapMarkerImage(Obj.defaultOrigin, Image.FromFile(Obj.path + #"\resources\images\mapIcon.png"));
overlay.Markers.Add(marker);
gm.Overlays.Add(overlay);
gm.MouseClick += (s, e) =>
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
GMap.NET.PointLatLng point = gm.FromLocalToLatLng(e.X, e.Y);
marker.Position = point;
}
};
You should declare overlay outside mouseclick event:
GMapOverlay markersOverlay = new GMapOverlay("markers");
private void gmap_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
double lat = gmap.FromLocalToLatLng(e.X, e.Y).Lat;
double lng = gmap.FromLocalToLatLng(e.X, e.Y).Lng;
// GMapOverlay markerOverlay = new GMapOverlay("markers"); Your code here
GMarkerGoogle marker = new GMarkerGoogle(new
GMap.NET.PointLatLng(lat, lng),
GMarkerGoogleType.green_pushpin);
gmap.Overlays.Add(markerOverlay); //Change position of this line first
markerOverlay.Markers.Add(marker);
}
}
My task is to draw a graph in chart control using mouse and retrieve the (X,Y) points from the Graph.
I tried of drawing a graph with mouse.
Here is the normal Graph looks like.
After drawing with mouse, it looks like :
The code which i used to draw graph is :
private void Form1_Load(object sender, EventArgs e)
{
chart1.ChartAreas[0].AxisX.Minimum =0170101;
chart1.ChartAreas[0].AxisX.Maximum =0175951;
chart1.ChartAreas[0].AxisY.Minimum=0780101;
chart1.ChartAreas[0].AxisY.Maximum=0785951;
double range = chart1.ChartAreas[0].AxisX.Maximum - chart1.ChartAreas[0].AxisX.Minimum;
chart1.ChartAreas[0].AxisX.Interval = range / 5;
range = chart1.ChartAreas[0].AxisY.Maximum - chart1.ChartAreas[0].AxisY.Minimum;
chart1.ChartAreas[0].AxisY.Interval = range / 5;
}
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
if (!(FirstPoint == null))
{
Graphics g = chart1.CreateGraphics();
Pen ErasePen = new Pen(Color.Transparent);
g.DrawLine(ErasePen, FirstPoint, TempPoint);
TempPoint = new Point(e.X, e.Y);
this.Refresh();
}
}
private void chart1_MouseDown_1(object sender, MouseEventArgs e)
{
FirstPoint = new Point(e.X, e.Y);
TempPoint = new Point(e.X, e.Y);
}
private void chart1_MouseUp_1(object sender, MouseEventArgs e)
{
LineEndPoints Line = new LineEndPoints
{
StartPoint = FirstPoint,
endPont = new Point(e.X, e.Y)
};
LinesList.Add(Line);
// FirstPoint = null;
this.Refresh();
}
private void chart1_Paint_1(object sender, PaintEventArgs e)
{
foreach (LineEndPoints line in LinesList)
{
e.Graphics.DrawLine(Pens.Green, line.StartPoint, line.endPont);
}
if (!(FirstPoint == null))
{
e.Graphics.DrawLine(Pens.Red, FirstPoint, TempPoint);
}
}
When I used to draw a graph it is moving away from the max and min values of the chart control.
Now what I need to know is:
1) My graph should not move away from the X and Y axis points of the chart control.
2) I need to know the X,Y points of the graph which is drawn with respect to chart axis but not with form axis.
I use C# VS 2010 Win-forms.
Chart uses a different coordinate system for its content than its Control surface, ie the mouse loacation; there are conversion functions but they come with a caveat: They are only guaranteed to work in the Paint events..
PixelPositionToValue
ValueToPixelPosition
Here is an example that translates the pixel points to chart point values. You can see the two graphics overlaying very nicely: The DataPoints are connected in blue lines and the pixel points by dotted red lines..:
public Form1()
{
InitializeComponent();
chart1.Series[0].ChartType = SeriesChartType.Line;
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.ChartAreas[0].AxisX.Maximum = 500;
chart1.ChartAreas[0].AxisY.Minimum = 0;
chart1.ChartAreas[0].AxisY.Maximum = 500;
}
List<Point> points = new List<Point>();
private void chart1_MouseClick(object sender, MouseEventArgs e)
{
points.Add(e.Location);
chart1.Invalidate();
}
private void chart1_Paint(object sender, PaintEventArgs e)
{
chart1.Series[0].Points.Clear();
foreach(Point pt in points)
{
double dx = chart1.ChartAreas[0].AxisX.PixelPositionToValue(pt.X);
double dy = chart1.ChartAreas[0].AxisY.PixelPositionToValue(pt.Y);
chart1.Series[0].Points.AddXY(dx, dy);
}
if (points.Count > 1)
using (Pen pen = new Pen(Color.Red, 2.5f))
e.Graphics.DrawLines(pen, points.ToArray());
}
Note that this will always clear the DataPoints and recreate them from the pixel points list, according to the current chart layout using the PixelPositionToValue method. The layout will always change when things like label sizes, other scaling, other minimum/maximum values etc change.
Maybe you really want to work the other way round, that is change the clicked points using the ValueToPixelPosition.
Here is the modified example that keeps the DataPoints and recalculates the pixel points:
List<Point> points = new List<Point>();
Point lastPoint = Point.Empty;
private void chart1_MouseClick(object sender, MouseEventArgs e)
{
lastPoint = e.Location;
chart1.Invalidate();
}
private void chart1_Paint(object sender, PaintEventArgs e)
{
// if we have a new point, convert to DataPoint and add to Series.Points:
if (lastPoint != Point.Empty)
{
double dx = chart1.ChartAreas[0].AxisX.PixelPositionToValue(lastPoint.X);
double dy = chart1.ChartAreas[0].AxisY.PixelPositionToValue(lastPoint.Y);
chart1.Series[0].Points.AddXY(dx, dy);
}
lastPoint = Point.Empty;
// now recalculate all pixel points:
points.Clear();
foreach (DataPoint pt in chart1.Series[0].Points)
{
double x = chart1.ChartAreas[0].AxisX.ValueToPixelPosition(pt.XValue);
double y = chart1.ChartAreas[0].AxisY.ValueToPixelPosition(pt.YValues[0]);
points.Add(new Point((int)x, (int)y));
}
if (points.Count > 1)
using (Pen pen = new Pen(Color.Red, 2.5f))
{
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
e.Graphics.DrawLines(pen, points.ToArray());
}
}
This makes a lot more sense, since the DataPoints are always bound to the chart's scaling, so they are the 'real thing'. When you resize the Chart the DataPoints and the Graphic they make up are scaled as usual and the drawn pixel points follow perfectly:
(When you resize the first version you can see how nothing is being scaled up or down and only the chart's grid lines change..)
Note that I set up a few things to start with, so that not every point I add enforces too many layout changes. Also note that sometimes there still occurs a feedback loop when the new points change e.g. the label sizes, which enforces a layout change and the paint loop.. To fix this you should probably control the labels' formats!
Also note that both conversion methods only work (correctly) in the Paint event(s), probably because only then the current layout is being settled.