Disappearances of shapes on Windows Forms - c#

I am trying to draw a series of rectangles on my Windows Form application in C#. I am using System.Drawing.Graphics to draw the Rectangles. They work fine, but once I switch to another application on my computer or minimize the form, they just disappear. Does anyone know why this is the case?
System.Drawing.Graphics graphics = this.CreateGraphics();
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(
25 + (32 * PASS_THROUGH), 190, 32, 32);
graphics.DrawRectangle(System.Drawing.Pens.Green, rectangle);

You're not going about painting the right way. Here's some basic information on how it works:
http://msdn.microsoft.com/en-us/library/kxys6ytf.aspx
You should have code that looks like this:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Rectangle = new Rectangle(25 + (32 * PASS_THROUGH), 190, 32, 32);
e.Graphics.DrawRectangle(Pens.Green, Rectangle);
}
Windows will call this method whenever it needs to repaint your window.
If you want to be able to change what is painted dynamically, you need to add logic to this method. Such as an if statement that writes, if (drawRectangle) ...
When you want to signal your control to repaint itself after changing a variable like my above example of drawRectangle, you just need to call the Control.Invalidate method on the control in question.
You can manage a lot of different variables and objects to control what is painted, such as a list of shapes. In your paint method you would then loop through those shapes and draw them one by one. I am not sure if this is what you're trying to do, or if you just want to customize the look of your form and you don't need it to change dynamically.

Related

Drawing rectangles on picture box

