I created two Rectangles. I want to add events on them. For example when mouse hover on one, the hovered one will change color, can do resize or drag them(rectangles) to other place...
I was just wondering if I could control the drawn graphic, or it will like Microsoft Paint that after you painted, the object can not be operate unless you clear canvas and do redraw.
Is it possible to control a drawn graphic, thanks for any suggestion.
Simple code of my drawn graphics
private void Form1_Paint(object sender, PaintEventArgs e)
{
// Create pen.
Pen blackPen = new Pen(Color.Black, 3);
// Create rectangle.
Rectangle rect1 = new Rectangle(20, 20, 250, 250);
Rectangle rect2 = new Rectangle(70, 70, 150, 150);
// Draw rectangle to screen.
e.Graphics.FillRectangle(Brushes.DeepSkyBlue, rect1);
e.Graphics.FillRectangle(Brushes.LightBlue, rect2);
}
Also, you can create your own control like:
class RectangleControl : Control
{
public void FillRectangle(Color color)
{
this.BackColor = color;
}
}
Then :
private void Form1_Paint(object sender, PaintEventArgs e)
{
RectangleControl rect1 = new RectangleControl() { Parent = this, Left = 20, Top = 20, Width = 250, Height = 250 };
rect1.FillRectangle(Color.DeepSkyBlue);
RectangleControl rect2 = new RectangleControl() { Parent = rect1, Left = 50, Top = 50, Width = 150, Height = 150 };
rect2.FillRectangle(Color.LightBlue);
rect1.MouseHover += Rect1_MouseHover;
rect2.MouseLeave += Rect2_MouseLeave;
}
private void Rect2_MouseLeave(object sender, EventArgs e)
{
(sender as RectangleControl).BackColor = Color.Yellow;
}
private void Rect1_MouseHover(object sender, EventArgs e)
{
(sender as RectangleControl).BackColor = Color.LightBlue;
}
You can use Panel control instead.
Just add 2 panel controls as you would like them to be arranged and add 2 event handlers:
private void panel1_MouseHover(object sender, EventArgs e)
{
panel1.BackColor = Color.Yellow;
}
private void panel1_MouseLeave(object sender, EventArgs e)
{
panel1.BackColor = Color.LightBlue;
}
You can monitor the MouseMove.
Here's code using MouseMove and some brush values used by the rectangles.
using System.Drawing;
using System.Windows.Forms;
namespace Question_Answer_WinForms_App
{
public partial class Form1 : Form
{
public Brush outerRectangleBrush = Brushes.DeepSkyBlue;
public Brush innerRectangleBrush = Brushes.LightBlue;
public Form1()
{
InitializeComponent();
Paint += Form1_Paint;
MouseMove += Form1_MouseMove;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
var isWithinOuterRectangle = e.Location.X >= 20
&& e.Location.X <= 250 + 20
&& e.Location.Y >= 20
&& e.Location.Y <= 250 + 20;
var isWithinInnerRectangle = e.Location.X >= 70
&& e.Location.X <= 150 + 70
&& e.Location.Y >= 70
&& e.Location.Y <= 150 + 70;
if (isWithinOuterRectangle)
{
if (isWithinInnerRectangle)
{
outerRectangleBrush = Brushes.DeepSkyBlue;
innerRectangleBrush = Brushes.Red;
Refresh();
}
else
{
outerRectangleBrush = Brushes.Red;
innerRectangleBrush = Brushes.LightBlue;
Refresh();
}
}
else
{
outerRectangleBrush = Brushes.DeepSkyBlue;
innerRectangleBrush = Brushes.LightBlue;
Refresh();
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
// Create pen.
Pen blackPen = new Pen(Color.Black, 3);
// Create rectangle.
Rectangle rect1 = new Rectangle(20, 20, 250, 250);
Rectangle rect2 = new Rectangle(70, 70, 150, 150);
// Draw rectangle to screen.
e.Graphics.FillRectangle(outerRectangleBrush, rect1);
e.Graphics.FillRectangle(innerRectangleBrush, rect2);
}
}
}
#FJF, writing a ms-paint like application is not a complicated task. Windows Forms applications are using GDI+ to render graphics. so you can write a simple paint application using WindowsForms.
#nexolini uses a panel to do some draws. actually Ms-Paint does the same somehow. Ms-Paint is a Single-Layer Editor. So you can't resize all objects anytime you wanted (but as I said before you can assume that you have a panel for each newly drawn Shapes; Something like what Ms-Paint does).
So what is the problem?
Ms-Paint doesn't tracks your mouse movements and it doesn't needed (as it's a single layer). You can do all of it's tasks using these Answers.
e.g: for adding a Fill Color tool you can use a getpixel and putpixel to do a recursive algorithm on you image. and you are not needed to know which shape you are working on.
all the other tasks could be implemented easy.
for multi-layer Editors I will prefer to use a more powerful framework (but it's also could be implemented in Windows forms in a bad way), Like WPF. WPF uses DirectX to render your graphics and you are able to write an smooth Editor. WPF is designed to handle your graphical request so it does better on graphics.
#Reza_Aghaei 's comments are useful for Windows Forms.
Related
I found out how to draw Rectangles and some code to find when two rectangles overlap but I can't connect these procedures.
I have the two rectangles that I wanted but then a cannot determine whether these intersect, to then add this information to a ListBox.
Here is my code:
public partial class Form1 : Form
{
Graphics g;
Pen p;
Point cursor;
int k = 0;
Point[] tocke = new Point[2];
public Form1()
{
InitializeComponent();
g = this.CreateGraphics();
p = new Pen(Color.Black, 3);
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
cursor = this.PointToClient(Cursor.Position);
statusMisa.Text = "X: " + cursor.X + " Y: " + cursor.Y;
}
private void Form1_Click(object sender, EventArgs e)
{
bool Preklapanje(int l1x, int l1y, int l2x, int l2y, int r1x, int r1y, int r2x, int r2y)
{
if (l1x >= r2x || l2x >= r1x)
{
return false;
}
if (l1y <= r2y || l2y <= r1y)
{
return false;
}
return true;
}
List<int> pozX = new List<int>();
List<int> pozY = new List<int>();
if (checkCrtanje.Checked == true)
{
Rectangle rect = new Rectangle(cursor.X - 50, cursor.Y - 50, 100, 100);
if (k < 2)
{
g.DrawRectangle(p, rect);
tocke[k++] = new Point(cursor.X, cursor.Y);
listBox1.Items.Add("X: " + cursor.X + " Y: " + cursor.Y);
pozX.Add(cursor.X);
pozY.Add(cursor.Y);
}
else
{
MessageBox.Show("Možeš nacrtati samo dva kvadrata!");
}
}
if (k == 3)
{
if (Preklapanje(pozX[0] - 50, pozY[0] - 50, pozX[0] + 50, pozY[0] + 50, pozX[1] - 50, pozY[1] - 50, pozX[1] + 50, pozY[1] + 50))
{
listBox1.Items.Add("Preklapaju se.");
}
else
{
listBox1.Items.Add("Ne preklapaju se.");
}
}
}
}
► As noted, you shouldn't use CreateGraphics() to draw on a Control's surface: this object becomes invalid (belongs to the past) as soon as the Control where the drawing is performed is invalidated (is repainted).
All Controls that have a drawable surface, raise a Paint event and have an OnPaint method that we can override to perform custom painting (the OnPaint method is responsible to raise the Paint event, so we need to handle just one).
The argument of both the event and the method, represents a PaintEventArgs object, which provides a fresh Graphics object that we can use to paint.
We can call the Invalidate() method to repaint a Control when needed. This method causes the generation of a new PaintEventArgs object (thus, a new Graphics object). After, the OnPaint method is called, which - in turn - raises the Paint event.
► To determine whether a Rectangle intersects another (or more than one), we can use the Rectangle.IntersetWith() method (it returns true or false) and the Rectangle.Interset() method → this is used to generate a Rectangle that represents the intersection of two other rectangles.
See also:
→ Rectangle.Contains([Rectangle])
→ Rectangle.Union([Rectangle a], [Rectangle b]).
Here, I'm using a few collections to store the shapes currently drawn and their intersections (just rectangles, but you can build more complex shapes using GraphicsPath objects):
A List<Rectangle> (rects) which stores the Rectangles already created.
A List<Rectangle> (intersections), to store the intersections which belong to the past (intersections already drawn).
A List<Rectangle> (currentIntersects), used to temporarily store the intersection generated when a new Rectangle shaped is being drawn, so we can use different colors (as soon as we release the Mouse Button, this collection is fixed and added to the intersections collection).
A Rectangle structure (currentRect) which represents the Rectangle that is currently being drawn on the surface (when the Mouse Button is released, this object is added to the rects collection).
A Point structure (startPosition), used to store the initial position of the Rectangle currently drawn. It's reset when the OnMouseDown method is called (when a new Rectangle shape is generated).
► To use this code, create a new Form and paste the code you find here in its Code file. No need to subscribe to any event: since we're drawing on a Form, I'm overriding its methods (OnPaint, OnMouseDown, OnMouseUp, OnMouseMove), no event is used.
You can do the same with a Custom Control or a UserControl.
To add these collection, or just the intersections collection, to e.g., a ListBox, to handle the collections visually, see here (the currentIntersects and intersections collections already contain the information):
How to call a method that uses PaintEventArgs and coordinates variables
NOTE:
► Here, in the OnPaint method override, I'm not calling base.OnPaint(), so the event is not generated. This speeds up the process a bit, but keep in mind that subscribing to the Form's Paint event is useless.
► You need to activate double-buffering: (set DoubleBuffered = true), otherwise you'll notice a lot of flickering (this is quite normal).
This is how it works:
public partial class FormDrawings : Form
{
private List<Rectangle> rects = new List<Rectangle>();
private List<Rectangle> intersections = new List<Rectangle>();
private List<Rectangle> currentIntersects = new List<Rectangle>();
private Rectangle currentRect = Rectangle.Empty;
private Point startPosition = Point.Empty;
private float penSize = 2.0f;
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left) {
startPosition = e.Location;
currentRect = new Rectangle(startPosition, Size.Empty);
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left) {
if (e.Y < startPosition.Y) { currentRect.Location = new Point(currentRect.X, e.Y); }
if (e.X < startPosition.X) { currentRect.Location = new Point(e.X, currentRect.Y); }
currentRect.Size = new Size(Math.Abs(startPosition.X - e.X), Math.Abs(startPosition.Y - e.Y));
currentIntersects.Clear();
foreach (var rect in rects) {
if (currentRect.IntersectsWith(rect)) {
currentIntersects.Add(Rectangle.Intersect(currentRect, rect));
}
}
this.Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
if (currentRect.Size != Size.Empty) rects.Add(currentRect);
if (currentIntersects.Count > 0) {
intersections.AddRange(currentIntersects);
}
}
protected override void OnPaint(PaintEventArgs e)
{
using (var borderPen = new Pen(Color.LightGreen, penSize))
using (var iBrush = new SolidBrush(Color.FromArgb(128, Color.Orange)))
using (var crBrush = new SolidBrush(Color.FromArgb(128, Color.DeepSkyBlue))) {
intersections.ForEach(r => e.Graphics.FillRectangle(iBrush, r));
currentIntersects.ForEach(r => e.Graphics.FillRectangle(crBrush, r));
e.Graphics.DrawRectangle(borderPen, currentRect);
rects.ForEach(r => e.Graphics.DrawRectangle(borderPen, r));
}
}
}
New to stack overflow so hoping someone knows what's going wrong here.
For some reason whenever I hover over a button in my c# forms application, it causes a reset in my code. This seems weird to me considering I don't actually have any hover events on the button. I even tried adding another button and even when I do nothing to it, hovering still causes the reset.
The program is supposed to fill up the tank with colors and the color can be changed while it is filling up. Once it is filled up it resets to empty. It should start filling the next time the slider governing fill speed is interacted with.
It does this correctly but it also starts filling again when I hover over the button.
namespace Assignment5A
{
public partial class MainForm : Form
{
public float streamHeight = 370;
public float lastWaterHeight = 0;
public float waterHeight = 0;
public float waterBottom = 500;
public float fillSpeed = 300;
public Color brushColor = Color.LightBlue;
public Graphics g;
public Pen pen;
public Brush brush = new SolidBrush(Color.LightBlue);
public MainForm()
{
InitializeComponent();
this.Width = 500;
this.Height =600;
this.BackColor = Color.Black;
SpeedTimer.Interval = (int)fillSpeed;
}
private void MainForm_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics;
pen = new Pen(Color.White);
g.DrawLine(pen, 50, 200, 50, 500);
g.DrawLine(pen, 350, 200, 350, 500);
g.DrawLine(pen, 50, 500, 350, 500);
SpeedTimer.Start();
}
private void SpeedTimer_Tick(object sender, EventArgs e)
{
if (waterHeight < 270)
{
brush = new SolidBrush(brushColor);
g = this.CreateGraphics();
g.FillRectangle(brush, 108, 136, 20, waterBottom - 136 - waterHeight);
waterHeight += 1f;
g.FillRectangle(brush, 51, waterBottom - waterHeight, 299, waterHeight - lastWaterHeight);
lastWaterHeight = waterHeight;
}
else
{
SpeedTimer.Stop();
waterHeight = 0;
lastWaterHeight = 0;
brush = new SolidBrush(Color.Black);
g.FillRectangle(brush, 51, 136, 299, 364);
}
}
private void Speed_Scroll(object sender, EventArgs e)
{
if (waterHeight < 270)
{
float scrollValue = Speed.Value;
fillSpeed = 300 / scrollValue;
SpeedTimer.Interval = (int)fillSpeed;
}
else
{
brush = new SolidBrush(Color.Black);
g.FillRectangle(brush, 51, 230, 299, 270);
SpeedTimer.Start();
}
}
private void ColorButton_Click(object sender, EventArgs e)
{
SetColor.ShowDialog();
brushColor = SetColor.Color;
}
}
}
OK, my first answer was completely wrong, must have read the question wrong, sorry.
The answer still comes down to your MainForm_Paint event, though. This event is fired whenever the form is drawn or redrawn, and includes anything on it (like your buttons). When your mouse hovers over an element it needs to be redrawn, as well as any of its parents, right back to the form level. It also occurs if the form is resized, comes back into view after being hidden (either partially or completely), goes off screen and comes back on, etc, etc. Lots of different things will trigger a form's Paint event to fire. And in your MainForm_Paint event, you have this line:
SpeedTimer.Start();
...which causes the timer to start and everything starts all over again.
Instead of using MainForm_Paint, I'd probably suggest you use the form's Load event to set up all these initial conditions. That will only fire once after the form has initialised and is shown on screen.
Sorry for my eng. Im quite new to C#, and i need this:
After clicking a button, a rectangle form with pre-determined size will appear;
This rectangle must move all around the form + move on screen even if the form is minimized;
The retangle must follow the mouse movements;
When i make a mouse click on the place of screen i want, i need that all coordinates of the area of the rectangle are stored in variables.
This coordinates of rectangle will later be checked by a read-pixel code that i already have, so i really need that the rectangle area of where i clicked really be stored in variables.
EDIT:
Im really new to c# and what i have done so far is:
private void button5_Click(object sender, EventArgs e)
{
Graphics dc = this.CreateGraphics();
Pen Bluepen = new Pen(Color.Blue, 3);
dc.DrawRectangle(Bluepen, 0, 0, 50, 50);
}
And:
private void button5_MouseMove(object sender, MouseEventArgs e)
{
if (isMouseDown == true)
{
rect.Location = e.Location;
if (rect.Right > pictureBox1.Width)
{
rect.X = pictureBox1.Width - rect.Width;
}
if (rect.Top < 0)
{
rect.Y = 0;
}
if (rect.Left < 0 )
{
rect.X = 0;
}
if (rect.Bottom > pictureBox1.Height)
{
rect.Y = pictureBox1.Height - rect.Height;
}
Refresh();
}
}
Thanks in advance!!
How to draw image on tabPage overlapping buttons
Black circles(DrawImage on tabPage8_Paint) should be above the buttons:
http://rghost.ru/6sVBl8mkh/image.png
It must be so:
http://rghost.ru/6BgDM77pq/image.png
My code
public SibModem() {
InitializeComponent();
tabPage8.Paint += new PaintEventHandler(tabPage8_Paint);
gettime();
this.SizeChanged += new EventHandler(this.SibModem_Resize);
}
protected void tabPage8_Paint(object sender, PaintEventArgs e) {
GraphicsUnit units = GraphicsUnit.Pixel;
base.OnPaint(e);
Graphics g = e.Graphics;
g.DrawImage(bg, 0, 0);
Rectangle srcRect = new Rectangle(offsetant, 0, w, h);
g.DrawImage(anten, x, y, srcRect, units);
Rectangle ussdwaitRect = new Rectangle(offsetussd, 0, 64, 64);
g.DrawImage(ussdwait, usx, usy, ussdwaitRect, units);
}
You can't draw above nested controls, so you need to draw parts of the image onto those Buttons.
So combine drawing onto the tabpage and drawing onto the buttons you need to adorn!
Here is a simple example using only one image:
A few class level variables:
Point iLoc = Point.Empty;
Image img = null;
List<Button> overlaidButtons = new List<Button>();
Prepare the image, its position and a list of possibly overlaid buttons:
public Form1()
{
InitializeComponent();
string imgN = #"d:\scrape\gears\gear_12x4hand.png";
img = Image.FromFile(imgN);
iLoc = new Point(100, 100);
overlaidButtons.AddRange(new []{button10,button11,button12,button13 });
// each button calls the same paint event
foreach (Button btn in overlaidButtons) btn.Paint += btn_Paint;
}
The common Paint event. We calculate the relative position of the image..
void btn_Paint(object sender, PaintEventArgs e)
{
Button btn = sender as Button;
e.Graphics.DrawImage(img, new Point(iLoc.X - btn.Left, iLoc.Y - btn.Top));
}
Note that if the Buttons are nested deeper you need to adapt the calculation to include all levels of nesting!
The TabPage Paint event:
private void tabPage5_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(img, iLoc);
}
Try BringToFront method, it brings the control to the front of the z-order.
See this reference on MSDN: https://msdn.microsoft.com/en-us/library/system.windows.forms.control.bringtofront(v=vs.110).aspx
Everytime I try to add a new line or move the paddle in this game the screen flickers.
How do I keep the screen from flickering when I move the paddle or add a line?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class GameTest : Form
{
int dx=3, dy=3, i =500, o = 100;
int rex = 400, rey = 450 ;
double c =0;
public GameTest()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
Invalidate();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
Graphics g = this.CreateGraphics();
if (e.KeyCode == Keys.Left)
{
//Graphics g = this.CreateGraphics();
Invalidate();
Brush black = new SolidBrush(Color.White);
g.FillRectangle(black, rex, rey, 200, 20);
rex -= 40;
Brush red = new SolidBrush(Color.Green);
g.FillRectangle(red, rex, rey, 200, 20);
}
if (e.KeyCode == Keys.Right)
{
//Graphics g = this.CreateGraphics();
Brush white = new SolidBrush(Color.White);
g.FillRectangle(white, rex, rey, 200, 20);
rex += 40;
Brush red = new SolidBrush(Color.Green);
g.FillRectangle(red, rex, rey, 200, 20);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
DoubleBuffered = false;
Graphics g = this.CreateGraphics();
// Bitmap bmp1 = new Bitmap("G:\c#\Bouncing ball\Pic.jpg");
//TextureBrush tb2 = new TextureBrush(bmp1);
Brush green = new SolidBrush(Color.Green);
g.FillRectangle(green, rex, rey, 200, 20);
Graphics b= this.CreateGraphics();
Brush red = new SolidBrush(Color.Red);
b.FillEllipse(red, i, o, 20, 20);
Pen p = new Pen(Color.Black, 10);
//
g.DrawLine(p, 1000, 480,0,480);
g.DrawLine(p, 1000, 485, 1000, 0);
g .DrawLine(p, 0,480, 0, 0);
}
private void timer1_Tick(object sender, EventArgs e)
{
DoubleBuffered = false;
// int dx=3, dy=3, i = 300, o = 50;
i += dx;
if (i < 0)
{
dx = -dx;
}
else if (i + 50 > 1000)
{
dx = -dx;
}
o += dy;
if ((o +20>= rey) &&(i+20<=rex+200)&&(i+20>=rex))
{
//int rex = 400, rey = 450; RECTANGLE
// int dx=3, dy=3, i(x) = 500, o(y) = 100;
dy =-dy;
//c++;
//label1.Text = c.ToString();
}
// Misgeret\\
if (o < 0)
{
dy = -dy;
}
// Misgeret\\
else if (o + 50 > 600)
{
dy = -dy;
}
this.Invalidate();
}
private void label1_Click(object sender, EventArgs e)
{
label1.Text = c.ToString();
}
}
}
I noticed that you are setting DoubleBuffered to false in multiple areas of your program. That is definitely not helping since the whole reason to use double buffering is to prevent flickering.
The other thing is you are creating Graphics contexts and drawing in multiple places in your application. Try to refactor your code to only draw in the OnPaint() event handler of the form, and do not create a new Graphics context. Use the one provided in the PaintEventArgs of the OnPaint() event.
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
using(Brush green = new SolidBrush(Color.Green))
{
g.FillRectangle(green, rex, rey, 200, 20);
}
// .. etc, etc..
}
Then, when you need to the form to be repainted you just need to invoke the Invalidate() method to tell the GDI that your form, or a portion of it, needs to be repainted. That will in turn cause the Paint event to be fired and the OnPaint() to be called.
As a side note, as #HighCore suggested in the comments, WinForms is definitely not the right framework to create a game in. For games try the XNA framework, or one of several open source ones available on the web such as Unity
UPDATE
To prevent flickering you can use automatic double buffering for your form. This can be enabled in the form constructor, after the call to InitializeComponent(), using a call to SetStyle:
SetStyle( ControlStyles.AllPaintingInWmPaint
| ControlStyles.UserPaint
| ControlStyles.DoubleBuffer , true);