How to Bring the Border of a Picturebox to Front? - c#

I am making a border around a picture box by simply drawing a rectangle around it. However since there is a panel behind the picturebox, I cannot see the border around the picturebox (despite the fact that I have drawn the border around the picture. Here's the code:
private void Form1_Load(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Maximized;
Graphics objGraphics = null;
objGraphics = this.CreateGraphics();
objGraphics.Clear(SystemColors.Control);
objGraphics.DrawRectangle(Pens.Blue,
ileriresmi.Left - 1, ileriresmi.Top - 1,
ileriresmi.Width + 1, ileriresmi.Height + 1);
objGraphics.Dispose();
}

you may try this..but it will draw inside the picture box
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(new Pen(Color.Red, 2f),0,0,pictureBox1.Size.Width-2, pictureBox1.Size.Height-2);
}
Complete solution will be like this.
add this class into your application and build application.
public class PicExt : PictureBox
{
private Color _borderColor;
private int _borderWidth;
[Browsable(true)]
public Color BorderColor {
get { return _borderColor; }
set { _borderColor = value; this.Invalidate(); }
}
[Browsable(true)]
public int BorderWidth {
get { return _borderWidth; }
set { _borderWidth = value; this.Invalidate(); }
}
public PicExt()
{
_borderColor = Color.Red;
_borderWidth = 3;
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
pe.Graphics.DrawRectangle(new Pen(BorderColor, BorderWidth), BorderWidth, BorderWidth, this.Size.Width - (BorderWidth*2), this.Size.Height - (BorderWidth*2));
}
}
after building application you will see new control "PicExt" in your toolbox.
replace pictureBox with PicExt Control
and subscribe the click event like this.
private void button1_Click(object sender, EventArgs e)
{
//set the color here
picExt1.BorderColor = Color.Red;
//and frame width
picExt1.BorderWidth = 5;
}
it should work like exactly you want.

There are a couple things wrong here. First, you're doing your drawing on the form, which is covered by the panel you mention, and second, you're only drawing the border once, in the Load event, rather than every time the form receives a WM_PAINT message.
See here for an explanation of why the latter is wrong.
As for getting the border drawn in the right place, why not just set the BackColor of the panel that holds the PictureBox to Color.Blue and give that panel a nonzero value for Padding? (Or, if the panel contains other controls, add an intermediate panel just for the border.)

Related

How to pass parameters in C# GDI+ Windows Desktop

