DrawRectangle doesn't work - c#

I have a rectangle on a class created by me. The function "DrawRectangle" doesn't draw anything. I put the code below:
My own class (Unidad.cs):
class Unidad
{
//Constructor
public Unidad(string tipo, int movimiento)
{
tipoUnidad = tipo;
movimientoUnidad = movimiento;
}
//Propiedades
public string tipoUnidad {get; set;}
public int movimientoUnidad { get; set; }
//Método para dibujar unidad
public void colocar(MouseEventArgs e)
{
Form1 myf = new Form1();
using (Graphics g = myf.picboxFondo.CreateGraphics())
{
Pen pen = new Pen(Color.Red, 2);
g.DrawRectangle(pen, e.X, e.Y, 20, 20);
pen.Dispose();
g.Dispose();
}
}
}
Main class:
public partial class Form1 : Form
{
//Prueba de clase
Unidad prueba;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
picboxFondo.Size = ClientRectangle.Size;
prueba = new Unidad("I", 20);
}
private void picboxFondo_MouseDown(object sender, MouseEventArgs e)
{
prueba.colocar(e);
}
}
I have picboxFondo Modifiers public. All compile correctly and works perfect, but when I go to g.DrawRectangle I see all the values are OK but it doesn't draw anything.
Can you help me?
Thanks!

You are creating a new instance of your Form1 class and try to draw on the PictureBox of that new instance (which isn't shown at all).
Instead you can pass the control you want to draw on as a parameter to your colocar method:
public void colocar(Point p, Control control)
{
using (Graphics g = control.CreateGraphics())
{
using (Pen pen = new Pen(Color.Red, 2))
{
g.DrawRectangle(pen, p.X, p.Y, 20, 20);
}
}
}
and call it like that in your form:
private void picboxFondo_MouseDown(object sender, MouseEventArgs e)
{
prueba.colocar(e.Location, picboxFondo);
}
I also changed the method so that you only pass the Location of the MouseEventArgs, because your drawing method doesn't need to know anything about mouse events, only about the Point.
And note that there is no need to call Dispose on the Pen or the Graphics, the using statement is doing that for you.
And you may consider using the .NET naming conventions and rename your method Colocar.

Related

How do I associate a mouse click with a drawn object in C#?

I have a picturebox with a bunch of rectangles drawn over it (highlighting some features of the image). I want to determine if my user clicked within a given rectangle, and add an action specific to that rectangle (i.e. show additional information). How do I do this?
I can provide more information if desired, I'm just not sure what information would be useful at this point.
Current code to draw rectangles. rectX, rectY, rectRot, rectColor are all currently arrays. rectW and rectH are constants.
private void pbPicture_Paint(object sender, PaintEventArgs e)
{
for(int i = 0; i < rectX.Length; i++)
{
e.Graphics.ResetTransform();
e.Graphics.TranslateTransform(rectX[i], rectY[i]);
e.Graphics.RotateTransform(rectRot[i]);
e.Graphics.DrawRectangle(new Pen(rectColor[i], penWidth), 0, 0, rectW, rectH);
}
e.Graphics.ResetTransform();
}
Edit: added link to picture, additional code.
It'll be easier if you apply and keep the transform data for each shape, then you can use that in your implementation to draw the shapes, interact with the mouse inputs...etc. without doing any additional transform calls to draw the main shapes, nor math routines to find out whether a shape/rectangle contains a given Point.
Consider the Shape class here which encapsulates the relevant data and functionalities that you'll need in your implementation. Using the GraphicsPath class to keep the shape and apply the transform, as well as to use the GraphicsPath.IsVisible method to determine whether the shape contains a given point so you can take an action accordingly. Keeping and exposing the Matrix instance is to use it to transform the graphics in case you need to do more drawings over the shape like drawing text, image...etc.
using System;
using System.Drawing;
using System.Drawing.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
public class Shape : IDisposable
{
private bool disposedValue;
private Matrix mx;
private GraphicsPath gp;
private Size sz;
private Point loc;
private float rot;
public string Text { get; set; }
public Size Size
{
get => sz;
set
{
if (sz != value)
{
sz = value;
CleanUp();
}
}
}
public Point Location
{
get => loc;
set
{
if (loc != value)
{
loc = value;
CleanUp();
}
}
}
public float Rotation
{
get => rot;
set
{
if (rot != value)
{
rot = value;
CleanUp();
}
}
}
public Matrix Matrix
{
get
{
if (mx == null)
{
mx = new Matrix();
// According to your code snippet, you don't need to offset here.
// mx.Translate(Location.X, Location.Y);
mx.RotateAt(Rotation, Center);
}
return mx;
}
}
public GraphicsPath GraphicsPath
{
get
{
if (gp == null)
{
gp = new GraphicsPath();
gp.AddRectangle(Rectangle);
gp.Transform(Matrix);
}
return gp;
}
}
public Point Center
{
get
{
var r = Rectangle;
return new Point(r.X + r.Width / 2, r.Y + r.Height / 2);
}
}
public Rectangle Rectangle => new Rectangle(Location, Size);
public bool Selected { get; set; }
public Color BorderColor { get; set; } = Color.Black;
// Add more, ForeColor, BackColor ...etc.
public bool Contains(Point point) => GraphicsPath.IsVisible(point);
private void CleanUp()
{
gp?.Dispose();
gp = null;
mx?.Dispose();
mx = null;
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing) CleanUp();
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
Having that, your implementation should be as simple as:
private readonly List<Shape> shapes = new List<Shape>();
private const int recW = 100;
private const int recH = 20;
// A method to create the list...
private void SomeMethod()
{
shapes.ForEach(s => s.Dispose());
shapes.Clear();
// In some loop...
var shape = new Shape
{
Text = "Shape...",
Size = new Size(recW, recH),
Location = new Point(some.X, some.Y),
Rotation = someAngle
};
shapes.Add(shape);
// Add the reset...
pbox.Invalidate();
}
// And to dispose of them...
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
shapes.ForEach(x => x.Dispose());
}
The drawing part:
private void pbox_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
using (var sf = new StringFormat(StringFormat.GenericTypographic))
{
sf.Alignment = sf.LineAlignment = StringAlignment.Center;
shapes.ForEach(s =>
{
using (var pnBorder = new Pen(s.BorderColor))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.Half;
if (s.Selected) g.FillPath(Brushes.DarkOrange, s.GraphicsPath);
g.DrawPath(pnBorder, s.GraphicsPath);
if (!string.IsNullOrEmpty(s.Text))
{
g.SmoothingMode = SmoothingMode.None;
g.PixelOffsetMode = PixelOffsetMode.Default;
g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
g.Transform = s.Matrix;
g.DrawString(s.Text, Font, Brushes.Black, s.Rectangle, sf);
g.ResetTransform();
}
}
});
}
}
Interacting with the mouse events:
private void pbox_MouseDown(object sender, MouseEventArgs e)
{
foreach (var shape in shapes)
shape.Selected = shape.Contains(e.Location);
pbox.Invalidate();
}
I've created rectangles (Shape objects) with random values to demo.
Note: Some offset (Matrix.Translate(...)) also applied here to have some space between the shapes.
\You can use the event argument e to get the mouse co ordinates
private void pictureBox1_Click(object sender, EventArgs e)
{
MouseEventArgs me = (MouseEventArgs)e;
Point coordinates = me.Location;
}
There is one more link to help you identify the click events on the shape -
https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2015/ide/tutorial-3-create-a-matching-game?view=vs-2015&redirectedfrom=MSDN