So I'm trying to automate drawing a bunch of rectangles over an image. I've mostly figured out how to draw them, but the problem I'm running into is that I only seem to be able to get them to actually be drawn when I interact with the picture box.
namespace myGUI
{
public partial class formPicture : Form
{
public formPicture()
{
InitializeComponent();
pbImage.Image = Image.FromFile(#"../../Images/myImage.bmp");
// Doesn't Work
var g = pbImage.CreateGraphics();
g.DrawRectangle(new Pen(Color.Red, 5), 500, 200, 20, 20);
}
private void formPicture_Shown(object sender, EventArgs e)
{
// Doesn't Work
var g = pbImage.CreateGraphics();
g.DrawRectangle(new Pen(Color.Red, 5), 500, 200, 20, 20);
}
private void pbImage_Click(object sender, EventArgs e)
{
// Works
var g = pbImage.CreateGraphics();
g.DrawRectangle(new Pen(Color.Red, 5), 500, 200, 20, 20);
}
}
}
The pbImage_Click() call successfully draws the rectangle on my picture box. The other two instances of trying to draw the rectangle don't seem to result in anything.
I have no idea why it would work in one case, but not the others? I've tried invalidating the graphics, that didn't work. I've tried adding it to the Paint event, that didn't work. I've tried adding it to the validated event, the visible event, the loaded event, pretty much any other event that I can think of such that once the GUI was active it might actually result in the rectangle being drawn.
The only time it seems to work is Click or MouseClick (I haven't tried other interactive events, such as MouseUp or MouseDown, but I presume those would work as well. Besides, the whole point is that I want it to show up automatically.)
NEVER call CreateGraphics. If you want to draw on a control, handle the Paint event of that control and use the e.Graphics property provided. If the drawing needs to change, store the data that describes the drawing in one or more fields, then read those fields in the Paint event handler. If you need to force the drawing to change, modify those fields and then call Invalidate on the control. Ideally, pass an argument to that Invalidate method that describes the smallest area that has or might have changed. Here's one I and a friend prepared earlier.
Note that WinForms controls are painted and repainted quite often, so any drawing done outside the Paint event handler is likely to be wiped. That's exactly what's happening in the cases that you say are not working. The drawing is being done but is then wiped. By doing your drawing in the Paint event handler, you ensure that it is reinstated every time it is wiped, so it appears permanent.

Winforms: How to draw line over control without invalidating it

i have a class that draws waveforms of audio. I'm drawing it in OnPaint function. Now i need to draw a line that shows where on the waveform we are at current moment. I can calculate the position but when i try to draw it i need to call Invalidate() and that forces form to redraw all that waveform chart data (a lot of points).
So is there a way to put some transparent element over this one and then call Invalidate() only on that element? i was trying with picture box but no sucess...
//main form
private void timer100ms_Tick(object sender, EventArgs e)
{
customWaveViewer1.currentPosition = (int)((stream.Position / (float)stream.Length) * customWaveViewer1.Width);
customWaveViewer1.overlayLabel.Invalidate(false);
}
//drawing function in my class
private void overlayLabelInvalidate(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0));
e.Graphics.DrawLine(pen, currentPosition, 0, currentPosition, this.Height);
}
//constructor
public CustomWaveViewer()
{
InitializeComponent();
this.DoubleBuffered = true;
this.PenColor = Color.DodgerBlue;
this.PenWidth = 1;
overlayLabel = new PictureBox();
overlayLabel.Size = new System.Drawing.Size(this.Width, this.Height);
overlayLabel.Location = new Point(this.Left, this.Top);
overlayLabel.Visible = true;
overlayLabel.BackColor=Color.FromArgb(0,0,0,0);
overlayLabel.Paint += new System.Windows.Forms.PaintEventHandler(this.overlayLabelInvalidate);
Controls.Add(overlayLabel);
}
Actually what you are saying is not exactly true.
In the painteventargs there is a rectangle indicating the small portion of the window that needs to be repainted.
Also when you invalidate, you don't necessarily need to invalidate the whole form.
In your case you might want to invalidate only the old and new position of the marker that indicates where you are in the waveform.
So in your algorithm of your paint method, it is really up to you to make it efficient and only paint that part of the window that really needs repainting and to skip the part that does not need repainting.
It really can make a huge difference.
To make it even more look professional, set double buffering on.
No need to hastle with bitmaps of the whole image you have yourself, that is just what double buffering is all about, and forms can do it for you.
I copied following excerpt from https://msdn.microsoft.com/en-us/library/windows/desktop/dd145137(v=vs.85).aspx
BeginPaint fills a PAINTSTRUCT structure with information such as the dimensions of the portion of the window to be updated and a flag indicating whether the window background has been drawn. The application can use this information to optimize drawing. For example, it can use the dimensions of the update region, specified by the rcPaint member, to limit drawing to only those portions of the window that need updating. If an application has very simple output, it can ignore the update region and draw in the entire window, relying on the system to discard (clip) any unneeded output. Because the system clips drawing that extends outside the clipping region, only drawing that is in the update region is visible.
In this case there is no simple output and taking this into account is adviced.
I am not saying that creating a bitmap will not work. I am saying that optimizing your drawing logic will solve it just as well.
The information above still stands as windows forms is built on top of the old win32 api.

Borderless Winform with a 1px border

This might sound like a weird question but I have C# Winform that I set the FormBorderStyle to None. So far everything is good but I was wondering if there was a way to add like a 1px border on around my form ? I know I could do it by creating my own image but I was wondering if there was a more natural way of doing it.
Thanks
I consider using an image, or creating unnecessary controls for something that is easily paintable using GDI+ a waste of resources.
I think the simplest solution is overriding the OnPaint method of your form and drawing the border yourself:
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.Black, this.Bounds);
}
Of course, you may also use your own Pen with your own color and width.
Use padding 1;1;1;1 to your form and set a background color to your form, and put a panel to your form. Set white or other normal background color to the panel. And set dock in parent controller. The background color of the form will act as a border.
How about just adding a Panel (and setting it's border) to the Form?
Thanks for the suggestions, I've decided to create 4 1px label and just toss on the edge on each side. That way:
1. They are minding their own business on the side rather than taking up the whole middle if you use use a groupbox or panel.
2. You are able to choose change your border color.
There is no more natural or non natural ways to do it. It depends on what you want.
If you put a background image on the form, you have to consider a fact that in order to be able to support resizable for you have to have resizable background images.
If you simply draw on the background with a Pen or Brush, you can support also resizable form, but you have to work more if you want to do something cool, instead with image it's easier.
You can embed some control inside the form and with color's of them make a feeling of the border. Like control, you can use Panel, as suggested in comment, can use GroupBox that creates thin broder arround, or something else.
I created this method, so you could easily set the borderposition, color and thickness.
private void customBackgroundPainter(PaintEventArgs e, int linethickness = 2, Color linecolor = new Color(), int offsetborder = 6)
{
Rectangle rect = new Rectangle(offsetborder, offsetborder, this.ClientSize.Width - (offsetborder * 2), this.ClientSize.Height - (offsetborder * 2));
Pen pen = new Pen(new Color());
pen.Width = linethickness;
if (linecolor != new Color())
{
pen.Color = linecolor;
}
else
{
pen.Color = Color.Black;
}
e.Graphics.DrawRectangle(pen, rect);
}
You could use it in the OnPaintBackground likes this:
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
customBackgroundPainter(
e,
linethickness: 3,
linecolor: Color.DarkOrange,
offsetborder: 5
);
}

