I am developing the GUI in C# using picturebox, button, and check box.I need to plot two different plots in parallel using one text file on an image. The image first reads in a picture box. The rest of the program has to be executed in the following way:
Reads text file contains the data points which have to be plotted.
After clicking the button the program execution started with the plotting of the First graphic (rectangular dot), however when the check box is checked the second graphic (continuous dots--path plot) plotting started in parallel with the first graphic.
when the check box is unchecked the second graphic stopped plotting and disappears.(As Both of the graphics style using the same text file).
I need help what to do in this case, should I create the separate thread for check box for this parallel plotting??
please help me where I am mistaken? And pardon my horrible English
From my point of view, the easiest way would be to reload the image into the picture box again and then redraw the first graphics object on it. So, the second one 'disappears'.
An additional thread makes no sense, because drawing must occur on the UI thread only (Windows general rule for GDI+, WinForms, WPF).
Such basic drawing as in your example is very fast.
Edit:
namespace PictureBoxDrawing
{
public partial class Form1 : Form
{
private Bitmap _bmpImage;
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_bmpImage = new Bitmap(#"C:\Image.jpg");
InitializePictureBox(_bmpImage);
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
DrawPictureBox(pictureBox1, 10, 10, checkBox1.Checked);
}
private void button1_Click(object sender, EventArgs e)
{
DrawPictureBox(pictureBox1, 10, 10, checkBox1.Checked);
}
private void button2_Click(object sender, EventArgs e)
{
InitializePictureBox(_bmpImage);
}
private void DrawPictureBox(PictureBox pb, int x, int y, bool drawBlue)
{
using (Graphics g = pb.CreateGraphics())
{
g.FillRectangle(Brushes.Red, x,y, 9,9);
if(drawBlue)
g.FillRectangle(Brushes.Blue, x, y, 7, 7);
}
}
private void InitializePictureBox(Bitmap bmp)
{
pictureBox1.Image = bmp;
}
}
}
From your example, here is my simplified suggestion. Load and cache the bitmap in a field for later use. I have added a second button2, which can be used to reload the image into the picture box to demonstrate the behaviour. Because the red rectangle is greater than the blue (9 > 7), it overwrites it when redrawing. So it is not necessary to reload the bitmap, if the position is constant. If the position changes, call InitializePictureBox prior to the DrawPictureBox call.
Related
I have an issue with printing from a panel (C#, windows form). I created a Print button, I wrote the necessary codes for that and it seems that only one textboxes are able to shown as it is supposed to be. The rest of the controls, such as the richtextboxes are blank, even if I write into them.
Bitmap bitmap;
private void btn_Print_Click(object sender, EventArgs e)
{
Print(this.panel_Doc_Print);
}
public void Print(Panel panel)
{
PrinterSettings set = new PrinterSettings();
panel_Doc_Print = panel;
PrintArea(panel);
print.Document = print_doc;
print_doc.PrintPage += new PrintPageEventHandler(PrintImage);
print.ShowDialog();
}
public void PrintImage(object sender, PrintPageEventArgs e)
{
Rectangle page_area = e.PageBounds;
e.Graphics.DrawImage(bitmap, (page_area.Width / 2) - (this.panel_Doc_Print.Width / 2), this.panel_Doc_Print.Location.Y);
}
public void PrintArea(Panel panel)
{
bitmap = new Bitmap(panel.Width, panel.Height);
panel.DrawToBitmap(bitmap, new Rectangle(0, 0, panel.Width, panel.Height));
}
Before the printing the Windows form looks like this:
Windows form before printing.
Before I click on the print button:
before
After I click on the print button the following happens:
after
What did I do wrong? When I click on the button I want the program to print the whole panel, including all items and control in it. It happens only to the textboxes. As you can see on the 3rd picture the size of the printing image is quite small. I want it to roughly fill out an A4 sheet of paper.
At this point I am too confused to solve this problem alone, therefore I would like to ask for your help.
I try to remove newest drawline.
declaration
Bitmap DrawArea ; // global variable
Bitmap Previuos_DrawArea; // global variable
when I click button to draw a line
private void button2_Click_1(object sender, EventArgs e)
{
Graphics g = Graphics.FromImage(DrawArea);
Previuos_DrawArea_img = DrawArea;
g.(new Pen(Brushes.BlueViolet, 1.0F),0,10,10,20);
pictureBox1.Image = DrawArea;
}
when I click button to remove a line
private void button3_Click_1(object sender, EventArgs e)
{
pictureBox1.Image = Previuos_DrawArea_img;
}
Concept :
1st step - Declare variable.
2nd step - Backup current picture.
3rd step - Draw new picture.
4th step - if undo just draw the backup picture.
You aren’t creating a copy of the bitmap, you’re only storing it in two variables. They point to the same bitmap so editing one affects the other one. You’ll need to create a copy:
Previuos_DrawArea_img = new Bitmap(DrawArea);
Now it is a separate image and whatever you do to one of them doesn’t affect the other one.
I created an application which is larger in size than an A4 paper . I placed a print button on my windows form and following the MSDN tried both printDocument and printForm . But both of them don't scale my image and print only half the screen .
I researched and found that somewhere it was advised to place all controls in a picturebox and print that , but I am looking for a better alternative before I go ahead changing the complete design of my application . Some places advised to go for a completely different route for crystal reports .
The task doesn't seem easy than I actually thought and now I am stuck .
Edit1 :Here is the code that I added to my Form . I did try using bitmaps but that did not resolve the problem too .
private void button1_Click(object sender, EventArgs e)
{
//Form3 dlg = new Form3();
//dlg.ShowDialog();
//CaptureScreen();
// printDocument2.Print();
printForm1.Print();
}
/* Bitmap memoryImage;
private void CaptureScreen()
{
Graphics myGraphics = this.CreateGraphics();
Size s = this.Size;
memoryImage = new Bitmap(s.Width, s.Height, myGraphics);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
memoryGraphics.CopyFromScreen(this.Location.X, this.Location.Y, 0, 0, s);
}
private void printDocument2_PrintPage(System.Object sender,
System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
private void groupBox4_Enter(object sender, EventArgs e)
{
}*/
Is there a way if I can also possibly change the orientation to landscape ? I would like to try to see of that probably fits .
Edit2 : I found a way to print in the landscape mode and all the contents fit well . My application has a windows form and 3 tabs in it under a tab control . What I am trying to print is only the contents of the third tab which is the result window . Is there a way I can only print the contents of the tab control and not the entire form ?
Question:
How do you properly draw on a winform from a method other than the OnPaint() method?
Additional Information:
The code I have now draws some background lines for a TicTacToe game in the OnPaint() method. Then I use the Mouse_Click event and am running this code which apparently is not proper:
private void TicTacToe_MouseClick(object sender, MouseEventArgs e)
Graphics g = this.CreateGraphics();
g.DrawEllipse(this.penRed, this.Rectangle);
For reasons I do not understand, it does draw the circle, but when minimizing or moving the form off screen it erases the circles but not the lines from the OnPaint() method.
You are doing a lot of "view" but no "model".
When you want to create a shape, when the mouse button goes down/up, create some DATA representing the shape.
Your data structures represent the persistent information (it is the data that allows you to save and load this information between sessions).
All your paint function needs to do is look at the DATA structures and paint it. This will therefore persist between sizing/hiding/showing.
The problem is that Windows windows (that includes WinForms) have no graphical memory of their own unless their creator provides such memory and it is only a matter of time before that particular window wilk get overwritten or hidden and eventually need to be repainted. You're painting to the screen ( you might say ) and others can do the same. The only convention you can rely on is that the OnPaint will get called when needed. Basically it's alright to use your philosophy and draw whenever you need to (not on some misterious and unpredictable schedule). For that check out my solution.
You should use a "backbuffer bitmap" like:
private Bitmap bb;
protected override void OnResize(EventArgs e) {
this.bb = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
this.InitBackBuffer();
}
private void InitBackBuffer() {
using (var g = Graphics.FromImage(this.bb)) {
// do any of the "non dissapearing line" drawing here
}
}
private void TicTacToe_MouseClick(object sender, MouseEventArgs e)
using (Graphics g = Graphics.FromImage(this.bb))
g.DrawEllipse(this.penRed, this.Rectangle);
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
e.Graphics.DrawImageUnscaled(this.bb);
}
Try that. That should do it :)
What you are doing is drawing on the form "asynchronously" (from the OnPaint method). You see, the OnPaint method is what Windows Forms relies on to draw your entire form. When something happens to your From, it is invalidated and OnPaint is called again. If something isn't drawn in that method, then it will not be there after that happens.
If you want a button to trigger something to appear permanently then what you need to do is Add that object to a collection somewhere, or set a variable related to it. Then call Refresh() which calls Invalidate() and Update() Then, during OnPaint, draw that object (ellipis).
If you want it to still be there after something happens to your form, such as minimize, you have to draw it during OnPaint.
Here's my suggestion:
public partial class Form1 : Form
{
Rectangle r = Rectangle.Empty;
Pen redPen = new Pen(Color.Red);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
r = new Rectangle(50, 50, 100, 100);
Refresh();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (r != Rectangle.Empty)
{
e.Graphics.DrawRectangle(redPen, r);
}
}
}
Relatively new to C#; hopefully I'm just overlooking something simple.
I have a form named 'Exercise1' which contains a picture box called 'drawingArea' and a few buttons. The code for the constructor of Exercise1 is as follows:
public Exercise1()
{
InitializeComponent();
paper = drawingArea.CreateGraphics();
balloon = new Balloon("redBalloon", Color.Red, drawingArea.Width / 2,
drawingArea.Height / 2, 30);
paper.Clear(Color.White);
balloon.Display(paper);
}
...
'paper' and 'balloon' are created as globals above the constructor for use in the other methods on the form. Both 'paper' and 'balloon' work as initialized in the constructor in the other methods defined on the form.
For whatever reason, the commands
paper.Clear(Color.White);
and
balloon.Display(paper);
Which should clear the picture box and show a red ellipse, don't execute (at least visibly). What gives?
UPDATE:
Think I'm going to like this website... You guys are quick!
#Nitesh: The constructor for Exercise1 is called from another form. Code is as follows:
private void button1_Click(object sender, EventArgs e)
{
int exSelector = (int)numericUpDown1.Value;
switch (exSelector)
{
case 1:
Exercise1 form1 = new Exercise1();
form1.Show();
break;
...
#Sean Dunford: Yes and yes it is.
#RBarryYoung: Was playing around with that a bit, but had no luck. What command triggers a Form_Load event for Exercise1?
UPDATE: This altered code works as expected:
public Exercise1()
{
InitializeComponent();
paper = drawingArea.CreateGraphics();
drawingArea.BackColor = Color.White;
drawingArea.Paint += new PaintEventHandler(this.drawingArea_Paint);
balloon = new Balloon("redBalloon", Color.Red, drawingArea.Width / 2, drawingArea.Height / 2, 30);
}
private void drawingArea_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.White);
balloon.Display(e.Graphics);
}
...
Thanks for all the help!
You cannot do drawing in the constructor. To do proper drawing, you need to have the form shown on the screen. You can try using the Shown event to do your rendering (this may get lost when the form is redrawn, though).
Usually the best way is to set whatever flags you need in the constructor and then use the Paint event of the form to do all painting. Later on, when you need to repaint something, set up whatever state needs to be rendered, invalidate your form (this results in a Paint event) and then you can repaint the new state.
If you try to do customized drawing (outside your Paint event) you'll run the risk of things randomly going blank or your drawing may disapper when you resize/minimize your form.
You use Graphics in a constructor, that means that you draw on the paper only once, any redraw for whatever reason that happens after constructor will draw the drawingArea in its original way. Try to add PaintEventHandler to drawingArea and then call inside balloon.Display(e.Graphics);
public Exercise1()
{
InitializeComponent();
balloon = new Balloon("redBalloon", Color.Red, drawingArea.Width / 2,
drawingArea.Height / 2, 30);
drawingArea.Paint += new PaintEventHandler(drawingArea_Paint);
}
void drawingArea_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.White);
baloon.Display(e.Graphics);
}
You should be overriding the forms OnPaint event handler. In doing so, you are able to get the graphics context which will redraw your paper and balloon areas.