C# Cursor Position not in right place in forms - c#

I'm trying to create a square that is located where the user clicks. I have pSize, pX, and pY as variables to represent the location and size of the square. But when I click on the form, the square is at least 70 pixels of in X and Y coordinates where the mouse clicked. I did (this is in the form click function):
pX = Cursor.Position.X;
pY = Cursor.Position.Y;
Graphics g = this.CreateGraphics();
SolidBrush brush = new SolidBrush(Color.Black);
g.FillRectangle(brush, pX, pY, pSize, pSize);
Here is a picture of what is happening:
The screenshot doesn't show my cursor but it is in the top left corner. I also noticed that every time I start the program, the amount the square is offset changes so this time it's relatively distant while next time it could be only about 25 pixels away in both axes.
Could someone tell me what I am doing wrong and/or what I can do about it? Thanks.

You're currently getting the Cursor position. Which is relative to the screen, which is why it is a different offset when you move the form around.
To get the position relative to your Form you need to use the Mouse Click position (sounds similar which is how this tricks people).
You need to make sure your Click event raises a MouseEventHandler:
this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.DrawSquare);
Then you need to get the coordintaes from the event handler:
private void DrawSquare(object sender, MouseEventArgs e)
{
int pX = e.X;
int pY = e.Y;
int pSize = 10;
Graphics g = this.CreateGraphics();
SolidBrush brush = new SolidBrush(Color.Black);
g.FillRectangle(brush, pX, pY, pSize, pSize);
}

I think you don't need the cursor position, but the click position instead.
Try this:
private void Form2_MouseClick(object sender, MouseEventArgs e)
{
int pX = e.X;
int pY = e.Y;
Graphics g = this.CreateGraphics();
SolidBrush brush = new SolidBrush(Color.Black);
g.FillRectangle(brush, pX, pY, 10, 10);//Size just for testing purposes
}

Related

c# drawing, circle goes outside form

I am trying to draw a circle within my form.
But it is strange to me I set form width and height to a fixed number, i do the same for the circle, but the circle figure goes outside the form.
private void Form3_Paint(object sender, PaintEventArgs e)
{
this.SuspendLayout();
gr = this.CreateGraphics();
gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
Brush fill_circ3 = Brushes.Blue;
Pen ellipse_pen = new Pen(Color.Blue);
ellipse_pen.Width = (float)2.0;
this.Width = this.Height = 400;
Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
gr.DrawEllipse(ellipse_pen, rect);
this.ResumeLayout();
}
The 3rd and 4th parameters of the Rectangle constructor defines the size in width and height of the circle.
See the circle I got
Why does the circle goes outside the form???! I have set form and circle sizes the same!!!
It's because you use the Window size, not the "client" size. Just replace your code by this:
gr.DrawEllipse(ellipse_pen, this.ClientRectangle);
The client area of a control is the bounds of the control, minus the
nonclient elements such as scroll bars, borders, title bars, and
menus.

How to zoom picturebox along with graphics

I want to zoom picture box along with graphics.
this will Zoom the only image part not the graphics part.
public Image PictureBoxZoom(Image imgP, Size size)
{
Bitmap bm = new Bitmap(imgP, Convert.ToInt32(imgP.Width * size.Width), Convert.ToInt32(imgP.Height * size.Height));
Graphics grap = Graphics.FromImage(bm);
grap.InterpolationMode = InterpolationMode.HighQualityBicubic;
return bm;
}
private void zoomSlider_Scroll(object sender, EventArgs e)
{
if (zoomSlider.Value > 0 && img != null)
{
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
pictureBox1.Image = null;
pictureBox1.Image = PictureBoxZoom(img, new Size(zoomSlider.Value, zoomSlider.Value));
}
}
the source of image is:
img = Image.FromStream(openFileDialog1.OpenFile());
Picture is zooming but when we draw the rectangle outside image then it's not zooming along with image.
See image:
You can do this (rather) easily by scaling the e.Graphics object in the Paint event.. See here for an example!
So to work with you code you probably should add this to the Paint event:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.ScaleTransform(zoom, zoom);
// now do your drawing..
// here just a demo ellipse and a line..
Rectangle rect = panel1.ClientRectangle;
g.DrawEllipse(Pens.Firebrick, rect);
using (Pen pen = new Pen(Color.DarkBlue, 4f)) g.DrawLine(pen, 22, 22, 88, 88);
}
To calculate the zoom factor you need to do a little calculation.
Usually you would not create a zoomed Image but leave that job to the PictureBox with a SizeMode=Zoom.
Then you could write:
float zoom = 1f * pictureBox1.ClientSize.Width / pictureBox1.Image.Width;
To center the image one usually moves the PictureBox inside a Panel. And to allow scrolling one sets the Panel to Autocroll=true;
But since you are creating a zoomed Image you should keep track of the current zoom by some other means.
Note:
But as you use PictureBoxSizeMode.CenterImage maybe your problem is not with the zooming after all?? If your issue really is the placement, not the size of the drawn graphics you need to do a e.Graphics.TranslateTransform to move it to the right spot..

C# GDI Rotate Projectile