Movable Rectangle or Label

I am writing a program in Visual C# 2010 that has several icons on the form. When the mouse is placed over the icon (which is just an image) I want the icon to b highlighted via a border around the icon. In visual basic i can make a transparent rectangle with a colored border and position it over the icon. In C#, i can do the same however until i call invalidate multiple borders appear. The problem with calling invalidate is that my program is doing something in the background every second so the border keeps flashing (re-drawing).
Anyone got any ideas how i can implement this?
You didn’t say how you draw the border but from your description you are creating a graphics context for this. Don’t do this, it’s wrong. Instead, draw inside the Paint element of either the control or the its parent container.
The Paint event handler could look as follows:
private void yourControl_Paint(object sender, PaintEventArgs e)
{
if (! HasFocus(yourControl))
return;
Graphics g = e.Graphics;
using (Pen p = new Pen(Color.FromArgb(128, 0, 0, 128)))
g.DrawRectangle(p, 0, 0, yourControl.Width -1, yourControl.Height - 1);
}
This uses a hypothetical HasFocus method to determine whether this control should have a focus rectangle.
By the way, this is identical in VB and C#.

Simple rectangle box

How do put rectangular box around few controls on my winform? (i dont want the grouping thing).
If you don't want to use a GroupBox, you can put your controls in a Panel and set its BorderStyle property to BorderStyle.FixedSingle or BorderStyle.Fixed3D.
What's wrong with the GroupBox control? Grouping together a related set of controls is exactly what it's intended for. Your users have seen it in every other application they use, and throughout the Windows shell. They're much more likely to recognize what it means than your own custom-drawn rectangle. Deviating from standard platform conventions is rarely a good idea. I strongly recommend using the GroupBox control, even if it's not exactly the perfect look that you had in mind.
That being said, it's certainly possible to draw your own box around a group of controls on a form. To do so, you'll need to override your form's OnPaint method and write some code to draw a rectangle. Doing it this way gives you complete control over the color of your box, as well as the line thickness.
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
// Call the base class
base.OnPaint(e);
// Create your drawing pen
using (Pen p = new Pen(SystemColors.WindowText, 2.0))
{
// Calculate the position and dimensions of the box
Rectangle rect = new Rectangle(10, 10, 30, 30);
// Draw the rectangle
e.Graphics.DrawRectangle(p, rect);
}
}
The only thing you'll need to add is the code that calculates the dimensions of your rectangle, relative to the controls you want it to surround. Use the Location property of each control to get this information.
You can put your controls into a panel and set its BorderStyle from None to FixedSingle - it is the easiest way
http://msdn.microsoft.com/en-us/library/cyh3c8h8.aspx
Pen pen = new Pen(Color.FromArgb(255, 0, 0, 0));
e.Graphics.DrawLine(pen, 20, 10, 300, 100);
You can draw lines on a windows form this way. This would hook into the Paint method where e is PaintEventArgs

Categories

Resources