I have a litle problem doing something I want.
What I want is quite simple.
I'm making a game tower defence for school.
When I clicked on a tower to place I want to see the tower when moving over my picturebox where everything happens in. This is no problem when I move it does what I want. But when I stop moving my Mouse I want the image stay on the position where it last was ( MouseHover).
But i don't get the mousehover event to do what I want. When I stop moving my mouse the image disapears and nothing is shown in my picturebox.
This is what i currently have for my MouseMove & MouseHover:
Note: I have already tried to use the MousePosition in the mousehover event but this doesn't work either. I hope someone can help me out on this ?
private void picGameArea_MouseMove(object sender, MouseEventArgs e)
{
Pen myPen = new Pen(Color.Black);
if (myGameLogic.tmpTower != null)
{
Xpos = e.X;
YPos = e.Y;
Graphics paper;
paper = picGameArea.CreateGraphics();
paper.DrawImage(myGameLogic.tmpTower.myImage, e.X - 25, e.Y -25, 50, 50);
paper.DrawEllipse(myPen, e.X - myGameLogic.tmpTower.Range, e.Y - myGameLogic.tmpTower.Range , myGameLogic.tmpTower.Range * 2, myGameLogic.tmpTower.Range * 2);
picGameArea.Invalidate();
}
}
private void picGameArea_MouseHover(object sender, EventArgs e)
{
Graphics paper;
paper = picGameArea.CreateGraphics();
if (myGameLogic.tmpTower != null)
{
paper.DrawImage(myGameLogic.tmpTower.myImage, Xpos - 25, YPos - 25, 50, 50);
}
picGameArea.Invalidate();
}
The image disappears because your next Paint event will redraw picGameArea and inside that event nothing will redraw your image of tmpTower.
You have 2 options:
move tmpTower drawing inside Paint event.
enable polling to redraw what is drawn on top by using timer.
There are mistakes in your code:
CreateGraphics required disposing, put it inside using or call paper.Dispose();
there is no need to handle MouseHover at all, this event is used for something like showing ToolTip, it only triggers once if mouse is inside control for some time.
calling Invalidate event will queue paint (it's like asking please, redraw my control some time later, when you have time), instead use Refresh before painting (and remove Invalidate).
Last one actually will fix your issue too...
Related
I am trying to create a elipse in a textbox on double click. But it doesnt seem to happen.
panel.MouseClick += create_terms;
private void create_terms(object sender, EventArgs arg)
{
if (Phys_terms_check.Checked == true)
{
MouseEventArgs e = (MouseEventArgs)arg;
Graphics g = CreateGraphics();
SolidBrush p = new SolidBrush(Color.Red);
Pen erase = new Pen(Color.White);
Panel panel = (Panel)sender;
g.FillEllipse(p, e.X+panel.Left,e.Y+panel.Top,10,10);
}
}
The e.x and e.y seem to be giving relative coordinates from the sender. How to get point relative to the form.
add sender's top and left coordinates.
g.FillEllipse(p, e.X + textbox.Left, e.Y + textbox.Top, 10, 10);
but, this won't show, because textbox paint event fill fire and repaint textbox.
First of all: TextBoxes are old legacy and rather special Controls that do not support all things normal controls let you do.
Among the things that won't work are
Setting a BackgroundImage
Owner-drawing them
The latter includes any drawing in its Paint/OnPaint events.
You can code and hook-up the Paint event, but it won't get called.
You still can draw onto a TextBox using CreateGraphics, if you do it right, but as always with this function the result is non-persistent and will go away as soon as the system refreshes the TextBox itself, which is super-fast: as soon as you move your cursor over it the circle you draw may disappear..
The code to do it would have to look similar to this:
Graphics g = yourTextBox.CreateGraphics();
g.FillEllipse(Brushes.Red, yourTextBox.Width - 22, 2, 11, 11);
But as I said this will not persist, so it has little or no value.
If you want to draw onto something with a visible Text property you can use a Label:
private void yourLabel_Paint(object sender, PaintEventArgs e)
{
e.Graphics.FillEllipse(Brushes.Red, yourLabel.Width - 22, 2, 11, 11);
}
The result looks the same, but only the dot in the Label will persist, e.g. a Minimize-Maximize of the form.. In fact the dot in the TextBox didn't even survive calling my screenshot program, so I had use resort to pressing the Print-Key !
For drawing circles upon mouseclicks onto normal controls see this post!
I am looking to draw an ellipse on the screen during the MouseMove() event but am wanting it to only draw the most recent ellipse from a start point to the current mouse position. At the moment it is drawing an ellipse for every mouse position that is getting registered. I would be able to draw it easily enough without showing the ellipse if i simply used the MouseDown() and MouseUp() events, but I am wanting the user to be able to see the ellipse as they move the mouse around, so they can know exactly where they are placing it. Does anyone know how I could achieve this?
My current code is as follows:
private void pnlDraw_MouseDown(object sender, MouseEventArgs e)
{
initialX = e.X;
initialY = e.Y;
previousX = e.X;
previousY = e.Y;
isPainting = true;
}
private void pnlDraw_MouseMove(object sender, MouseEventArgs e)
{
if (isPainting)
{
switch (currentDrawType)
{
case DRAWTYPE.ELLIPSE:
{
DrawEllipse(e);
break;
}
default:
{
break;
}
}
}
}
private void DrawEllipse(MouseEventArgs e)
{
pen = new Pen(Color.Black);
Graphics graphics = pnlDraw.CreateGraphics();
graphics.DrawEllipse(pen, initialX, initialY, e.X - initialX, e.Y - initialY);
previousX = e.X;
previousY = e.Y;
graphics.Dispose();
}
Any help would be greatly appreciated!
The first thing you should do when you are drawing something on screen is to clear what was previously displayed. Otherwise, you simply draw on top of existing drawing.
In WinForm, it's normally handled in the OnBackgroundPaint() method, which is a simple way of saying that it's there you should clear the background.
It should looks like this:
e.Graphics.FillRectangle(new SolidBrush(MyBackgroundColor), e.ClipRectangle);
or if it's not a drawing event:
graphics.FillRectangle(new SolidBrush(MyBackgroundColor), 0, 0, MyWidth, MyHeight);
And should be called before drawing anything on top of it.
It is also a guaranty that your drawing zone is ready to be drawn on it.
I've been having problems with onPaint event handler for a pictureBox. I've simplified the code, so right now I'm trying to achieve this: load the bitmap from path into pictureBox1 and draw a small rectangle around mouse cursor when moving over the pictureBox1.
private int mouseX;
private int mouseY;
private String path;
public Form1()
{
InitializeComponent();
path = "images\\image.jpg";
}
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.Image = new Bitmap(path);
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
mouseX = e.X;
mouseY = e.Y;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.Black, mouseX - 10, mouseY - 10, 20, 20);
pictureBox1.Invalidate();
}
When I run the application the bitmap is loaded successfully and the rectangle is being drawn nicely wherever I drag the mouse. Anyway there are two problems:
1) When the Form is loaded everything is white but pictureBox until I move the window somewhere. It means menuStrip, toolStrip eg is cleared with white color. When I add pictureBox.Invalidate(); into Form1_Load it seems to take care of that problem (everything is loaded and visible) but on the toolStrip there are some buttons and comboBoxes that are interacting, changing its visibility and this still causes problems. I'd like to reduce the funcionality of the Paint only on pictureBox.
2) The rectangle is drawn the moment the Form is loaded despite the mouse cursor didn't enter pictureBox. Also when cursor leaves the pictureBox the last drawn rectangle stays there. I've tried to remove it but I couldn't figure it out.
Thanks for any suggestions, it seems to me that something fundamental is missing there but don't know what.
2) MouseMove works only when cursor is over picture box. Try to use MouseEnter and MouseLeave in order to handle when to start drawing rectangle and when to stop doing that.
I'm currently trying to draw something on image that is shown in pictureBox. I'm using event handlers for mouse activity: onMouseUp, onMouseMove and onMouseDown.
private void onMouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
}
private void onMouseMove(object sender, MouseEventArgs e)
{
if (mouseDown)
{
using (Graphics g = pictureBox.CreateGraphics())
{
g.FillEllipse(Brushes.Black, e.X - size, e.Y - size, size * 2, size * 2);
}
}
}
private void onMouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
using (Graphics g = pictureBox.CreateGraphics())
{
g.FillEllipse(Brushes.Black, e.X - size, e.Y - size, size * 2, size * 2); //just in case user just clicks instead of move the mouse
}
}
I'm trying to simulate brush tool that draws circles of specified size (radius) when mouse is moving over pictureBox. It is working great when moving slow but when the movement is faster pictureBox seems to catch only some of the events and lot of circles is skipped and not drawn. Especially when the radius is small.
What can I do to make it faster and smoother?
When the mouse is moved, you won't get a MouseMove event for every single pixel traveled by the mouse pointer. You'll get them at a fairly consistent time interval, so the faster the mouse moves, the further apart the points you'll get. This particular detail you can't do much about.
What you need to do is store the position of the last point received, and draw an ellipse at every point between the last and the new one.
I am working on a simple windows forms paint application. I am having problem in clearing the panel. The code i am using to draw is
private void panel1_Paint(object sender, PaintEventArgs e)
{
Graphics g = Graphics.FromImage(tempDraw);
Pen myPen = new Pen(foreColor, lineWidth);
g.DrawLine(myPen, x1, y1, x2, y2);
myPen.Width = 100;
myPen.Dispose();
e.Graphics.DrawImageUnscaled(tempDraw, 0, 0);
g.Dispose();
}
How to clear the panel?
Are drawing in the paint handler of the Panel instance? If not then calling Invalidate on the panel would do.
But you will probably be persisting the drawing items and so to clear them you would need to delete what has been drawn and then call Invalidate. You could also fill the Panel with a particular color using FillRect but that would be a dirty workaround and not fit your final design.
You should also check out CodeProject.com for examples like this one to give you an idea on what needs to be handled when creating a drawing app like this.
EDIT:
Per the edited answer, you cannot clear the panel with the existing logic. You are painting inside Paint handler of the form which will happen any time it needs to be redrawn. This means that you should change your approach. You need some sort of condition inside the Paint handler which decides whether or not it will paint anything at all. This is where the persistence of drawing objects comes in. If you want to create a drawing program then you will have to handle the mouse Down, Up and Move events over the panel objects and store the data in a points array. (As an example of one type of drawing.) Then in your Paint handler if the Points[] is not empty you draw the points. Otherwise you draw nothing... which ends up in an empty container. Then if you need to clear the drawing you delete the contents of the Points array and call Invalidate on the Panel. That will clear the persisted data and repaint to nothing.
You can use
Panel1.Invalidate();
But there is a problem with this, after you call this function it clears all the graphics from the panel, but it also recalls the function i.e.
private void panel1_Paint(object sender, PaintEventArgs e)
{
//This function is recalled after Panel1.Invalidate();
}
So solution is to make your paint code in some other function
private void MyDrawing()
{
Graphics g = Graphics.FromImage(tempDraw);
// if above line doesn't work you can use the following commented line
//Graphics g = Graphics.Panel1.CreateGraphics();
Pen myPen = new Pen(foreColor, lineWidth);
g.DrawLine(myPen, x1, y1, x2, y2);
myPen.Width = 100;
myPen.Dispose();
Panel1.Graphics.DrawImageUnscaled(tempDraw, 0, 0);
g.Dispose();
}
You'll have to draw over the panel again with whatever base colour you're using eg. white\grey with the Graphics.FillRectangle method:
// Create solid brush.
SolidBrush whiteBrush = new SolidBrush(Color.White);
// Create location and size of rectangle.
// Fill rectangle to screen.
e.Graphics.FillRectangle(whiteBrush, panel.Location.X, panel.Location.Y, panel.Width, panel.Height);
this.Invalidate();