I'm fairly new to using C#. I started on monday to be honest and prior to this only had basic MATLAB level of experience, so I'm still some kind of newb scrub. The question I will ask has already been asked, according to my googling skills, but I have yet to find a working solution.
I'm currently writing a program to make the image acquisition from a Vimba camera, and the subsequent image tratment, and that program includes a UI, so a form1. On this form, there is a pictureBoxLiveCamera that shows the live recording from the camera.
What I am trying to do is :
draw two rectangles on top of the pictureBoxLiveCamera, indicating specific zones of the image (THIS WORKS LIKE A CHARM)
have those two rectangles NOT drawn when I launch the program, but when I click a specific drawRectanglesButton (AND HERE I HAVE A PROBLEM)
have that same button hide the rectangles if they are drawn, and then draw them if they are hidden (I'M NOT THERE YET)
I have already explored a lot of similar threads, and this one particularly shaped the way I wrote the code, though it is not working as intended yet.
Here are the protions of my code that are relevant here :
form loading :
// Form loading
private void Form1_Load(object sender, EventArgs e)
{
pictureBoxLiveCamera.Paint += pictureBoxLiveCamera_Paint;
... //Vimba API startup and so on
}
button code :
private void drawRectanglesButton_Click(object sender, EventArgs e)
{
this.Invalidate(); // force Redraw the form
}
rectangles drawing code :
public void pictureBoxLiveCamera_Paint(object sender, PaintEventArgs e)
{
Rectangle ee = new Rectangle(-5, 120, 790, 100);
using (Pen pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, ee);
}
Rectangle eee = new Rectangle(-5, 364, 790, 100);
using (Pen pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, eee);
}
}
My problem is the following : as it is, when I start the program, the rectangles are already drawn, so the button does nothing.
I'm pretty sure the mistake will be obvious to most of you, but this has been driving me crazy all day.
Thanks a lot !
Trion
Related
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.
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.
I would like to use a picturebox to put together an analog clock. I have set a backgound image for the picturebox, that is going to be the "clock-face". Upon it, I meant to use bitmap images as my hour,-minute, and second-hands. I had looked up a few forums, and MSDN documentations, and my problem was nearly solved, but I got stuck at a certain point. (I am using Visual Studio 2013 and C# form application). I had turned my bitmap into a Graphics object, and after that I set the rotation point with the TranslateTransform class and then rotated it with the RotateTransform class. The I drew the my original bitmap to the Graphics object, and set my picturebox.Image to this bitmap. An is shows up only a certain point of the hand. As I set another value to the degree, it shows another certain part of it. My code looks like:
private void rotateImg(Bitmap b , int degree) {
Bitmap bitmap = new Bitmap(b.Width,b.Height);
Graphics g = Graphics.FromImage(bitmap);
g.TranslateTransform(bitmap.Width/2,bitmap.Height/2);
g.RotateTransform(degree);
g.DrawImage(b, new Point(0,0));
g.Dispose();
pictureBox1.Image=bitmap;
}
And my result looks like this:
I am very confused with this now, I am not really familiar with C# form applications, so I would approciate any advice, link or whatsoever to carry on with this tiny project.
Leave the clock face as the Background, then use the Paint() event of your PictureBox to put the hand on top. Something like...
private Bitmap HourHand;
private int HourDegree =45;
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.TranslateTransform(pictureBox1.Width / 2, pictureBox1.Height / 2);
g.RotateTransform(HourDegree);
g.DrawImage(HourHand, new Point(0, 0));
}
I am building a C# app that shows the trajectory of a cannonball. But when I minimize it the trajectory I have drawn to a picture box are gone when I bring it back up. Is there an easy way to stop this?
I bet your drawing in the mouse event. Use the onpaint event and you should be good to go.
Edit:
Here is a decent drawing tutorial using the onpaint() event:
http://www.geekpedia.com/tutorial50_Drawing-with-Csharp.html
When the window is restored it will need to redraw the form. If you do not have your drawing as part of the paint event, then it will not be redrawn.
This question is very similar to this one
Saving a Graphics content to a file
As the others have already stated the problem is when you draw onto a graphics object, there is nothing retained. It is called persistent graphics. Sometimes you want this behavior, more often than not you don't.
You should do your drawing onto a bitmap, then copy the bitmap to your picturebox.Image. The other option as stated in the other answers, is do your drawing routines in the OnPaint Method.
Read my answer in the above. The title is misleading, he thought he had to save to a file to gain persistence, but we showed him otherwise.
EDIT Here is the important code from the above link
Bitmap buffer;
public Form1()
{
InitializeComponent();
panel1.BorderStyle = BorderStyle.FixedSingle;
buffer = new Bitmap(panel1.Width,panel1.Height);
//Make sure you resize your buffer whenever the panel1 resizes.
}
private void button1_Click(object sender, EventArgs e)
{
using (Graphics g = Graphics.FromImage(buffer))
{
g.DrawRectangle(Pens.Red, 100, 100,100,100);
}
panel1.BackgroundImage = buffer;
}
i was having same problem just used mainp.refresh() after event change
mainp was my panel in which i was drawing my all graphics
I exhaustively used the search but have not been able to find a satisfying solution to my problem.
I programmed a data visualization using a chart (datavisualization.charting.chart). This chart changes steadily since it shows some kind of simulation results.
I would like to draw for example a line upon the chart (depending on the mouse position) in order to show context sensitive information.
Therefore, I tried two implementations, none of both works exactly as I would like it to:
plotLine is called on MouseMove- Event
gGraph is created from the underlying graph using: chartCreateGraphics();
protected void plotLine(object sender, System.EventArgs e)
{
if (this.chart.Series.Count > 0) //ensure that the chart shows data
{
plotChart(); // this plots the underlying chart
penGraph = new Pen(Color.Black);
Point point1 = new Point(Form1.MousePosition.X - chart.Location.X, 0);
Point point2 = new Point(Form1.MousePosition.X - chart.Location.X,
chart.Location.Y + chart.Size.Height);
gGraph.DrawLine(penGraph, point1, point2);
penGraph.Dispose();
}
}
Here, the line disappears each time immediately after being plotted, but should remain as long as the mouse is not moved.
protected void plotLine(object sender, System.EventArgs e)
{
penGraph = new Pen(Color.Black);
Point point1 = new Point(Form1.MousePosition.X - chart.Location.X, 0);
Point point2 = new Point(Form1.MousePosition.X - chart.Location.X,
chart.Location.Y + chart.Size.Height);
gGraph.DrawLine(penGraph, point1, point2);
penGraph.Dispose();
}
Here, all plotted lines remain in the graphics surface as long as the chart is not plotted by new. (only the last line should remain in order to indicate the mouse position)
Can anybody help me?
You should be drawing in the OnPaint event. You are circumventing the update model and are seeing the effects of doing so. Sure, you do some drawing in MouseMove, but when the Paint event fires it will simply be erased.
Put your code in OnPaint first. On mouse move simply record whatever data you need to (i.e., mouse position) and then call Invalidate() on the chart. When you do that the Paint event will be called and your drawing code will fire.
Rule of thumb; never draw from anywhere but the Paint event.