GMap - cannot detect clicking on polygon - c#

IsMouseOverMarker property detects clicking on marker just fine, but when trying to use IsMouseOverPolygon property of GMap Control to detect if user clicked on polygon line - it doesn't seem to be working.
Note: PolygonEnabled property of GMap control is set to True.
The OnPolygonClick event doesn't even fire:
private void gMap_OnPolygonClick(GMapPolygon item, MouseEventArgs e) {
double pLat = item.From.Value.Lat;
}
Map Click event does fire, but the 'IsMouseOverPolygon` never gets True value:
private void gMap_Click(object sender, EventArgs e) {
if (gMap.IsMouseOverMarker) {
MessageBox.Show("Clicked on marker and it works!");
}
if (gMap.IsMouseOverPolygon) {
MessageBox.Show("clicked on line - never works");
}
}
I wonder if there is something wrong in a way I'm adding polygons or is it because in my case it's just lines:
GMapOverlay polyOverlay = new GMapOverlay("polygons");
gMap.Overlays.Add(polyOverlay);
List<PointLatLng> points = new List<PointLatLng>();
points.Add(start);
points.Add(end);
polygon = new GMapPolygon(points, "mypolygon");
polygon.Stroke = new Pen(Color.Blue, 5);
polyOverlay.Polygons.Add(polygon);
So, the question is: how should I go about detecting mouse click on those lines?

I can see two issues within the code. First you need to explicitely define the polygon as HitTestVisible:
polygon.IsHitTestVisible = true;
Second, to set up a polygon add at least three points that are not aligned and actually spawn an area. I've found that the click will only be noticed on an actual area, where in theory a polygon can consist of two points.
With the hints above the check for gMap.IsMouseOverPolygon should return true then.

Related

Drawing multiple rectangles chokes my WPF app

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

Zedgraph drawing a line with the mouse

