I have a panel containing multiple picturebox.
I want to give users the option of selecting any part of any picturebox.
The user will select it by mouse.
I want to draw a semi-transparent rectangle on the picturebox while the mouse move as per the selection.
The code is working fine, but the rectangle is flickering. I want to stop the flickering.
I tried double buffer using how to stop flickering C# winforms
Also, added Invalide using How to force graphic to be redrawn with the invalidate method
But not working. Please help.
My Code:
private Brush selectionBrush = new SolidBrush(Color.FromArgb(70, 76, 255, 0));
private void Picture_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
PictureBox pb = (PictureBox)(sender);
Point tempEndPoint = e.Location;
Rect.Location = new Point(
Math.Min(RecStartpoint.X, tempEndPoint.X),
Math.Min(RecStartpoint.Y, tempEndPoint.Y));
Rect.Size = new Size(
Math.Abs(RecStartpoint.X - tempEndPoint.X),
Math.Abs(RecStartpoint.Y - tempEndPoint.Y));
pb.CreateGraphics().FillRectangle(selectionBrush, Rect);
pb.Invalidate(Rect);
}
This does not address the PictureBox, but maybe helps.
First I replaced the PictureBox with Panel which can also be used to draw pictures. Next I activated double buffering:
somewhere in the namespace add this class:
class DoubleBufferedPanel : Panel
{
public DoubleBufferedPanel() : base()
{
DoubleBuffered = true;
}
}
and then replace in
Form1.Designer.cs
all "System.Windows.Forms.Panel" with "DoubleBufferedPanel".
this works fine in many of my graphical applications.
You indicate the Double Buffering solution doesn't work for you, did you find out why? Because the following custom control draws a sizable rectangle on the picturebox without the flicker:
public class TryDoubleBufferAgain : PictureBox
{
public TryDoubleBufferAgain()
{
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.UpdateStyles();
}
protected override void OnMouseMove(MouseEventArgs e)
{
this.Refresh();
base.OnMouseMove(e);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Edit below to actually draw a usefull rectangle
e.Graphics.DrawRectangle(System.Drawing.Pens.Red, new System.Drawing.Rectangle(0, 0, Cursor.Position.X, Cursor.Position.Y));
}
}
Related
I am trying to draw circles using Bitmap.
Each time I click the mouse, the circle I previously drew is moved to the new position.
What I want to happen is: Each time I click the mouse, a new circle is created/drawn at the position I clicked and all previously drawn circles remain without moving.
I am working with the following code:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace multirectangle
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
Bitmap background;
Graphics scG;
Rectangle rectangleObj;
private Point clickCurrent = Point.Empty;
private Point clickPrev = Point.Empty;
private void Form1_Load(object sender, EventArgs e)
{
background = new Bitmap(Width, Height);
rectangleObj = new Rectangle(10, 10, 30, 30);
scG = Graphics.FromImage(background);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
clickCurrent = PointToClient(Cursor.Position);
clickPrev = clickCurrent;
if (clickPrev == Point.Empty) return;
rectangleObj.X = clickPrev.X - rectangleObj.Height / 2;// +radius;
rectangleObj.Y = clickPrev.Y - rectangleObj.Width / 2;
Refresh();
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.DrawImage(Draw(), 0, 0);
}
public Bitmap Draw()
{
Graphics scG = Graphics.FromImage(background);
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
scG.Clear(SystemColors.Control);
scG.DrawEllipse(myPen, rectangleObj);
return background;
}
}
}
Your English was a little confusing. If I'm understanding your problem correctly, right now the only thing that's being drawn is the new circle where the click was, and you want all the old ones to persist as well? In which case, there are two options:
Don't clear the bitmap before you draw. scG.Clear(SystemColors.Control); will clear the bitmap you just drew. If you remove that line and don't clear the bitmap, then the next time you click, it will then draw the new ellipse right on top of the last bitmap.
If you want a fresh drawing/bitmap everytime, you would need a list of your rectangleObj . Each time you click, you add that point to your rectangleObj collection. Then in your draw method, you would iterate through the collection and draw all of them.
I notice a few things. First, in Form1_MouseDown(), you have this:
clickCurrent = PointToClient(Cursor.Position);
clickPrev = clickCurrent;
You are overwriting the old position (clickPrev) before you even save it. If you want to keep both positions, you should put them in a simple structure, like a List. When you get a new point, just Add() it to the list. Then, in your Draw() routine, loop over all the elements in the list and draw them all.
If you just want two positions--and only two--just swap your statements like this:
clickPrev = clickCurrent;
clickCurrent = PointToClient(Cursor.Position);
And you'll have to allocate another rectangle object for the drawing, although it would make more sense to take care of this in the Draw() routine.
Swap the position of the following statements
clickCurrent = PointToClient(Cursor.Position);
clickPrev = clickCurrent;
I think you are assigning the clickCurrent to clickPrevious after you initialize clickCurrent. It needs to be the other way.
Please try this
Rectangle rectangleObj;
Bitmap background;
Graphics scG;
Pen myPen;
private void Form1_Load(object sender, EventArgs e)
{
rectangleObj = new Rectangle(10, 10, 30, 30);
background = new Bitmap(Width, Height);
scG = Graphics.FromImage(background);
myPen = new Pen(Color.Red, 3);
BackgroundImage = background;
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
var point = PointToClient(Cursor.Position);
rectangleObj.X = point.X - rectangleObj.Height / 2;
rectangleObj.Y = point.Y - rectangleObj.Width / 2;
scG.DrawEllipse(myPen, rectangleObj);
Refresh();
}
OnPaint and Draw methods removed. As well as clickCurrent and clickPrev fields.
When you change the form size (for example, maximize it), Bitmap and Graphics remain the same, so you get this effect. To avoid this, you need to add the event handler
private void Form1_SizeChanged(object sender, EventArgs e)
{
background = new Bitmap(Width, Height);
scG = Graphics.FromImage(background);
BackgroundImage = background;
}
Note that each time you resize the form, all previously drawn is erased. If this is undesirable, a different approach is needed for drawing. Let me know, I will give another example.
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
The problem isn't that I don't know how to make a border-less form re-sizable, or to how to draw a border. The problem is what happens when you re-size the form with that custom border.
Here is a screenshot, because I don't know how to explain it:
Here is how I created the border (currently):
private void Form1_Paint(object sender, PaintEventArgs e)
{
int width = 1;
Rectangle rec = this.ClientRectangle;
ButtonBorderStyle bbs = ButtonBorderStyle.Solid;
Color clr = Color.Gray;
ControlPaint.DrawBorder(e.Graphics, rec, clr, width, bbs, clr, width, bbs, clr, width, bbs, clr, width, bbs);
}
As for re-sizing a border-less form; I created a repository for the project.
Resize Custom Border - Bitbucket
I don't have any idea as to why this happens, so I wouldn't know where to begin. I just need to draw a border without it doing this. I have tried other ways of drawing one, but the results were the same.
Hopefully this and the repository becomes useful for anyone trying to do the same.
Thank you for taking your time to read if you did.
Try to use Graphics.DrawRectangle instead of DrawBorder
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Single fWidth = 5.0f;
Rectangle r = new Rectangle(0,0,this.ClientRectangle.Width-1,this.ClientRectangle.Height-1);
e.Graphics.DrawRectangle(new Pen(Color.Gray, fWidth), r);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.Invalidate();
}
Use Graphic library :
Step 1: Override the OnPaint handler for your main form
Step 2: Define a rectangle that covers your current form
Step 3: Draw the defined rectangle
protected override void OnPaint(PaintEventArgs e)
{
Rectangle r = new Rectangle(0,0,this.ClientRectangle.Width-1,this.ClientRectangle.Height-1);
e.Graphics.DrawRectangle(new Pen(Color.Gray, 1.0f), r);
}
You may also implement this using a condition statement like:
this.form.Resize += // some handler1
//in hadler1
{
this.form.Paint += // Your new paint handler2
}
//in handler2
{
Rectangle r = new Rectangle(0,0,this.ClientRectangle.Width-1,this.ClientRectangle.Height-1);
e.Graphics.DrawRectangle(new Pen(Color.Gray, 1.0f), r);
}
I have a pictureBox1 with image inside and when i click on it its drawing points.
Now i added a reset button i called it when i click on it its should clear all the drawings i did on the pictureBox and leavethe image inside without the drawings on it.
I did:
private void button4_Click(object sender, EventArgs e)
{
Graphics graphics;
graphics = pictureBox1.CreateGraphics();
graphics.DrawImage(pictureBox1.Image, 0, 0);
}
So i draw a lot of points on pictureBox1 then click the button and all points are gone but then once i click on the picturebox1 again i see also the new points but also the old points i did before the clearing.
How can i clear the old drawings so it wont show up on the next clicks ?
This is the paint event: Moved the paint event to a new class:
public static void Paint(List<PointF> pb1points, GraphicsPath pb1gp, Point movingPoint, PictureBox pictureBox1, Graphics e)
{
e.Clear(Color.White);
e.DrawImage(pictureBox1.Image, movingPoint);
Pen p;
p = new Pen(Brushes.Green);
foreach (PointF pt in pb1points)
{
e.FillEllipse(Brushes.Red, pt.X, pt.Y, 3f, 3f);
}
using (Pen pp = new Pen(Color.Green, 2f))
{
pp.StartCap = pp.EndCap = LineCap.Round;
pp.LineJoin = LineJoin.Round;
e.DrawPath(pp, pb1gp);
}
}
You can try using Graphics.Clear().
Reference: http://msdn.microsoft.com/en-us/library/system.drawing.graphics.clear(v=vs.110).aspx
setting the Image property to null should work.
picBox.Image = null;
Ii it's not worked ,you might be used the InitialImage property to display your image.
pictBox.InitialImage = null;
Please refer the link:
Clear image on picturebox
This is working:
private void button4_Click(object sender, EventArgs e)
{
Graphics graphics;
graphics = pictureBox1.CreateGraphics();
graphics.DrawImage(pictureBox1.Image, 0, 0);
pb1points = new List<PointF>();
}
I have a UserControl that contains a PictureBox and a Label. The Control loads three different images in PictureBox on different events (fore example onMouseEnter, OnMouseLeave). As the images can have different sizes, I neet to resize the pictureBox and
the control itself. Below is provided the control's OnPaint event but this does not work.
protected override void OnPaint(PaintEventArgs pe)
{
if (pictureBox.Image != null)
{
this.Width = this.pictureBox.Image.Size.Width;
this.Height = this.pictureBox.Image.Size.Height;
CutRoundedRectangle2(pictureBox, cornerRadius);
}
else
{
Bitmap DrawArea = new Bitmap(pictureBox.Size.Width, pictureBox.Size.Height);
Graphics g = Graphics.FromImage(DrawArea);
Pen mypen = new Pen(Color.Black);
pictureBox.Image = DrawArea;
System.Drawing.Pen pen = new Pen(new SolidBrush(this.ForeColor));
g.DrawRectangle(pen, 0, 0, this.Width-1, this.Height-1);
g.Dispose();
}
this.labelText.ocation = new Point((this.pictureBox.Width - this.labelText.Width) / 2,
(this.pictureBox.Height - this.labelText.Height) / 2);
base.OnPaint(pe);
}
The pictureBox SizeMode is set in control's constuctor:
this.pictureBox.SizeMode = PictureBoxSizeMode.AutoSize;
It was long time ago when I worked with WinForms last time, but ...
My first thought is: have you tried set value of parent control's AutoSize property to 'true' and AutoSizeMode to GrowAndShrink and call parent control's Refresh() method when new image is loaded to picture box?
#Alexey, the pictureBox resize event helped!
private void pictureBox_Resize(object sender, EventArgs e)
{
this.Width = this.pictureBox.Image.Size.Width;
this.Height = this.pictureBox.Image.Size.Height;
}