I'm interested in learning about C# GDI+ and have googled many tutorials. I'm attempting to create a simple windows form that has two textbox controls and a button. I simply want to put a length dimension in one textbox and a height dimension in the other, click the button and have the app draw the rectangle on the window using those two entered dimensions. To date, all I have been able to do is locate tutorials where the rectangle parameters are hardcoded into the Form_Load and Form_Paint. How would I take the user input from the textboxes and pass them to make the app refresh and draw the rectangles on the button click?
Please let me know if more info is needed.
Thanks in advance for your knowledge!
public partial class Form1 : Form
{
Bitmap drwBitmap;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Graphics graphicObj;
drwBitmap = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
graphicObj = Graphics.FromImage(drwBitmap);
graphicObj.Clear(Color.White);
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
Rectangle rectObj;
rectObj = new Rectangle(10, 10, 100, 200);
graphicObj.DrawEllipse(myPen, rectObj);
graphicObj.Dispose();
}
private void Form1_Paint(object sender, PaintEventArgs e, Graphics graphicsObj)
{
Graphics graphicsObj1 = graphicsObj;
graphicsObj1.DrawImage(drwBitmap, 0, 0, drwBitmap.Width, drwBitmap.Height);
graphicsObj.Dispose();
}
The current approach is quite strange as it draws directly to the form. It's difficult to modify as a bitmap is created early on and then must somehow be changed. Furthermore, there is no need for a bitmap.
A better approach is to create a custom control:
public class EllipseControl : Control
{
private float m_ellipseWidth = 200;
private float m_ellipseHeight = 120;
public float EllipseWidth
{
get { return m_ellipseWidth; }
set
{
m_ellipseWidth = value;
Invalidate();
}
}
public float EllipseHeight
{
get { return m_ellipseHeight; }
set
{
m_ellipseHeight = value;
Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var graphics = e.Graphics;
using Pen pen = new Pen(System.Drawing.Color.Red, 3);
graphics.DrawEllipse(pen, 0, 0, EllipseWidth, EllipseHeight);
}
}
This control can then be placed on the form. It has two properties: EllipseWidth and EllipseHeight.
In the event handler for the button click, you can take the values from the text fields and set them on the ellipse control.

draw filled circle in WinForms C#

I have a WinForms application that interacts with a connection. If the connection is fine I want to show a green ("everything is fine") filled circle, if not I want to show a red filled circle.
I found no circle element in the toolbox so I think I have to draw it on my own.
I created a picture box called picBoxClientState and started with this code
public partial class FrmMain : Form
{
public void CheckSignedInState()
{
// some other code
DrawClientStateIcon(client.IsSignedIn);
}
private void DrawClientStateIcon(bool isSignedIn)
{
Point rectangleLocation = picBoxClientState.Location;
Size rectangleSize = picBoxClientState.Size;
Rectangle rectangle = new Rectangle(rectangleLocation, rectangleSize);
Color iconColor = isSignedIn ? Color.Green : Color.Red;
SolidBrush iconBrush = new SolidBrush(iconColor);
Graphics graphics = picBoxClientState.CreateGraphics();
graphics.FillEllipse(iconBrush, rectangle);
}
}
How can I draw on this picturebox whenever I call CheckSignedInState() ?
Maybe there is a better way instead of drawing? (I don't want to toggle two images because there might be more states to draw)
A simple example using a Label control to draw an ellipse.
You can use any control that has a Paint event to draw shapes.
It could also be a Panel, a PictureBox, a Button...
A bool variable (clientIsSignedIn) declared at Class scope is used to keep track of the current status, as reported by your client.IsSignedIn value.
When the status changes, update clientIsSignedIn and Invalidate() the Control that provides the visual aid.
bool clientIsSignedIn = false;
public void CheckSignedInState()
{
// some other code
clientIsSignedIn = client.IsSignedIn;
lblVisualStatus.Invalidate();
}
private void lblVisualStatus_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillEllipse((clientIsSignedIn) ? Brushes.Green : Brushes.Red, ((Control)sender).ClientRectangle);
}
I don't think picture box is necessary. You can try something like this:
private void button1_Click(object sender, EventArgs e)
{
System.Drawing.SolidBrush myBrush = new
System.Drawing.SolidBrush(System.Drawing.Color.Red);
System.Drawing.Graphics formGraphics;
formGraphics = this.CreateGraphics();
formGraphics.FillEllipse(myBrush, new Rectangle(200, 200, 30, 30));
myBrush.Dispose();
formGraphics.Dispose();
}
If you need to draw on picturebox be sure to call picturebox.Invalidate();
your code works, it did seem to draw a bit off center though but also the fact that you weren't disposing of the object could potentially cause issues too. Try using the code below as your DrawClientStateIcon method
Edit: full code example below. I added a button to toggle the state of the client and this works for me.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public class Client
{
public bool IsSignedIn { get; set; }
}
Client client = new Client()
{
IsSignedIn = false
};
public Form1()
{
InitializeComponent();
}
public void CheckSignedInState()
{
// some other code
DrawClientStateIcon(client.IsSignedIn);
}
private void DrawClientStateIcon(bool isSignedIn)
{
Point rectangleLocation = picBoxClientState.Location;
Size rectangleSize = picBoxClientState.Size;
Rectangle rectangle = new Rectangle(rectangleLocation, new Size(rectangleSize.Width / 2, rectangleSize.Height / 2));
Color iconColor = isSignedIn ? Color.Green : Color.Red;
using (SolidBrush iconBrush = new SolidBrush(iconColor))
{
using (Graphics graphics = picBoxClientState.CreateGraphics())
{
graphics.FillEllipse(iconBrush, rectangle);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
client.IsSignedIn = !client.IsSignedIn;
CheckSignedInState();
}
}
}
You need to call it in Form Shown event.
private void FrmGraphics_Shown(object sender, EventArgs e)
{
DrawClientStateIcon(true);
}
private void DrawClientStateIcon(bool isSignedIn)
{
Point rectangleLocation = picBoxClientState.Location;
Size rectangleSize = picBoxClientState.Size;
Rectangle rectangle = new Rectangle(rectangleLocation, rectangleSize);
Color iconColor = isSignedIn ? Color.Green : Color.Red;
SolidBrush iconBrush = new SolidBrush(iconColor);
Graphics graphics = base.CreateGraphics();
graphics.FillEllipse(iconBrush, rectangle);
}

Create rectangle drawing inside the picturebox

After button click event I want the program to draw a rectangle inside a picturebox. I don't know how to do that. So far I made only a rectangle outside of picture box like this. Afterwards I want to implement a flood fill algorithm to fill the rectangle with a color. That's why I have to have those bitmaps there.
namespace howto_floodfill
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// The background image.
private Bitmap bm;
private Bitmap32 bm32;
// Make a rectangle
private void button1_Click(object sender, EventArgs e)
{
bm = new Bitmap(ClientSize.Width, ClientSize.Height);
using (Graphics gr = Graphics.FromImage(bm))
{
gr.Clear(Color.Silver);
gr.DrawRectangle(Pens.Black, 5, 5, 100, 60);
}
bm32 = new Bitmap32(bm);
this.BackgroundImage = bm;
}
}
}
You can set a Paint event handler for the PictureBox that will allow you to do drawing over the top of the PictureBox contents:
public partial class Form1 : Form
{
private bool _drawRectangle = false;
public Form1()
{
InitializeComponent();
pictureBox1.Paint += new PaintEventHandler(this.pictureBox1_Paint);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_drawRectangle) {
Graphics g = e.Graphics;
// use g to do your drawing
}
}
}
Just set _drawRectangle to true in your button click handler and call pictureBox1.Invalidate(). Doing your drawing in the Paint event handler guarantees that whenever the PictureBox is redrawn (say, because another window was over it), your rectangle gets drawn as well.
This will let you draw a rectangle over the PictureBox's contents. Rather than a flood fill algorithm, have you considered just using FillRectangle?
If you really want to do a flood fill, you'll have to work with an image as you're already doing, so you can read pixels from the image to know if a boundary has been reached. Then you could set the PictureBox's Image property with the resulting bitmap. (In this case, it wouldn't be necessary to do the graphics work in the Paint event handler, since the PictureBox will make sure its Image is drawn on every paint.)
You can use the control.CreateGraphics() method invoked from your picturebox.
namespace WindowsFormsApplication_Test
{
public partial class Form1 : Form
{
private Bitmap bm;
public Form1()
{
InitializeComponent();
bm = new Bitmap(pB.ClientRectangle.Width, pB.ClientRectangle.Height);
}
private void btn_Click(object sender, EventArgs e)
{
Graphics gF = pB.CreateGraphics();
gF.Clear(Color.Silver);
gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
}
private void button1_Click(object sender, EventArgs e)
{
Graphics gF = Graphics.FromImage(bm);
gF.Clear(Color.Silver);
gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
pB.Image = bm;
}
}
}
btn_click() is an example of getting the graphics context from the control and drawing directly.
Form prior to clicking...
Clicking the button will draw on the control directly - note that by default it gives you the clientRectangle portion of the control, which is nice...
Clicking on the button gives you this.
Now I resized the form.
Unfortunately, drawing on the form this way makes you responsible for redrawing your data any time the window is invalidated.
You can also just set the Image property of the form to be your private bitmap and then the framework handles redrawing for you. This is shown in the button1_Click() method.
You can still draw directly on the control if you wish, but you'll need to hook into the control events and redraw when the form does. For example, adding a flag as a private bool to the form class, overriding the OnPaint method, and adding code to your button event to swap the flag. Rather than duplicating the drawing code in the button event, you can just flip the flag and call this.Invalidate();
public partial class Form1 : Form
{
private Bitmap bm;
private bool bDrawn = false;
public Form1()
{
InitializeComponent();
bm = new Bitmap(pB.ClientRectangle.Width, pB.ClientRectangle.Height);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (bDrawn)
{
Graphics gF = pB.CreateGraphics();
gF.Clear(Color.Silver);
gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
}
}
private void btn_Click(object sender, EventArgs e)
{
//Graphics gF = pB.CreateGraphics();
//gF.Clear(Color.Silver);
///gF.DrawRectangle(Pens.Black, 5, 5, 100, 60);
bDrawn = true;
this.Invalidate();
}
Assign the created bitmap to the Image property of the picture box. Now you can draw whatever you want on the bitmap, and then manipulate it's data.
namespace howto_floodfill {
public partial class Form1 : Form {
private Bitmap bitmap;
public Form1() {
InitializeComponent();
this.bitmap = new Bitmap(100, 100);
this.pictureBox1.Image = this.bitmap;
}
// Make a rectangle
private void button1_Click(object sender, EventArgs e) {
if (this.bitmap != null) {
this.bitmap.Dispose();
}
this.bitmap = new Bitmap(ClientSize.Width, ClientSize.Height);
using (Graphics gr = Graphics.FromImage(bitmap)) {
gr.Clear(Color.Silver);
gr.DrawRectangle(Pens.Black, 5, 5, 100, 60);
}
this.pictureBox1.Image = this.bitmap;
}
}
}
Note that you may not need to re-create the bitmap each time if it has a fixed size.

How can i draw a rectangle around a label control?

I added a label control to form1 designer and assign some text to it.
Then i did label mouse click event:
private void label5_MouseClick(object sender, MouseEventArgs e)
{
DrawRectangleOnLabel = true;
label5.Invalidate();
}
And the label paint event:
private void label5_Paint(object sender, PaintEventArgs e)
{
if (DrawRectangleOnLabel == true)
{
e.Graphics.DrawRectangle(Pens.Red, 0, 0, label5.Width, label5.Height);
}
}
But what i see when i click on the label is half rectangle only the Left and Top the right and bottom of the rectangle not exist/show.
This is because the rectangle is drawn with a pen width of 1 and the right and bottom portions fall outside the bounds of the label. Just make it one pixel smaller :
e.Graphics.DrawRectangle(Pens.Red, 0, 0, label1.Width - 1, label1.Height - 1);
Alternatively, you can use the ControlPaint method instead :
ControlPaint.DrawBorder(e.Graphics, label1.DisplayRectangle,
Color.Red, ButtonBorderStyle.Solid);
This gives you access to various other ButtonBorderStyles (dashed, dotted, inset, outset).
Why don't you try BorderStyle property on MouseClick event. And assign single event for all labels.
label1.MouseClick += new EventHandler(this.AllLable_MouseClick);
label2.MouseClick += new EventHandler(this.AllLable_MouseClick);
label3.MouseClick += new EventHandler(this.AllLable_MouseClick);
private void AllLable_MouseClick(object sender, MouseEventArgs e)
{
Label lbl = (Label)sender;
if (lbl.BorderStyle == BorderStyle.FixedSingle)
lbl.BorderStyle = BorderStyle.None
else
lbl.BorderStyle = BorderStyle.FixedSingle
}
For a simple "box" just add a Forms.Panel and place your controls on it. Then set the Panel border to FixedSingle.

Paint with brush on existing image

I have embedded the code below in a project in which a want to paint with a brush OVER a picture. The problem is that if a write this code for a main panel , everything goes fine, but as I want to use it for an existing image, I can not see the brush. I suppose that the brush paints but it is a matter of foreground / background.
//the first line goes to the main form - under the initialize component
graphics = DisplayPicturebox.CreateGraphics();
bool draw = false;
Graphics graphics;
private void DisplayPicturebox_MouseDown(object sender, MouseEventArgs e)
{
draw = true;
}
private void DisplayPicturebox_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
}
private void DisplayPicturebox_MouseMove(object sender, MouseEventArgs e)
{
if (draw)
{
//create a brush:
SolidBrush MysolidBrush = new SolidBrush(Color.Red);
graphics.FillEllipse(MysolidBrush, e.X, e.Y,
Convert.ToInt32(toolStripTextBox1.Text),
Convert.ToInt32(toolStripTextBox1.Text));
}
}
A few important things to note here:
Graphics need to be processed in a pipeline or saved in some way so that repaints don't eliminate the changes the user had made.
Keeping a graphics context open indefinitely is a bad idea. You should open the context log enough to draw what you need to either to a buffer or to the screen, then close that context.
If you want to use an offscreen buffer you need to keep in mind the coordinate system you are working in ("Screen" versus "control", versus "buffer"). If you get these confused you may not see what you expect
Those concepts in mind, you might consider the following changes to your code:
// at the beginning of your class declare an offscreen buffer
private System.Drawing.Bitmap buffer;
// .. later create it in the constructor
public Form1() {
InitializeComponent();
// use the w/h of the picture box here
buffer = new System.Drawing.Bitmap(picBox.Width, picBox.Height);
}
// in the designer add a paint event for the picture box:
private picBox_Paint(object sender, System.Windows.Forms.PaintEventArgs e) {
e.Graphics.DrawImageUnscaled(buffer);
}
// finally, your slightly modified painting routine...
private picBox__MouseMove(object sender, MouseEventArgs e)
{
if (draw)
{
using (var context = System.Drawing.Graphics.FromImage(buffer)) {
//create a brush:
SolidBrush MysolidBrush = new SolidBrush(Color.Red);
graphics.FillEllipse(MysolidBrush, e.X, e.Y,
Convert.ToInt32(toolStripTextBox1.Text),
Convert.ToInt32(toolStripTextBox1.Text));
}
}
}
This isn't meant to be perfect code but the general template should work and get you closer to what I think you are looking for. Hope that helps some!
Try this one, modify the mousemove event:
private void DisplayPicturebox_MouseMove(object sender, MouseEventArgs e)
{
if (draw)
{
graphics = DisplayPicturebox.CreateGraphics();
SolidBrush MysolidBrush = new SolidBrush(Color.Red);
float newX = (float)DisplayPicturebox.Image.Size.Width / (float)DisplayPicturebox.Size.Width;
float newY = (float)DisplayPicturebox.Image.Size.Height / (float)DisplayPicturebox.Size.Height;
graphics = Graphics.FromImage(DisplayPicturebox.Image);
graphics.FillEllipse(MysolidBrush, e.X * newX, e.Y * newY, Convert.ToInt32(toolStripTextBox1.Text), Convert.ToInt32(toolStripTextBox1.Text));
DisplayPicturebox.Refresh();
}
}

Categories