EDIT: For new programmers to OOP just calling the class isn't enough if the syntax is looking for a specific variable type it will throw an error. This was the problem as pointed at the answers bellow, this line of code:
System.Windows.Controls.Canvas.SetLeft(Gate_list[Gate_list.Count - 1], Pos.X);
It has one fatal mistake and that is that the Canvas.SetLeft is looking for a canvas child class (in this case a rectangle) and a point. However I sent in a Class type Gate_list[Gate_list.Count - 1] when it should've been Gate_list[Gate_list.Count - 1].GetRect()
End of edit
I have a delegate that is calling a class in a method. The delegate is detecting a mouse down event on a Rectangle(Here is how it's done). In the method I'm trying to SetLeft on a Rectangle I just added to the Canvas but get the error CS1503.
I've tried converting it to System.Windows.UIElement but System can't be converted.
public partial class Program
{
public void Rect_Button_MouseDown(MainWindow MainWind, string Tag)
{
Point Pos = new Point();
Pos = System.Windows.Input.Mouse.GetPosition(MainWind.Main_Canvas);
if (Drag == false)
{
Drag = true;
Gate_list.Add(new Gate_Class(Convert.ToInt32(Tag),new Rectangle()));
MainWind.Main_Canvas.Children.Add(Gate_list[Gate_list.Count-1].Get_Rect());
System.Windows.Controls.Canvas.SetLeft(Gate_list[Gate_list.Count - 1], Pos.X);
}
}
}
I believe there should be an away to transfer system.windows but I don't know.
My question comes down to finding a way to convert Gate_list[] to UIElement.
Gate_Class is apparently not a UIElement. It should have a Rectangle property that returns the Rectangle that you pass to its constructor. You can then set the Canvas.Left property of the Rectangle:
System.Windows.Controls.Canvas.SetLeft(Gate_list[Gate_list.Count - 1].Rectangle, Pos.X);
public class Gate_Class
{
public Gate_Class(int tag, Rectangle rectangle)
{
//...
Rectangle = rectangle;
}
public Rectangle Rectangle { get; }
}
I think in last line of your code you are providing Gate_list[Gate_list.Count - 1] but this is your custom class and not the Rectangle you just created. I can deduce from your code that you can get the Rectangle by using Gate_list[Gate_list.Count - 1].Get_Rect().
In other words it seems to me that you need to add .Get_Rect() to actually get the rectangle.
If this doesn't work, please provide code of your Gate_Class and the error message you are getting.
Related
I'm creating a Graphical Editor. I'm able to draw lines and rectangles but now I want to move them, so I am trying to add the MouseMove event now. I tried the following things:
rectangle.MouseMove += shape_MouseMove;
Error:
'System.Drawing.Rectangle' does not contain a definition for 'MouseDown' and no extension method 'MouseDown' accepting a first argument of type 'System.Drawing.Rectangle' could be found (are you missing a using directive or an assembly reference?)
rectangle += shape_MouseMove;
Errors:
Error 2 Cannot convert method group 'shape_MouseMove' to non-delegate type 'System.Drawing.Rectangle'. Did you intend to invoke the method
Error 1 Operator '+=' cannot be applied to operands of type 'System.Drawing.Rectangle' and 'method group'
Code:
private void shape_MouseMove(object sender, MouseEventArgs e)
{
}
private void panel_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
xe = e.X;
ye = e.Y;
Item item;
Enum.TryParse<Item>(menuComboBoxShape.ComboBox.SelectedValue.ToString(), out item);
switch (item)
{
case Item.Pencil:
using (Graphics g = panel.CreateGraphics())
using (var pen = new Pen(System.Drawing.Color.Black)) //Create the pen used to draw the line (using statement makes sure the pen is disposed)
{
g.DrawLine(pen, new Point(x, y), new Point(xe, ye));
}
break;
case Item.Rectangle:
Rectangle rectangle = new Rectangle(x, y,xe-x, ye-y);
rectangle += shape_MouseMove; //Error here
using (Graphics g = panel.CreateGraphics())
using (var pen = new Pen(System.Drawing.Color.Black)) //Create the pen used to draw the rectangle (using statement makes sure the pen is disposed)
{
g.DrawRectangle(pen,rectangle);
}
break;
default:
break;
}
}
How can I add the MouseMove event to the Rectangle?
You can't solve your problem as it stands.
Rectangle is just a structure, intended to describe some region on the screen. To avoid problems with manual mouse/keyboard handling, you need to wrap shapes into UserControls, and implement shape-specific painting.
This also will use OOP benefits. Instead of switch/case you will get a set of shape types, and every type will be responsible to draw its instances:
public partial class RectangularShape : UserControl
{
public RectangularShape()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(Brushes.Red, ClientRectangle);
}
}
simple as it is ... you can't
you can however create a subclass of Control or UserControl, and create your own type of rectangle with all that fancy UI support...
You should create a class Shape with all the info needed to draw itself.
Then you should have a List<Shape> and use the Paint event of the Panel to draw all the Shapes.
Using Controls, no matter which, will always run into the tranparency problems inherent to Winforms GDI+ drawing. This means that overlapping controls will not be able to fake transparency well.. Real transparency between controls is not possible at all and faked transparency only works between nested controls.
The Shape class would contain fields for its types, the location and size, colors and penstyle, text and font and maybe many more things your various shapes need to know for drawing themselves.
To edit, change, delete those shapes you will need to process the shapes list and upon MouseDown find the one that was hit; then you can follow it up with MouseMove or enter changing values for the other properties..
How to do that precisely is always a matter of taste; commercial programs have rather different methods to resolve stacking conflicts: Some pick a shape when you click near its border, other cycle though overlapping shapes with each click..
You should also plan for ways to change the z-order of the shapes..
Have fun!
I'm experiencing a discrepancy between a GraphicsPath drawn in World coordinates on a UserControl and the results of GraphicsPath.IsVisible() to Hit Test the shape with the mouse.
I performed a little test that made a map of where IsVisible() returned true, relative to the GraphicsPath shape that was drawn. The results show a very "low resolution" version of the shape I'm drawing.
Link to shared Google Drive image showing the results:
http://goo.gl/zd6xiM
Is there something I'm doing or not doing correctly that's causing this?
Thanks!
Here's the majority of my OnMouseMove() event handler:
protected override void OnMouseMove(MouseEventArgs e)
{
//base.OnMouseMove(e);
debugPixel = Point.Empty;
PointF worldPosition = ScreenToWorld(PointToClient(Cursor.Position));
if (_mouseStart == Point.Empty) // Just moving mouse around, no buttons pressed
{
_objectUnderMouse = null;
// Hit test mouse position against each canvas object to see if we're overtop of anything
for (int index = 0; index < _canvasObjects.Count; index++) // Uses front to back order
{
NPCanvasObject canvasObject = _canvasObjects[index];
if (canvasObject is NPCanvasPart)
{
NPCanvasPart canvasPart = (canvasObject as NPCanvasPart);
NPPart part = canvasPart.Part;
GraphicsPath gp = canvasPart.GraphicsPath;
// Set the object under the mouse cursor, and move it to the "front" so it draws on top of everythign else
if (gp.IsVisible(worldPosition))
{
// DEBUG
debugPixel.X = e.X;
debugPixel.Y = e.Y;
_objectUnderMouse = canvasObject;
_canvasObjects.MoveItemAtIndexToFront(_canvasObjects.IndexOf(canvasObject));
break; // Since we're modifying the collection we're iterating through, we can't reliably continue past this point
}
}
}
}
else
{
...
}
}
Later in my drawing code I draw a pixel whenever debugPixel != Point.Empty . I temporarily suppressed clearing before drawing so I could see them all.
Some other info that may be asked, or could be helpful to troubleshoot:
I've tried different Graphics.InterpolationMode settings but that doesn't seem to have any effect
I've applied a TranslateTransform and ScaleTransform to the main drawing Graphics but the underlying HitTest map seems to scale and translate equal to the GraphicsPath
For my main drawing canvas, Graphics.PageUnit = GraphicsUnit.Inch, except when I'm doing pixel-based overlay stuff
I thought I had researched this thoroughly enough, but apparently not. Shortly after posting this question I did another search with slightly different terms and found this:
http://vbcity.com/forums/t/72877.aspx
...which was enough to clue me in that the GraphicsPath and my main drawing Graphics were not the same. Using the overloaded GraphicsPath.IsVisible(PointF, Graphics) solved this problem very nicely.
Essentially it was trying to check against a very aliased (pixelated) version of my shape that had been scaled to the same size but not smoothed.
I have this problem, that I want to be able to click on a "tile" on the screen and then a pop-up menu should be shown just next to the tile. I can click on the tile and then a pop-up menu shows up but not where I want it.
On the picture here I've clicked on the top left one.
My code for placing the picture is as following:
using UnityEngine;
using System.Collections;
public class TowerMenu : MonoBehaviour
{
bool showMenu = false;
float x;
float y;
GUIStyle myStyle;
public Texture2D[] towers;
void OnGUI()
{
if(showMenu)
{
//Bear tower
GUI.Button(new Rect(x + 10, y - 25, 50, 50), towers[0]);
//Seal tower
GUI.Button(new Rect(x + 10, y + 25, 50, 50), towers[1]);
}
}
public void ShowMenu(Vector2 pos)
{
showMenu = true;
x = pos.x;
y = pos.y;
}
}
Hope anyone can help me :)
Sry, i cant comment because i dont have enough rep, this is a comment to Steven Mills answer and comments to that post.
The first error comes because you are calling WorldToViewportPoint as if it was a static member function which it isnt(Think of if you had 2 Cameras you would have to specify which Camera you want, reading up on what a static member is would be helpful here). What you need to do to fix this is get a reference of your MainCamera and call the function from that instance(best method would probably be with a public variable and dragging the camera on the script in the editor)
The second error occurs because you are trying to give a Vector3 to ShowMenu() which requires a Vector2. The third is probably a product of the compiler trying to fix error 2
This is a logical error because the tiles are GameObjects and thus the transform.position are positions in 3d space. What you actually want is the 2d-pixel-position on the screen of your MainCamera. To get this you need to call WorldToScreenPoint instead of WorldToViewportPoint. Sadly, as you will notice you will also get a Vector3 here which is not what you want, but you can just take the x and y coordinates as your pixel screen coordinates. the z-coordinate denotes the distance from the camera.
Hope that clears it up a little instead of confusing you ;D
Feel free to ask again, but also try to read the Unity Script Reference and try to understand what is written there and what it means :)
By the look of it, your ShowMenu method is receiving a pos of (0,0), which is why the two buttons are placed at what seems to be a position of (10,-25) and (10,25) respectively.
Without seeing the code calling ShowMenu I can't be sure what location you're giving, but my guess would be that the tiles belong to a parent object, and you're passing the local position instead of the world position.
If you post the code in which you call ShowMenu I may be able to point out any problems.
EDIT:
Based on the information provided in the comments, the problem is that the position needs converting between the world coordinates and screen coordinates:
void OnMouseDown()
{
if(state == State.water)
{
errorHandler.sendError("You can't click on that");
}
if(state == State.ice)
{
towerMenu.ShowMenu(camera.WorldToViewportPoint(this.transform.position));
}
}
and change the ShowMenu to this:
public void ShowMenu(Vector3 pos)
{
showMenu = true;
x = pos.x;
y = pos.y;
}
I'm trying to figure out which of the passed in array of CustomPopupPlacement positions have been used when the popup actually renders. Is there any event to detect this?
This msdn thread from 2009 seems to be exactly my issue however there does not seem to be an answer for it.
http://social.msdn.microsoft.com/Forums/da/wpf/thread/4c6d216a-0011-4202-aa7e-2fccef3cc355
The marked answer seems invalid and my situation is exactly as the OP in the thread.
I'm going to have my popup with 4 paths and use a DP to toggle visibility on three paths to choose the correct arrow path being rendered.
So given we provide 4 placement options via the CustomPopupPlacementCallbackdelegate, Is there a way to detect which of the 4 positions the system finally chose after dealing with screen edge cases and the sorts.
A better way to find placement of the Popup.
This method requires a Child element to be present, but that's no problem considering the Grid that comes with a Popup element.
UIElement container = VisualTreeHelper.GetParent(this) as UIElement;
Point relativeLocation = this.Child.TranslatePoint(new Point(0, 0), container); //It HAS(!!!) to be this.Child
if (relativeLocation.Y < 0) //or use X for left and right
{
Console.WriteLine("TOP PLACEMENT!");
}
else
{
Console.WriteLine("BOTTOM PLACEMENT!");
}
I have a little hacky solution.
Save the custom points as fields in the derived TooTip class and override the OnOpened method.
protected override void OnOpened(RoutedEventArgs e)
{
base.OnOpened(e);
var p = this.TranslatePoint(new Point(0, 0), this.PlacementTarget);
var diff1 = this.first - p;
var diff2 = this.second - p;
if (Math.Abs(Math.Min(diff1.Length, diff2.Length) - diff1.Length) < 0.01)
{
// First Point
}
else
{
// Second Point
}
}
Better solutions are welcome
I am designing a control where the user can specify the X, Y, Width and Height of the DisplayRectangle property in relation to the ClientRectangle.
From what I have read in the MSDN documentation, DisplayRectangle only has a get accessor, and therefore its dimensions cannot be set, however this is imperative in my control!
Can any one suggest how I might safely implement a DisplayRectangle that has both get and set accessors? - or explain why this is bad practice?
Thanks.
TESTS:
Set TabControl style to UserPaint, and adjust the Alignment property, The DisplayRectangle moves to compensate for the location of the tabs. Assuming TabControl has a built in mechanism to set the Rectangle bounds.
Created DemoControl : Control, painted ClientRectangle in Red, and DisplayRectangle in Blue and tried calling SetDisplayRectLocation(x, y)...not quite what I wanted...and yielded no results!
In order to allow the user to set the bounds of the DisplayRectangle property for a control, I have come up with the following solution:
public class ExtendedControl : Control
{
private Rectangle displayRectangle;
protected override Rectangle DisplayRectangle
{
get { return this.displayRectangle; }
}
public void SetDisplayRectangle(Rectangle rect)
{
this.displayRectangle = rect;
}
public ExtendedControl()
{
this.displayRectangle = base.DisplayRectangle;
}
}