increase pen width with trackbar value

As the it's said in the title, i am trying to increase pen width size by using a trackbar.
This is what i have written so far:
public partial class Form26_10 : Form
{
float scrollValue = 0F;
Pen CustomPen = new Pen(Color.Black, scrollValue);//ERROR<-
public Form26_10()
{
InitializeComponent();
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
scrollValue = trackBar1.Value;
}
}
essentially i should be able to declare a value in memory, then have it in the pen width parameter and so when the trackbar value change's the pen width changes. Though i am getting this error:
a field initializer cannot reference the non-static field, method or property of 'Form.scrollValue'
public partial class Form26_10 : Form
{
private Pen CustomPen;
public Form26_10()
{
InitializeComponent();
CustomPen = new Pen(Color.Black, scrollValue);
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
CustomPen.Width = trackBar1.Value;
}
}
You shouldn't initialize class fields at declaration if you've got a changing value. Also, float has a default value of 0.0F so you don't need to initialize it. I removed it in this example because I assumed you wouldn't need it. If you still plan on using it, you can just add it at the top.
float scrollValue;

Adding control to form from other class

I'm trying to create picturebox in class and add it to form with method, it doesn't have any errors but it doesn't display picturebox
Class:
class Igrac
{
public int ID;
public string Ime;
public int Polje;
public int Novac;
public Igrac(int id, string ime, int polje, int novac)
{
ID = id;
Ime = ime;
Polje = polje;
Novac = novac;
}
public void Pijun (int LocX,Image image, Form1 form)
{
PictureBox pijun = new PictureBox();
pijun.Size = new Size(20, 40);
pijun.Location = new Point(LocX,655);
pijun.Image = image;
form.Controls.Add(pijun);
}
}
Main program:
private void Form1_Load(object sender, EventArgs e)
{
Igrac igrac1 = new Igrac(1, ImeIgraca1, 0, 10000);
igrac1.Pijun(643, Properties.Resources.Pijun1,this);
}
I have pasted your code and its works fine, but check parameters in new Point(LocX, 655) contructor. If it is larger than form size, control will be outer window, because (0,0) point is on left upper corner.
It was overlapped by another control...