I wrote a code to draw a line using the mouse.
On mouse down i save where the user clicked.
bool mZgc_MouseDownEvent(ZedGraphControl sender, MouseEventArgs e)
{
GraphPane graphPane = mZgc.GraphPane;
graphPane.ReverseTransform(e.Location, out mMouseDownX, out mMouseDownY);
return false;
}
On mouse up i draw the line:
bool zgc_MouseUpEvent(ZedGraphControl sender, MouseEventArgs e)
{
GraphPane graphPane = mZgc.GraphPane;
double x, y;
graphPane.ReverseTransform(e.Location, out x, out y);
LineObj threshHoldLine = new LineObj(Color.Red, mMouseDownX, mMouseDownY, x, y);
graphPane.GraphObjList.Add(threshHoldLine);
mZgc.Refresh();
return false;
}
The problem is that while the mouse is down, the user don't see the line (because i draw it only on "up" event).
How can i solve it ?
Technically I can use "on hover" and draw/remove the line from the graph each second and refresh the graph, but it's a bit crazy.
Is there a "normal" way to do this ?
Thanks
Ok, I've solved the problem I'll post the answer for future generations.
First of all we need to make a minor change in the zedgraph code to allow ourselves to change lines after they created, It probably breaks some "immutable" paradigm that the creators are trying to achieve, but if you want to avoid creating and deleting lines every time the mouse is moving that's the way.
In the file Location.cs edit the X2,Y2 properties (set was missing):
public double X2
{
get { return _x+_width; }
set { _width = value-_x; }
}
public double Y2
{
get { return _y+_height; }
set { _height = value-_y; }
}
from here it is easy, i won't post all the code but will explain the steps:
Add a member to your class : private LineObj mCurrentLine;
On mouse down create a line mCurrentLine = new LineObj(Color.Red, mMouseDownX, mMouseDownY, mMouseDownX, mMouseDownY);
On mouse move change the line X2,Y2 coordinates mCurrentLine.Location.X2 = x;
On mouse up just stop that drawing process (to avoid changing the line in "on mouse move"
If someone actually going to use it, and needs better explanation, just comment.

Getting a line that has the coordinates defined by the mouse location

I'm trying to make a little graphics program that has a circle of diameter 100 on the screen and from the center of it, a line is coming out of it that is always attached to the mouse pointer until such time that the user does a click, and then the line is permanently drawn. It's exactly like MSPaint's line, except that starting point is always the center of the circle.
I tried a few things that DON'T work.
I can get the line to appear only after a mouse-click. That's not what I want. I want the line to always be present and pivoting from the circle-center until the mouse is clicked and then it's then permanently on the screen.
I can get a smeary thing where the line is always being drawn. It makes a sort of star shape, but that's not what I want either.
Basically, I want the same functionality that you have in MSPaint when you draw a line. What am I supposed to do? Draw the line and then erase it a second later, and then draw it again when the mouse is in a new position? I tried something like that, but it does a thing where it erases the background a little bit, and then the line is only drawn when the mouse is in motion, but not when the mouse is stationary.
If anyone can provide a code snippet, that'd be great. Or just some pseudo-code.
Is this the right pseudo code?
Start:
Left click and a line appears from center of circle to mouse tip
Line stays there until a new mouse coordinate is made (how do I keep track)?
Line from center of circle to original location gets erased
New line is made to new location of mouse coordinates.
I think this something of a state-machine to use what I learned in digital class. How are states implemented in C#?
Any help would be appreciated, and thanks to everyone that can understand my question even though I'm probably not using the proper terminology.
So short answer is you will need some custom painting. The longer answer involves custom drawing, and event handling.
The other piece of code you need is a list of some sort to hold all of the lines. The code below creates a user control and does the custom painting without relying on a state machine. To test it, create a new project add a user control called UserControl1, and add it to a form. Make sure you tie into the listed events.
I tried to comment the relevant sections and this shows a quick and dirty way to do what you appear to be trying to do.
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace CustomDrawingAndEvents
{
public partial class UserControl1 : UserControl
{
private struct MyLine
{
public Point mStart;
public Point mEnd;
public MyLine(Point xStart, Point xEnd)
{
mStart = xStart;
mEnd = xEnd;
}
}
private List<MyLine> mLines;
private Point mCircleCenter;
private Point mMousePosition;
public UserControl1()
{
InitializeComponent();
mLines = new List<MyLine>();
//Double Buffer to prevent flicker
DoubleBuffered = true;
//Create the center for our circle. For this just put it in the center of
//the control.
mCircleCenter = new Point(this.Width / 2, this.Height / 2);
}
private void UserControl1_MouseClick(object sender, MouseEventArgs e)
{
//User clicked create a new line to add to the list.
mLines.Add(new MyLine(mCircleCenter, e.Location));
}
private void UserControl1_MouseMove(object sender, MouseEventArgs e)
{
//Update mouse position
mMousePosition = e.Location;
//Make the control redraw itself
Invalidate();
}
private void UserControl1_Paint(object sender, PaintEventArgs e)
{
//Create the rect with 100 width/height (subtract half the diameter to center the rect over the circle)
Rectangle lCenterRect = new Rectangle(mCircleCenter.X - 50, mCircleCenter.Y - 50, 100, 100);
//Draw our circle in the center of the control with a diameter of 100
e.Graphics.DrawEllipse(new Pen(Brushes.Black), lCenterRect);
//Draw all of our saved lines
foreach (MyLine lLine in mLines)
e.Graphics.DrawLine(new Pen(Brushes.Red), lLine.mStart, lLine.mEnd);
//Draw our active line from the center of the circle to
//our mouse location
e.Graphics.DrawLine(new Pen(Brushes.Blue), mCircleCenter, mMousePosition);
}
}
}

get cursor position

I have an usercontrol called TaskControl and a button for creating other usercontrols by dragging. I want the new user control that appears to be at the same coordinates where my cursor is. Below it is my code. It doesn't want to appear at those coordinates and the new usercontrol appears behind the old one.
My code:
private void button1_Click(object sender, EventArgs e)
{
Point localCoordinates = this.PointToClient(Cursor.Position);
TaskControl t = new TaskControl();
t.Location = new Point(Cursor.Position.X,Cursor.Position.Y);
t.MouseDown += new MouseEventHandler(t_MouseDown);
t.MouseMove += new MouseEventHandler(t_MouseMove);
t.MouseUp += new MouseEventHandler(t_MouseUp);
this.Controls.Add(t);
}
You have to work out that using Control.MousePosition static property, which
Gets the position of the mouse cursor in screen coordinates.
After move your use control to the coordinates retrived. Please note, that depends on how you architect your UI, you may need to convert coordinates to client. For this can use
Control.PointToClient static method, which:
Computes the location of the specified screen point into client
coordinates.
Take a look Control.MousePosition
Gets the position of the mouse cursor in screen coordinates.

WPF Render Transform Behaving Weird

I am experiencing a weird problem with a render transform in WPF. The project I'm working on needs to display a clicked user point over an image. When the user clicks a point, a custom control is placed at the location of their click. The image should then be able to be scaled around any point using the mouse wheel, and the custom control should be translated (not scaled) to the correct location.
To do this, I follow the MouseWheel event as follows:
private void MapPositioner_MouseWheel(object sender, MouseWheelEventArgs e)
{
Point location = Mouse.GetPosition(MainWindow.Instance.imageMap);
MainWindow.Instance.imageMap.RenderTransform = null;
ScaleTransform st = new ScaleTransform(scale + (e.Delta < 0 ? -0.2 : 0.2), scale += (e.Delta < 0 ? -0.2 : 0.2));
st.CenterX = location.X;
st.CenterY = location.Y;
TransformGroup tg = new TransformGroup();
tg.Children.Add(st);
//tg.Children.Add(tt);
MainWindow.Instance.imageMap.RenderTransform = tg;
if (scale <= 1)
{
MainWindow.Instance.imageMap.RenderTransform = null;
}
if (TransformationChanged != null)
TransformationChanged();
}
Then, I implemented an event handler in the custom control for the TransformationChanged event seen at the end of the above code block as follows:
private void Instance_TransformationChanged()
{
//check image coords
//
if (MainWindow.Instance.imageMap.RenderTransform != null)
{
if (MainWindow.Instance.imageMap.RenderTransform != Transform.Identity)
{
Transform st = MainWindow.Instance.imageMap.RenderTransform;
Point image = MainWindow.VideoOverlayCanvas.TransformToVisual(MainWindow.Instance.MapImage).Transform(loc2);
Point trans = st.Transform(image);
Point final = MainWindow.Instance.MapImage.TransformToVisual(MainWindow.VideoOverlayCanvas).Transform(trans);
// selected = anchor2;
// final = ClipToOverlay(final);
// selected = null;
connector.X2 = final.X;
connector.Y2 = final.Y;
Canvas.SetLeft(anchor2, final.X);
Canvas.SetTop(anchor2, final.Y);
}
}
else
{
connector.X2 = loc2.X;
connector.Y2 = loc2.Y;
Canvas.SetLeft(anchor2, loc2.X);
Canvas.SetTop(anchor2, loc2.Y);
}
}
This way, I can ensure that the custom control's position is updated only after the new transform is set. Note that since I am applying the transform to the point, there is no scaling done to the control, the effect is that it is translated to the point it should. This works fine as long as the user is only scaling around one point. If they change that point, it doesnt work.
Here are some images that show the problem:
User clicks a point
user zooms out, what happened here?
after zooming out (all the way out in this case) it looks ok
I've been messing with this for about two days now, so I apologize if my code looks messy. I know this is a pretty obscure question so any help would be appreciated.
Thanks,
Max
If anyone is looking for an answer to this, because of deadlines, I had to write a workaround by having the user pan with the right mouse button and zoom with the mouse wheel. This way zooming always happens around the center of the image, so the controls are always lined up. I'm still looking for answers to the original question though if anyone can figure it out
Thanks,
Max
I'm not sure what's wrong with your transform, but have you considered an alternate approach? For example, you might want to add a transparent canvas set to stay at the same size as the image, z-order above the image (explicitly set or just put the Canvas element just after the image element). Then you can just use Canvas.SetLeft and Canvas.SetTop to place the user control where the user clicked, and to move it around. A lot easier than using a transform.

Categories

Resources