I have made a chart on my form.
I want the user to see the value, x_value and y_value of each part in a balloon by clicking on that part.
The ballon shoud disappear when the user moves the mouse.
How can I do that?
You could do something like this:
ToolTip tooltip = new ToolTip();
Point? clickPosition = null;
void chart1_MouseMove(object sender, MouseEventArgs e)
{
if (clickPosition.HasValue && e.Location != clickPosition)
{
tooltip.RemoveAll();
clickPosition = null;
}
}
void chart1_MouseClick(object sender, MouseEventArgs e)
{
var pos = e.Location;
clickPosition = pos;
var results = chart1.HitTest(pos.X, pos.Y, false,
ChartElementType.PlottingArea);
foreach (var result in results)
{
if (result.ChartElementType == ChartElementType.PlottingArea)
{
var xVal = result.ChartArea.AxisX.PixelPositionToValue(pos.X);
var yVal = result.ChartArea.AxisY.PixelPositionToValue(pos.Y);
tooltip.Show("X=" + xVal + ", Y=" + yVal,
this.chart1, e.Location.X,e.Location.Y - 15);
}
}
}
Result:
EDIT :
to show the tooltip whenever the mouse move, you can use the following code:
Point? prevPosition = null;
ToolTip tooltip = new ToolTip();
void chart1_MouseMove(object sender, MouseEventArgs e)
{
var pos = e.Location;
if (prevPosition.HasValue && pos == prevPosition.Value)
return;
tooltip.RemoveAll();
prevPosition = pos;
var results = chart1.HitTest(pos.X, pos.Y, false,
ChartElementType.PlottingArea);
foreach (var result in results)
{
if (result.ChartElementType == ChartElementType.PlottingArea)
{
var xVal = result.ChartArea.AxisX.PixelPositionToValue(pos.X);
var yVal = result.ChartArea.AxisY.PixelPositionToValue(pos.Y);
tooltip.Show("X=" + xVal + ", Y=" + yVal, this.chart1,
pos.X, pos.Y - 15);
}
}
}
Note that this shows the tooltip on any position of the chart. If you want to show it only when the mouse is near to a series point, you can use a mschart functionality e.g. :
yourSeries.ToolTip = "X=#VALX, Y=#VALY";
(further examples here)
Related
I encounter a strange problem. I've got a canvas and drawed a complexe structure:
an Image inside a Grid inside a Border.
My Image is the one which is active for moving.
It works well the first time i drag my structure but the second time nothing works at all no exception but nothing works. It seems to me to be a problem of mouse capture but i can't catch what's about.
Here is my event code :
bool captured = false;
double x_shape, x_canvas, y_shape, y_canvas;
double x_shape_Origine, y_shape_Origine;
Border source = null;
int CountZ = 10;
private void shape_MoveButtonDown(object sender, MouseButtonEventArgs e)
{
/// AWFULLY SOURCE WAS null. I don't understand Why it was working the
/// first time
Mouse.Capture(source);
captured = true;
Image myImage = (Image)sender;
Grid outerGrid = (Grid)myImage.Parent;
source = (Border)outerGrid.Parent;
Canvas.SetZIndex(source, CountZ++);
x_shape = Canvas.GetLeft(source);
y_shape = Canvas.GetTop(source);
x_canvas = e.GetPosition(myCanvas).X;
y_canvas = e.GetPosition(myCanvas).Y;
}
private void shape_MoveMoving(object sender, MouseEventArgs e)
{
if (captured)
{
double x = e.GetPosition(myCanvas).X;
double y = e.GetPosition(myCanvas).Y;
x_shape += x - x_canvas;
Canvas.SetLeft(source, x_shape);
x_canvas = x;
y_shape += y - y_canvas;
Canvas.SetTop(source, y_shape);
y_canvas = y;
}
}
private void shape_MoveButtonUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
captured = false;
}
private void shape_MouseEnter(object sender, MouseEventArgs e)
{
if (!captured)
{
Border inner = (Border)sender;
Grid parentInner = (Grid)inner.Parent;
parentInner.Children[0].Visibility = Visibility.Visible;
parentInner.Children[2].Visibility = Visibility.Visible;
parentInner.Children[5].Visibility = Visibility.Visible;
parentInner.Children[6].Visibility = Visibility.Visible;
parentInner.Children[8].Visibility = Visibility.Visible;
parentInner.Background = new SolidColorBrush(Colors.Red);
}
}
private void shape_MouseLeave(object sender, MouseEventArgs e)
{
if (!captured)
{
Grid outer = (Grid)sender;
outer.Children[0].Visibility = Visibility.Hidden;
outer.Children[2].Visibility = Visibility.Hidden;
outer.Children[5].Visibility = Visibility.Hidden;
outer.Children[6].Visibility = Visibility.Hidden;
outer.Children[8].Visibility = Visibility.Hidden;
outer.Background = null;
}
}
Hope it will make sense for you
I had a complete sample for D&D with WPF and Silverlight. Here full code, hope it helps.
class MyWnd : Window
{
public MyWnd()
{
var c = new Canvas();
c.Background = new SolidColorBrush(Colors.White);
var rect = new Rectangle { Fill = new SolidColorBrush(Colors.Red), Width = 20, Height = 20 };
c.Children.Add(rect);
this.Content = c;
Canvas.SetLeft(rect, 0);
Canvas.SetTop(rect, 0);
rect.MouseLeftButtonDown+=Handle_MouseDown;
rect.MouseLeftButtonUp+=Handle_MouseUp;
rect.MouseMove+=Handle_MouseMove;
}
bool isMouseCaptured;
double mouseVerticalPosition;
double mouseHorizontalPosition;
public void Handle_MouseDown(object sender, MouseEventArgs args)
{
var item = sender as FrameworkElement;
mouseVerticalPosition = args.GetPosition(null).Y;
mouseHorizontalPosition = args.GetPosition(null).X;
isMouseCaptured = true;
item.CaptureMouse();
}
public void Handle_MouseMove(object sender, MouseEventArgs args)
{
var item = sender as FrameworkElement;
if (isMouseCaptured)
{
// Calculate the current position of the object.
double deltaV = args.GetPosition(null).Y - mouseVerticalPosition;
double deltaH = args.GetPosition(null).X - mouseHorizontalPosition;
double newTop = deltaV + (double)item.GetValue(Canvas.TopProperty);
double newLeft = deltaH + (double)item.GetValue(Canvas.LeftProperty);
// Set new position of object.
item.SetValue(Canvas.TopProperty, newTop);
item.SetValue(Canvas.LeftProperty, newLeft);
// Update position global variables.
mouseVerticalPosition = args.GetPosition(null).Y;
mouseHorizontalPosition = args.GetPosition(null).X;
}
}
public void Handle_MouseUp(object sender, MouseEventArgs args)
{
var item = sender as FrameworkElement;
isMouseCaptured = false;
item.ReleaseMouseCapture();
mouseVerticalPosition = -1;
mouseHorizontalPosition = -1;
}
}
void Main()
{
var wnd = new MyWnd();
wnd.ShowDialog();
}
I have a double buffered panel which has a background image. Now when I draw line on panel its good but when I move that line in panel area it takes a snapshot or background with it where it was first located. I thought double buffered panel will solve this but its not working and I also try to add refresh panel code in mouse down event but then line constantly flickers so please guys help me.
public void LineMouseDown(object sender, MouseEventArgs e)
{
var l = (Line)sender;
if (GetDistance(e.X, e.Y, l.StartPoint.X, l.StartPoint.Y) < 30 ||
GetDistance(e.X, e.Y, l.EndPoint.X, l.EndPoint.Y) < 30)
{
_rotating = true;
}
else
{
_dragging = true;
panel5.Refresh();
}
_clickX = e.X;
_clickY = e.Y;
panel5.Refresh();
_clickCoords = new Point(l.Left + e.X, l.Top + e.Y);
UpdateCircle(l);
UpdateMiddle(l);
}
public void LineMouseUp(object sender, MouseEventArgs e)
{
_rotating = false;
_dragging = false;
panel5.Refresh();
}
public void LineMouseMove(object sender, MouseEventArgs e)
{
var l = (Line)sender;
if (_rotating)
{
if ((DateTime.Now - lastRotate).TotalMilliseconds > 60)
{
try
{
var angle = GetAngle(l.Left + e.X, l.Top + e.Y, _centerX, 0, _centerX, _centerY);
var newStartPoint = new Point(
(int)Math.Round(_middleX + _radius * Math.Sin(angle)),
(int)Math.Round(_middleY + _radius * Math.Cos(angle))
);
var newEndPoint = new Point(2 * _middleX - newStartPoint.X, 2 * _middleY - newStartPoint.Y);
l.SetPoints(newStartPoint, newEndPoint);
UpdateMiddle(l);
lastRotate = DateTime.Now;
}
catch
{
//ignored
}
}
}
else if (_dragging)
{
l.Left = l.Left + e.X - _clickX;
l.Top = l.Top + e.Y - _clickY;
}
}
Here what it looks like when I move line
public class DoubleBufferPanel : Panel
{
public DoubleBufferPanel()
{
// Set the value of the double-buffering style bits to true.
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw , true);
this.UpdateStyles();
}
}
I am currently attempting to show the x,y values whenever I mouse over a point on the chart but for the x axis is in a date/time format, and I want to display the date/time instead of the actual pixel value.
What I am currently using is this following code for the mouse over event
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
var pos = e.Location;
if (prevPosition.HasValue && pos == prevPosition.Value)
return;
tooltip.RemoveAll();
prevPosition = pos;
var results = chart1.HitTest(pos.X, pos.Y, false,
ChartElementType.DataPoint);
foreach (var result in results)
{
if (result.ChartElementType == ChartElementType.DataPoint)
{
var prop = result.Object as DataPoint;
if (prop != null)
{
var pointXPixel = result.ChartArea.AxisX.ValueToPixelPosition(prop.XValue);
var pointYPixel = result.ChartArea.AxisY.ValueToPixelPosition(prop.YValues[0]);
// check if the cursor is really close to the point (2 pixels around the point)
if (Math.Abs(pos.X - pointXPixel) < 2 &&
Math.Abs(pos.Y - pointYPixel) < 2)
{
tooltip.Show("X=" + prop.XValue + ", Y=" + prop.YValues[0], this.chart1,
pos.X, pos.Y - 15);
}
}
}
}
}
In terms of the formatting of the x axis goes, I have this
chart1.ChartAreas["ChartArea1"].AxisX.LabelStyle.Format = "MMM.dd.yyyy HH:mm:ss";
chart1.Series["Series1"].XValueType = ChartValueType.DateTime;
I was wondering if there was a simple way to convert the point into a date/time value.
Thank you
I have a mainPicture box that contains Two picture boxes (_pic1 , _pic2) .
I can drag _pic1 and drag _pic2 too.
But I want to when I do mouse down on intersection of two picture boxes, I could drag two lines together.
So I should get intersection position . by below code I could not.
_pic2.MouseUp += new MouseEventHandler(_pic1_MouseUp);
_pic2.MouseDown += new MouseEventHandler(_pic1_MouseDown);
Point p = new Point();
bool interSection;
private void _pic1_MouseDown(object sender, MouseEventArgs e)
{
p = e.Location;
dragging = true;
dragPoint = new Point(e.X, e.Y);
this.Cursor = Cursors.SizeAll;
Rectangle p1 = this._pic1.ClientRectangle;
p1.Offset(this._pic1.Location);
Rectangle p2 = this._pic2.ClientRectangle;
p2.Offset(this._pic2.Location);
//bool z = p1.Contains(p) it returns false
//bool zz = p2.Contains(p) it returns false too
if (p1.Contains(p) && p2.Contains(p))
{
interSection = true;
}
}
private void _pic_MouseMove(object sender, MouseEventArgs e)
{
if (interSection)
{
//drag two lines together
_pic1.Location = new Point(_pic1.Location.X + e.X - dragPoint.X, _pic1.Location.Y + e.Y - dragPoint.Y);
_pic2.Location = new Point(_pic2.Location.X + e.X - dragPoint.X, _pic2.Location.Y + e.Y - dragPoint.Y);
return;
}
if (dragging)
{
_pic_1.Location = new Point(_pic1.Location.X + e.X - dragPoint.X, _pic1.Location.Y + e.Y - dragPoint.Y);
}
}
private void _pic1_MouseUp(object sender, MouseEventArgs e)
{
dragging = false;
this.Cursor = Cursors.Default;
}
private void _pic2_MouseMove(object sender, MouseEventArgs e)
{
if (dragging)
{
_pic2.Location = new Point(_pic2.Location.X + e.X - dragPoint.X, _pic2.Location.Y + e.Y - dragPoint.Y);
}
}
image :
http://tinypic.com/view.php?pic=ix8bab&s=8
You can test two Rectangles for Intersection like this:
if (_pic1.Bounds.IntersectsWith(_pic2.Bounds) ) // do stuff
And you can get the intersection like this:
Rectangle R = _pic1.Bounds;
R.Intersect(_pic2.Bounds);
Now you can test it again:
if (R != Rectangle.Empty)
Or find the Center:
Point center = new Point(R.X + R.Width / 2, R.Y + R.Height / 2);
Or test whether the Mouse was clicked on the intersection:
if (R.Contains(e.Location) // ..
I have a chart and I want the user to see the values when the pointer is on the points.
By using digEmAll's help in the page finding the value of the points in a chart ,I could write the following code:
Point? prevPosition = null;
ToolTip tooltip = new ToolTip();
void chart1_MouseMove(object sender, MouseEventArgs e)
{
var pos = e.Location;
if (prevPosition.HasValue && pos == prevPosition.Value)
return;
tooltip.RemoveAll();
prevPosition = pos;
var results = chart1.HitTest(pos.X, pos.Y, false, ChartElementType.PlottingArea);
foreach (var result in results)
{
if (result.ChartElementType == ChartElementType.PlottingArea)
{
chart1.Series[0].ToolTip = "X=#VALX, Y=#VALY";
}
}
}
by the above code,the user can see the values when the pointer is near to a series.But now How can I let the user to see the values only when the pointer is on the points?
I replaced
int k = result.PointIndex;
if (k >= 0)
{
chart1.Series[0].Points[k].ToolTip = "X=#VALX, Y=#VALY";
}
instead of
chart1.Series[0].ToolTip = "X=#VALX, Y=#VALY";
to solve my problem.But It wasn't usefull.
You should modify the code in this way:
Point? prevPosition = null;
ToolTip tooltip = new ToolTip();
void chart1_MouseMove(object sender, MouseEventArgs e)
{
var pos = e.Location;
if (prevPosition.HasValue && pos == prevPosition.Value)
return;
tooltip.RemoveAll();
prevPosition = pos;
var results = chart1.HitTest(pos.X, pos.Y, false,
ChartElementType.DataPoint);
foreach (var result in results)
{
if (result.ChartElementType == ChartElementType.DataPoint)
{
var prop = result.Object as DataPoint;
if (prop != null)
{
var pointXPixel = result.ChartArea.AxisX.ValueToPixelPosition(prop.XValue);
var pointYPixel = result.ChartArea.AxisY.ValueToPixelPosition(prop.YValues[0]);
// check if the cursor is really close to the point (2 pixels around the point)
if (Math.Abs(pos.X - pointXPixel) < 2 &&
Math.Abs(pos.Y - pointYPixel) < 2)
{
tooltip.Show("X=" + prop.XValue + ", Y=" + prop.YValues[0], this.chart1,
pos.X, pos.Y - 15);
}
}
}
}
}
The idea is to check if the mouse is very close to the point e.g. 2 pixels around it (because is really unlikely to be exactly on the point) and show the tooltip in that case.
Here's a complete working example.
I would take this solution:
Add custom tooltip event handler:
this.chart1.GetToolTipText += this.chart1_GetToolTipText;
Implement event handler:
private void chart1_GetToolTipText(object sender, ToolTipEventArgs e)
{
// Check selected chart element and set tooltip text for it
switch (e.HitTestResult.ChartElementType)
{
case ChartElementType.DataPoint:
var dataPoint = e.HitTestResult.Series.Points[e.HitTestResult.PointIndex];
e.Text = string.Format("X:\t{0}\nY:\t{1}", dataPoint.XValue, dataPoint.YValues[0]);
break;
}
}
Consider the following as a possible better option than tooltips...use the label feature of the chart control.
DataPoint _prevPoint;
void chart1_MouseMove(object sender, MouseEventArgs e)
{
// this if statement clears the values from the previously activated point.
if (_prevPoint) {
_prevPoint.MarkerStyle = MarkerStyle.None;
_prevPoint.IsValueShownAsLabel = false;
}
var result = chart1.HitTest(e.X, e.Y, ChartElementType.DataPoint);
if (result.ChartElementType == ChartElementType.DataPoint)
{
var prop = result.Object as DataPoint;
if (prop != null)
{
prop.IsValueShownAsLabel = true;
prop.MarkerStyle = MarkerStyle.Star4;
}
}
}
I've tested this and i'm using it currently. It's very nice on charts with a lot of points since it shows the marker on the chart as well.