I have this code
Graphics g;
g.FillRectangle(new SolidBrush(Color.Red), _Location.X - 2, _Location.Y - 2, 10, 10);
and the rectangle is shot at an angle to some direction, how can I get the rectangle to rotate while moving or rotate at all.
This should rotate a rectangle moving across the screen.
private int _angle = 0;
private Point _location = new Point(0, 0);
private void _timer_Tick(object sender, System.EventArgs e)
{
// nothing interesting here, moving the top left co-ordinate of the
// rectangle at constant rate
_location = new System.Drawing.Point(_location.X + 2, _location.Y + 2);
_angle += 5; // our current rotation angle
this.Invalidate();
}
void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
// rebase the co-ordinate system so our current x,y is 0, 0 and that is
// the center of the rotation
g.TranslateTransform(_location.X, _location.Y, MatrixOrder.Append);
g.RotateTransform(_angle); // do the rotation
// make sure the centre of the rectangle is the centre of rotation (0, 0)
g.FillRectangle(new SolidBrush(Color.Red), -5, -5, 10, 10);
}
I've figured it out right before I saw #steve16351 's response, but his code was still useful. What I did was switch from using PointF to Rectangle, because the Rectangle has a property which holds the value of the upper left corner's coordinates, so I can increment/decrement that at a stable rate, in my game loop, to make it rotate.

Move a rectangle using angles

I need to move a rectangle using angles. Actually I want to change the direction of my moving rectangle when it reaches the location I have given in my code in if statement!
I just need the way I can find out how to move my rectangle at 60, 30, 60, 120, 150, 270 degrees!
Suppose that if
circle.Y>=this.Height-80
See this:
I really actually need to change the direction of rectangle movement using angles! so that at certain location reaches I can change the rectangle direction according to angle of my own choice!
such that:
if(circle.Y>=this.Height-80)
move in the direction of 90 degrees
if(circle.X>=this.Width-80)
move in the direction of 60 degree
as you can see in the screen shot!
What I have been trying is:
public partial class Form1 : Form
{
Rectangle circle;
double dx = 2;
double dy = 2;
public Form1()
{
InitializeComponent();
circle = new Rectangle(10, 10, 40, 40);
}
private void Form1_Load(object sender, EventArgs e)
{
this.Refresh();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.FillEllipse(new SolidBrush(Color.Red), circle);
}
private void timer_Tick(object sender, EventArgs e)
{
circle.X += (int)dx;
circle.Y += (int)dy;
if (circle.Y>=this.Height-80)
{
dy = -Math.Acos(0) * dy/dy; //here i want to change the direction of circle at 90 degrees so that it should go up vertically straight with same speed
}
this.Refresh();
}
}
The Problem is that I have been trying changing my conditions to:
dy = -Math.Asin(1) * dy;
dx = Math.Acos(0) * dx ;
but in both cases nothing is happening and the direction remains same!
I just want to move the circle in inverted upward direction at 90 degrees when it reach at
circle.Y>=this.Height-80
You need to draw the rectangle again to some image for it to display. I created this code for moving and drawing rectangle on pictureBox1, using your already defined circle-rectangle:
Moving the rectangle:
public void MoveRectangle(ref Rectangle rectangle, double angle, double distance)
{
double angleRadians = (Math.PI * (angle) / 180.0);
rectangle.X = (int)((double)rectangle.X - (Math.Cos(angleRadians) * distance));
rectangle.Y = (int)((double)rectangle.Y - (Math.Sin(angleRadians) * distance));
}
Drawing the rectangle and displaying it in the PictureBox:
public void DrawRectangle(Rectangle rectangle)
{
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.FillEllipse(new SolidBrush(Color.Red), rectangle);
}
pictureBox1.Image = bmp;
}
Demo it with a button click:
private void Button1_Click(object sender, EventArgs e)
{
MoveRectangle(ref circle, 90, 5);
DrawRectangle(circle);
}
Math.Asin(1) * dy is a constant value. Thus, you should use, for example, an instance variable that increments in each Tick of your timer.
...And *dy/dy is irrelevant.
public partial class Form1 : Form
{
Rectangle circle;
double dx = 2;
double dy = 2;
acum=0; //the new variable
...
private void timer_Tick(object sender, EventArgs e)
{
circle.X += (int)dx;
circle.Y += (int)dy;
if (circle.Y>=this.Height-300)
{
dy = -Math.Acos(acum);
acum+=1; //your accumulator
}
this.Refresh();
}
acos and asin are the inverse of sin and cos so the output of those two functions is an angle (usually in radians). This makes the code incorrect.
I strongly suggest that you read up on vector and matrix maths as using Euler angles can get quite messy.
So, you will have a position vector P and a movement vector M and the current position is:
P' = P + M.t
where t is time, P is the original position and P' is the current position.
Then, when you want to change direction, you create a rotation matrix and multiply the movement vector M by this rotation matrix.
The advantage here is that you can step from a 2D system to a 3D system by adding a Z component to your vectors and increasing the size of your matrices.

Always visible drawing on form

I want to draw always visible cross over picturebox on winform. I know ho to use Graphics and it's method DrawLine. But problem is that, painted cross is hidden behind the picturebox. this textbox is continually refreshed and this cross should be always visible.
Do you have some solution for this?
Here is code:
Point picBoxLocation = pictureBox.Location;
Size picBoxSize = pictureBox.Size;
Pen myPen = new Pen(System.Drawing.Color.Red, 5);
Point left = new Point(picBoxLocation.X, picBoxSize.Height/2);
Point right = new Point(picBoxLocation.X+picBoxSize.Width, picBoxSize.Height / 2);
Point up = new Point((picBoxLocation.X + picBoxSize.Width) / 2, picBoxLocation.Y);
Point bottom = new Point((picBoxLocation.X + picBoxSize.Width) / 2, (picBoxLocation.Y+picBoxSize.Height)/2);
Graphics graphics = this.CreateGraphics();
graphics.DrawLine(myPen, left, right);
graphics.DrawLine(myPen, up, bottom);
Try to get Graphics object in OnPaint callback:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawLine(...);
}

Categories