This little program opens a windows form and draws 70 red rectangles, where the user clicks on the form.
Every time the user clicks, the rectangles disappear, and new ones are drawn on the new click-Point.
I want to make the rectangles to stay when the user clicks and draws a new set of rectangles.
How do i do that?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace tegnRektangel
{
public partial class Form1 : Form
{
int x;
int y;
bool mouseClicked = false;
Graphics g = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
}
private void Form1_Resize(object sender, EventArgs e)
{
Invalidate();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
if (mouseClicked)
{
g = panel1.CreateGraphics();
paintRectangel();
}
}
private void paintRectangel()
{
for (int i = 1; i <= 70; i++)
{
g.DrawRectangle(Pens.Red, x - 50-i*5, y - 40-i*5, 100, 80);
}
g.Dispose();
}//end paint
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
mouseClicked = true;
Point clickPoint = new Point(e.X,e.Y);
x = clickPoint.X;
y = clickPoint.Y;
panel1.Invalidate();
}
}
}
From MSDN:
The Graphics object that you retrieve through the CreateGraphics
method should not normally be retained after the current Windows
message has been processed, because anything painted with that object
will be erased with the next WM_PAINT message.
You can work around it like this:
In the click event, add the (x, y) coordinate to a list of coordinates.
In the paint event, iterate all these (x, y) coordinates and paint each rectangle.
Here is some code to demonstrate creating rectangles for each click, storing them, and painting all stored rectangles.
public partial class Form1 : Form
{
private List<Rectangle> Rectangles { get; set; }
public Form1()
{
InitializeComponent();
Rectangles = new List<Rectangle>();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (Rectangles.Count > 0)
e.Graphics.DrawRectangles(Pens.Red, Rectangles.ToArray());
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
for (int i = 1; i <= 70; i++)
{
Rectangles.Add(new Rectangle(e.X - 50 - i * 5, e.Y - 40 - i * 5, 100, 80));
}
Invalidate();
}
}
Related
I've created a windows form that when I click on a button, it shows a panda moving.
It works when I add one Panda, but I want another panda to appear on button click. I'm trying to when I click the button for another time to show another panda! When I click the button my panda disappear and reappear again from it's start point and starts moving!
(for example clicking the button 3 times = having 3 pandas moving in my form)
That's the code for the class called "panda":
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace test_moving_pic
{
class panda
{
public Image img_panda;
public Rectangle rect_panda;
public panda(Image img, Rectangle rect)
{
this.img_panda = img;
this.rect_panda = rect;
}
}
}
and this is the code that I used for my Form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test_moving_pic
{
public partial class Form1 : Form
{
Image image;
Rectangle rect;
int direction = 3;
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
if (image != null && rect != null)
g.DrawImage(image, rect);
}
private void timer1_Tick(object sender, EventArgs e)
{
rect.X += this.direction;
rect.Y += this.direction;
if (rect.X <= 100 && rect.Y <= 100)
{
rect.X += this.direction;
rect.Y += this.direction;
}
else
{
rect.Y += this.direction;
if (rect.Y >= 100)
{
rect.Y = 100;
rect.X += this.direction;
}
}
Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
panda p = new panda(Image.FromFile("C:\\Users\\hsnha\\OneDrive\\Desktop\\Panda.png"), new Rectangle(20, 20, 70, 70));
image = p.img_panda;
rect = p.rect_panda;
}
}
}
Try this:
public partial class Form1 : Form
{
List<panda> pandaList = new List<panda>();
int direction = 3;
class panda
{
public Image img_panda;
public Rectangle rect_panda;
public panda(Image img, Rectangle rect)
{
this.img_panda = img;
this.rect_panda = rect;
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
foreach (panda p in pandaList)
g.DrawImage(p.img_panda, p.rect_panda);
}
private void timer1_Tick(object sender, EventArgs e)
{
foreach (panda p in pandaList)
{
p.rect_panda.X += this.direction;
p.rect_panda.Y += this.direction;
if (p.rect_panda.X <= 100 && p.rect_panda.Y <= 100)
{
p.rect_panda.X += this.direction;
p.rect_panda.Y += this.direction;
}
else
{
p.rect_panda.Y += this.direction;
if (p.rect_panda.Y >= 100)
{
p.rect_panda.Y = 100;
p.rect_panda.X += this.direction;
}
}
}
Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
pandaList.Add(new panda(Image.FromFile(#"C:\Users\hsnha\OneDrive\Desktop\Panda.png"), new Rectangle(20, 20, 70, 70)));
}
}
Form1_Paint is only going to draw one panda. You need to somehow save all the pandas you've created, and draw all of the pandas in the Paint method! You also need to update the position of all pandas in Tick.
For example:
Define a member in your class List<panda> pandas; and
private void button1_Click(object sender, EventArgs e)
{
panda p = new panda(Image.FromFile("C:\\Users\\hsnha\\OneDrive\\Desktop\\Panda.png"), new Rectangle(20, 20, 70, 70));
pandas.Add(p);
}
private void timer1_Tick(object sender, EventArgs e)
{
foreach (panda p in pandas)
{
Rectangle rect = p.rect_panda;
// Fix the rect like before
}
}
And similarly for Draw, loop over the pandas and draw each. Does this help you get unstuck?
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 UTUResultWithCoordinates
{
public partial class GetCoordinates : Form
{
private string sem;
private string branch;
private int mouseisdown = 0;
private int recx = 0;
private int recy = 0;
private int mousemovingwhilepressed = 0;
public GetCoordinates()
{
InitializeComponent();
}
public GetCoordinates(string p, string p_2)
{
// TODO: Complete member initialization
InitializeComponent();
branch = p;
sem = p_2;
pictureBox1.Controls.Add(pictureBox2);
pictureBox2.Location = new Point(0, 0);
pictureBox2.BackColor = Color.Transparent;
pictureBox2.Width = 1191;
pictureBox2.Height = 842;
}
private void GetCoordinates_Load(object sender, EventArgs e)
{
pictureBox1.ImageLocation = #"D:\DotNet\UTUResultWithCoordinates\UTUResultWithCoordinates\bin\Debug\ComputerScience6.jpg";
}
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
if (mouseisdown == 1 && mousemovingwhilepressed==1)
{
System.Drawing.Graphics graphicsObj;
graphicsObj = this.CreateGraphics();
Pen myPen = new Pen(System.Drawing.Color.Blue, 100);
Rectangle myRectangle = new Rectangle(recx, recy, 20, 20);
e.Graphics.DrawRectangle(myPen, myRectangle);
}
}
private void pictureBox2_MouseDown(object sender, MouseEventArgs e)
{
mouseisdown = 1;
recx = e.X;
recy = e.Y;
pictureBox2.CreateGraphics();
}
private void pictureBox2_MouseMove(object sender, MouseEventArgs e)
{
label1.Text = e.X + "," + e.Y;
mousemovingwhilepressed = 1;
recx = e.X;
recy = e.Y;
pictureBox2.CreateGraphics();
}
private void pictureBox2_MouseUp(object sender, MouseEventArgs e)
{
mousemovingwhilepressed = 0;
mouseisdown = 0;
pictureBox2.CreateGraphics();
}
}
}
I have created a pictureBox1 in which an image is displayed. Then I have created a pictureBox2 inside it so that I can paint on that image a rectangle by dragging the mouse. But nothing is happening on clicking the mouse. What is the error?
Calling CreateGraphics does not trigger the painting of the PictureBox.
Use Invalidate to cause a redraw.
For a full example see: How to select an area on a PictureBox.Image with mouse in C#
Side notes:
Calling InitializeControl in a method other than the constructor is not a good idea.
when you need a boolean use a boolean, not an integer.
Objects that implement IDisposable (such as Pen) should be created as few times as possible and be disposed when no longer needed/used.
I have a panel and a richTextBox placed at the bottom corner of the panel. Panel takes text from richTextBox and Draws using DrawString() on the panel using its paint event.
When the panel is filled it does not auto-scroll the panel even if autoscroll=true.
How to enable scrollings to a paint event handling panel?
How to reflect the scrolling of richTexBox in a panel(if richtextbox is scrolled to some extent, the panel should also be scrolled to the same extent?)
In short the visible content of richtextbox must be visible in the panel exactly.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
namespace TextFormatter
{
public partial class Form1 : Form
{
//int scrol;
public Form1()
{
InitializeComponent();
//Set Double Buffering
panel1.GetType().GetMethod("SetStyle",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic)
.Invoke(panel1, new object[] {
System.Windows.Forms.ControlStyles.UserPaint |
System.Windows.Forms.ControlStyles.AllPaintingInWmPaint |
System.Windows.Forms.ControlStyles.DoubleBuffer, true });
}
class myFont
{
public int size;
public string family;
public Color c;
}
myFont f = new myFont();
private void Form1_Load(object sender, EventArgs e)
{
}
private void UpdateStatus()
{
panel1.Refresh();
}
delegate void UpdateStatusInvoker();
private void panel1_Paint_1(object sender, PaintEventArgs e)
{
Point P = new Point();
int w = this.ClientSize.Width;
int h = this.ClientSize.Height;
P.X = w - 180;
P.Y = h - 52;
richTextBox1.Location = (P);
Graphics g = e.Graphics;
Brush b;
b = new SolidBrush(f.c);
if (f.c.IsEmpty)
{
b = new SolidBrush(Color.Brown);
}
Point p = new Point();
p.X = 100;
p.Y = 100;
Font ff = new Font(f.family, f.size | 20);
g.DrawString("" + richTextBox1.Text, ff, b, p);
// richTextBox1.AppendText(
b.Dispose();
// g.Dispose();
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
// Invalidate();
this.Invoke(new UpdateStatusInvoker(UpdateStatus));
}
private void richTextBox1_VScroll(object sender, EventArgs e)
{
// same scrolling must be applied on panel.
}
private void panel1_Scroll(object sender, ScrollEventArgs e)
{
// control the scrolling of graphical content of the panel
}
}
}
I am trying do image slide show with picturebox Control and a trackbar. The trackbar gets minimum and maximum value corresponds to the number of images to show. I use a timer to get interval period for the slide along with trackbar valuechange.
Now, here is the main thing for each image in the picturebox I'm drawing a rectangle box over the image.
I am not able to draw on the first image when the form get load with first image. But I could do if I scroll the mouse wheel.
I need help to trigger the mouse wheel scroll event once after the first image get loaded.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test
{
public partial class Form1 : Form
{
public event MouseEventHandler MouseWheel;
//MouseEventArgs k = new MouseEventArgs(MouseButtons.Middle,0,0,-1);
string[] pics = { "C:\\Downloads\\folder_picture_green.png", "C:\\Downloads\\Aetherpal.ico", "C:\\Downloads\\folder_picture_green.png" };
public Form1()
{
InitializeComponent();
this.trackBar1.Minimum = 0;
this.trackBar1.Maximum = (pics.Count() - 1);
//this.trackBar1.Maximum = 0;
imageupdate(0);
timer1.Start();
timer1.Interval = 3000;
this.MouseWheel += test;
this.MouseWheel(null, null);
}
private void test(object sender, System.Windows.Forms.MouseEventArgs e)
{
MessageBox.Show("Scrolled");
}
private void check(object sender, System.EventArgs e)
{
//if (Initializing == false) { return; }
if(this.trackBar1.Value < this.trackBar1.Maximum )
this.trackBar1.Value += 1;
else
timer1.Stop();
}
private void Valuechange(object sender, System.EventArgs e)
{
imageupdate(this.trackBar1.Value);
if(this.trackBar1.Value < this.trackBar1.Maximum)
timer1.Start();
}
private void imageupdate(int k)
{
this.pictureBox1.Refresh();
this.pictureBox1.Image = new Bitmap(pics[k]);
Pen blackPen = new Pen(Color.Blue, 5);
this.pictureBox1.Refresh();
using (Graphics g = this.pictureBox1.CreateGraphics())
{
g.DrawRectangle(blackPen, 10, 10, 100, 50);
}
}
}
}
You can add this code to your form to scroll your form (of course with MouseWheel):
private void Wheel(int ticks, bool down){
//WM_MOUSEWHEEL = 0x20a
Message msg = Message.Create(Handle, 0x20a, new IntPtr((down ? -1 : 1)<<16), new IntPtr(MousePosition.X + MousePosition.Y << 16));
for(int i = 0; i < ticks; i++)
WndProc(ref msg);
}
//Use it
Wheel(120,true);//Wheel down
Wheel(120,false);//Wheel up
NOTE: I can see you define a MouseWheel event in your own form. This will hide the base MouseWheel event, I don't think you have any reason to do this, your own MouseWheel can't work as the base one, you have to catch the win32 message and raise it yourself, we should use the base MouseWheel event instead. (Maybe you thought there isn't any MouseWheel event in your form class?)
I am trying to write a drawing program for use with a tablet. For this I need fall-off and transparency for use with pressures. So I am using the bitmap system in C# for image construction.
I cannot seem to get my drawing code at the moment to display anything. It is being rendered to a picture box. I know there is some stuff being input to the bitmap as it shows up when I do a bitmap save.
I have had a look around an pretty much all C# drawing questions refer to using the line drawing or ellipse drawing stuff as opposed to bitmaps
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 paint1
{
public partial class Form2 : Form
{
public Bitmap m_bitmap;
public bool m_penDown;
public int m_lastX;
public int m_lastY;
public int m_currentX;
public int m_currentY;
public Form2()
{
InitializeComponent();
// Create the bitmap area
m_bitmap = new Bitmap(this.Width, this.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
m_penDown = false;
Graphics m_graphics = Graphics.FromImage(m_bitmap);
m_lastX = System.Windows.Forms.Cursor.Position.X;
m_lastY = System.Windows.Forms.Cursor.Position.Y;
m_currentX = System.Windows.Forms.Cursor.Position.X;
m_currentY = System.Windows.Forms.Cursor.Position.Y;
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void Form2_Paint(object sender, PaintEventArgs e)
{
Graphics objGraphics;
//You can't modify e.Graphics directly.
objGraphics = e.Graphics;
// Draw the contents of the bitmap on the form.
objGraphics.DrawImage(m_bitmap, 0, 0,
m_bitmap.Width,
m_bitmap.Height);
objGraphics.Dispose();
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
m_penDown = true;
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
m_penDown = false;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
m_lastX = m_currentX;
m_lastY = m_currentY;
m_currentX = System.Windows.Forms.Cursor.Position.X;
m_currentY = System.Windows.Forms.Cursor.Position.Y;
if(m_penDown)
m_bitmap.SetPixel(m_currentX, m_currentY, Color.Gray);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Form2_Paint(sender, e);
this.pictureBox1.Image = m_bitmap;
}
private void Form2_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space)
{
m_bitmap.Save(#"C:\Users\rpettefar\Documents\My Dropbox\Programming\paint1\preview.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
}
}
}
}
I am a bit new to c# so I am very open to any other issues or things that may come to your attention too.
You will have to assign your bitmap to the picture box.
myPictureBox.Image = m_bitmap;
You can do that after you changed the bitmap or assign it once and then invalidate your PictureBox.
myPictureBox.Invalidate();
This tells your form to refresh the picture on the screen. There is no need to override OnPaint. Draw to the bitmap using the Graphics object you created in the constructor of the form (if you want to make more complicated things than just drawing single pixels). The PictureBox will do the rest.
It looks like there's at least two ways you're trying to get the image on screen; can't say immediately what's wrong, but I would say definitely get rid of that objGraphics.Dispose(); line - you didn't create the Graphics (you were passed it), so you shouldn't Dispose it.
I cleaned up your code a bit. You probably shouldn't use a picturebox for this.
Here is a form with just a panel:
public partial class Form1 : Form
{
public Bitmap m_bitmap;
public Point m_lastPoint = Point.Empty;
public Form1()
{
InitializeComponent();
m_bitmap = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(m_bitmap))
g.Clear(SystemColors.Window);
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(m_bitmap, new Point(0, 0));
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
m_lastPoint = e.Location;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
using (Graphics g = Graphics.FromImage(m_bitmap))
g.DrawLine(Pens.Black, m_lastPoint, e.Location);
m_lastPoint = e.Location;
panel1.Invalidate();
}
}
}
The other posters have largely answered the question, but in my experience, I'd add that you'll likely get some flicker with this method. If you do, one thing you can do to help with this is sub-class your rendering target and enable double buffering. For a picture box, it would look something like this:
public class DoubleBufferedPictureBox : PictureBox
{
/// <summary>
/// Creates an instance of the DoubleBufferedPictureBox.
/// </summary>
public DoubleBufferedPictureBox() : base()
{
this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true);
}
}