c# List.Add() unable to add correct values

Program suppose to draw shapes on panel1.
This is code for my main form:
namespace DrawShapes
{
public partial class Form1 : Form
{
List<Shape> myShapeList;
Shape shape;
public Form1()
{
InitializeComponent();
}
public void AddShape(Shape myshape)
{
myShapeList.Add(shape);
}
public List<Shape> MyShapeList
{
get { return myShapeList; }
}
private void Form1_Load(object sender, EventArgs e)
{
myShapeList = new List<Shape>();
shape = new Shape();
}
private void drawMeButton_Click(object sender, EventArgs e)
{
EditShape editShape = new EditShape();
editShape.Shape = shape;
if (editShape.ShowDialog() == DialogResult.OK)
{
this.shape = editShape.Shape;
myShapeList.Add(shape);
panel1.Invalidate();
}
editShape.Dispose();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
int panelWidth = panel1.ClientRectangle.Width;
int panelHeight = panel1.ClientRectangle.Height;
Pen penLine = new Pen(Color.Blue, 1);
Graphics g = e.Graphics;
if (myShapeList != null)
{
foreach (Shape element in myShapeList)
{
label1.Text = element.Width.ToString();
g.DrawRectangle(penLine, element.XCordinates, element.XCordinates, 50, 50);
}
}
}
}
}
and here is code for my edit shape dialog box
namespace DrawShapes
{
public partial class EditShape : Form
{
Shape shape = null;
public EditShape()
{
InitializeComponent();
}
public Shape Shape
{
get { return shape; }
set { shape = value; }
}
private void button1_Click(object sender, EventArgs e)
{
shape.Width = 50;
shape.Height = 50;
shape.XCordinates = int.Parse(textBox1.Text);
shape.YCordinates = int.Parse(textBox2.Text);
shape.Type = 0;
DialogResult = DialogResult.OK;
}
}
}
I am having problem assigning shape object(from Edit Shape form) to myShapeList, all properties are set to 0 for some reason. Please help.
Perhaps the problem is your AddShape method. You seem to be adding shape each time instead of the shape that's getting passed into the method (myshape).
What happens if you do this instead?
public void AddShape(Shape myshape)
{
myShapeList.Add(myshape); // myshapeinstead of shape
}
It seems that you're not actually adding your shape to your shapelist. You're taking in myShape and then trying to add in shape. This should come up as an intellisense error.
public void AddShape(Shape myshape)
{
myShapeList.Add(shape);
}
EDIT: Nevermind, it wouldn't come up as an error because you have a member variable named shape. You're getting zero for everything because it's calling the default constructor for shape.
The big problem is in your call to the edit form. You are adding to the list the same object reference. So when you modify the reference inside the edit form you change all the elements added to the list to the inputs set in the latest call
Change your code to
private void drawMeButton_Click(object sender, EventArgs e)
{
using(EditShape editShape = new EditShape())
{
// Here, create a new instance of a Shape and edit it....
editShape.Shape = new Shape();
if (editShape.ShowDialog() == DialogResult.OK)
{
// Add the new instance to the list, not the same instance
// declared globally. (and, at this point, useless)
myShapeList.Add(editShape.Shape);
panel1.Invalidate();
}
// The using blocks makes this call superflous
// editShape.Dispose();
}
}
Then it is not clear when you call the method AddShape(Shape myshape) but it is clear that you have typo in that method
I have found my mistake.I Created new event handler with wrong parameters. Therefore information that suppose to be passed by my dialog OK button was never correctly assigned. Silly mistake. Thanks guys.

How to access the picturebox from a new class?

Here is my "Card" class:
public class Card
{
public Card()
{
}
public void Generate()
{
frmMain0 frmMain0 = new frmMain0();
Player Spieler = new Player();
//some code here
Graphics g = frmMain0.pbCard.CreateGraphics();
SolidBrush bWhite = new SolidBrush(Color.White);
Font fntDebug = new Font("Arial", 8);
g.DrawString("fsdfsdfcdsfcdscfdsfsdfsdfs", fntDebug, bWhite, 10, 10);
}
}
And here is the main Form:
public partial class frmMain0 : Form
{
public frmMain0()
{
InitializeComponent();
}
private void frmMain0_Load(object sender, EventArgs e)
{
Card Karte = new Card();
Karte.Generate();
}
}
Visual Studio lets me debug the code but I don't see the text on my picture, what am I doing from here?

Categories