How do I repaint my picturebox when the picture disappears? - c#

I don't know how to repaint my picturebox. This is just a demonstration. The production code is too time consuming to put in the paint event. What I need is a way to capture the image that is drawn in the pucturebox with the graphics methods so I can quickly repaint it when needed.
Here's a demo:
public partial class Form1 : Form
{
Image Outout;
public Form1()
{
InitializeComponent();
button1.Click += Button1_Click;
}
private void Button1_Click(Object sender, EventArgs e)
{
PrintPageEventArgs eOutput;
Graphics g;
string OutputText;
Font PrintFont;
OutputText = "CERTIFICATION";
PrintFont = new Font("Arial", 16, FontStyle.Bold);
g = pictureBox1.CreateGraphics();
eOutput = new PrintPageEventArgs(g, new Rectangle(new Point(25, 25), new Size(new Point(825, 1075))), new Rectangle(new Point(0, 0), new Size(new Point(850, 1100))), new PageSettings());
eOutput.Graphics.DrawString(OutputText, PrintFont, Brushes.Black, 0, 0);
Outout = pictureBox1.Image;
pictureBox1.Paint += PictureBox1_Paint;
}
private void PictureBox1_Paint(object sender, PaintEventArgs e)
{
pictureBox1.Image = Outout;
}
}

Thanks TaW for pointing me in the right direction. The example I posted is from an ERP system and the actual problem uses over a dozen objects plus the graphics is from a multipage report. So drawing in the paint event will not work. For starters, keeping a list of things to draw is pointless, since EVERYTHING needs to be drawn when the part number changes. Also the report generator needs to run twice, the first time just to calculate the number of pages and the second time to actually draw the pages. Also I cant use the PrintPreview of the PrintDocument because of its limitations. But you were spot on about using Graphics g = Graphics.FromImage(bmp). That's what I needed.
#LarsTech, you are correct, that is a weird use of the PrintPageEventArgs. That is merely a side effect when an issue embedded in a couple of events and several objects needs to be reduced in form to present a representation of a problem. If its reduced too small, the proposed solutions do not scale, therefore, do not work. If it is not reduced enough, it can be difficult to understand the actual problem, as people will present solutions to different aspects, some of which are artificial due to the reduction of the issue.
ANSWER
Drawing on the graphics created by the picturebox was not persistent. Drawing on a bitmap, however, worked perfectly as suggested by TaW. Thank you for your assistance!
PrintPageEventArgs eOutput;
Graphics g;
string OutputText;
Font PrintFont;
Bitmap Output;
OutputText = "CERTIFICATION";
PrintFont = new Font("Times New Roman", 24, FontStyle.Regular);
Output = new Bitmap(850, 1100);
g = Graphics.FromImage(Output);
eOutput = new PrintPageEventArgs(g, new Rectangle(new Point(25, 25), new Size(new Point(825, 1075))), new Rectangle(new Point(0, 0), new Size(new Point(850, 1100))), new PageSettings());
eOutput.Graphics.DrawString(OutputText, PrintFont, Brushes.Black, 0, 0);
pictureBox1.Image = Output;

Related

How to draw graph in c#

I'm new ,and I don't understand why this method when copied to windows forms doesn't do anything when running the program. I was copy it from MSDN page.
public void DrawLinesPoint(PaintEventArgs e)
{
// Create pen.
Pen pen = new Pen(Color.Black, 3);
// Create array of points that define lines to draw.
Point[] points =
{
new Point(10, 10),
new Point(10, 100),
new Point(200, 50),
new Point(250, 300)
};
//Draw lines to screen.
e.Graphics.DrawLines(pen, points);
}
Typically, when you draw on a form, you handle the form’s Paint event and perform the drawing using the Graphics property of the PaintEventArgs
In your code you need to add the DrawLinesPoint to the paint event before being able to use it
In your Constructor() add
InitializeComponent();
this.Paint += new System.Windows.Forms.PaintEventHandler(this.DrawLinesPoint);
And in your Paint PaintEventHandler
private void DrawLinesPoint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Black, 3);
// Create array of points that define lines to draw.
Point[] points =
{
new Point(10, 10),
new Point(10, 100),
new Point(200, 50),
new Point(250, 300)
};
//Draw lines to screen.
e.Graphics.DrawLines(pen, points);
}

Print Text with DrawString() next to an existing bitmap

Greetings fellow users,
A virgin post on my end since its the first time i am abusing stack overflow with a question! I have been trying to get a bitmap print along with a String to print. Basically the view i want to achieve is the Image and the text to the right of the image as we see the printout. Below is the code I am using
Bitmap qrCodeImage = qrCode.GetGraphic(20);
senderQR = qrCodeImage;
PrintDocument pd = new PrintDocument();
Margins margins = new Margins(10, 10, 10, 10);
pd.DefaultPageSettings.Margins = margins;
pd.PrintPage += PrintPage;
pd.Print();
Here is the PrintPage method
private void PrintPage(object sender, PrintPageEventArgs e)
{
System.Drawing.Image img = senderQR;
Bitmap batchCode = new Bitmap(80, 700);
Rectangle m = e.MarginBounds;
RectangleF batch1 = new RectangleF(80, 700, 650, 1000);
m.Width = img.Width / 5;
m.Height = img.Height / 5;
Graphics g = Graphics.FromImage(batchCode);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.DrawString(batch, new Font("Arial", 40), Brushes.Black, batch1);
g.Flush();
e.Graphics.DrawImage(img, m);
}
What am i doing wrong? what seems to be the issue? I have been struggling a whole lot to achieve this but no luck!
Additional Notes:
I want the text on the right to Wrap under itself and not under or on top of the existing bitmap within a size of 3,5 x 2 (inches) (label printing).
This is the printout i get with the existing code;
https://prnt.sc/h1ecb0
https://prnt.sc/h1edex
The image you're drawing on (batchCode) is 80 pixels wide and 700 high. When you write your text over it, you set the top-left point of your writing to 80,700 - exactly to the bottom-right corner of your picture. Basically, you write your text outside of the picture.
Update
I've created a small example to make it reproducible, below is a form class for a basic WinForms application:
public partial class Form1 : Form
{
private PictureBox pictureBox2;
public Form1()
{
InitializeComponent();
pictureBox2 = new PictureBox();
pictureBox2.Size = ClientSize;
pictureBox2.SizeMode = PictureBoxSizeMode.AutoSize;
this.Click += Form1_Click;
pictureBox2.Click += Form1_Click;
Controls.Add(pictureBox2);
}
private void Form1_Click(object sender, EventArgs e)
{
var batch = "hello there!";
Bitmap batchCode = new Bitmap(1000, 1000);
var batch1 = new RectangleF(150, 150, 850, 850);
using (Graphics g = Graphics.FromImage(batchCode))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.DrawString(batch, new Font("Arial", 40), Brushes.Black, batch1);
}
pictureBox2.Image = batchCode;
}
}

Draw line on a dynamically created picturebox

i need to draw a line for example, in a dynamically created PictureBox. What happens is that the picture box is created and shown in the form but the line is missing. My code is below, any ideas?? thnx
public void create_pb()
{
PictureBox pb = new PictureBox();
pb.Size = new Size(200, 200);
pb.BorderStyle = BorderStyle.Fixed3D;
pb.Location = new Point(0,0);
panel1.Controls.Add(pb);
g = pb.CreateGraphics();
Pen p = new Pen(Color.Black, 2);
g.DrawLine(p, 0, 0, 200, 200);
}
g is defined as public Graphics g;
Don't use CreateGraphics. You need to do your drawing in the Paint event handler instead, using e.Graphics from the event arguments passed to you.
Otherwise your line will simply be erased when the picture box is next repainted (e.g. when the form is moved, resized, covered by another form, etc).
Example:
pb.Paint += (sender, e) =>
{
Pen p = new Pen(Color.Black, 2);
e.Graphics.DrawLine(p, 0, 0, 200, 200);
};

Using the Matrix.RotateAt in C#

I am attempting to rotate a gauge based on data that I am acquiring from a Serial Port. The Serial communications are working well and now I am having issues making the gauge rotate. I am now trying to make the image rotate with a slider bar and I am still having no luck. I currently have a timer implemented to trigger every 100 ms and run this code. However when I move the sliderBar nothing happens to the image on the screen. The reason I am using a timer is because that is what I will be using for my final implementation. Using a timer to trigger the UI update instead of the Serial event makes the application run much more smooth.
As always any help is greatly appreciated!
in the constructor...
public Form1()
{
InitializeComponent();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
imgpic = (Image)pictureBoxBase.Image.Clone(); // This is storing an image in a picture box...
foreach (int rate in baudRates)
{
brbox.Items.Add(rate);
}
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = 100;
timer.Enabled = true;
timer.Start();
com.DataReceived += new SerialDataReceivedEventHandler(OnReceived);
}
Then in the timer event...
void timer_Tick(object sender, EventArgs e) // Again it is initially drawing the picture, but it does not rotate with the statusBar
{
Point test = new Point(0, 0);
Image img = new Bitmap(400, 400);
pictureBox1.Image = img;
Graphics g = Graphics.FromImage(pictureBox1.Image);
Matrix mm1 = new Matrix();
mm1.RotateAt((trackBar1.Value),new Point( 0,0),MatrixOrder.Append);
GraphicsPath gp = new GraphicsPath();
gp.Transform(mm1);
gp.AddPolygon(new Point[] { new Point(0, 0), new Point(imgpic.Width, 0), new Point(0, imgpic.Height) });
PointF[] pts = gp.PathPoints;
g.DrawImage(imgpic, test);
pictureBox1.Refresh();
}
Key issues are:
Not actually drawing the path you produce
Not rotating the polys you add to the path (must apply transform after adding them)
Lots of potential for memory leaks here - objects with unmanaged components (Graphics, GraphicsPath, Image, and Matrix objects here) need to be disposed so that underlying Windows objects can be deleted nicely (.NET can't do this for you).
Fixed up code:
void timer_Tick(object sender, EventArgs e)
{
if (pictureBox1.Image != null)
pictureBox1.Image.Dispose(); // dispose old image (you might consider reusing it rather than making a new one each frame)
Point test = new Point(0, 0);
Image img = new Bitmap(400, 400);
pictureBox1.Image = img;
Graphics g = Graphics.FromImage(pictureBox1.Image);
Matrix mm1 = new Matrix();
mm1.RotateAt((trackBar1.Value), new Point( 0,0), MatrixOrder.Append); // note that the angle is in degrees, so make sure the trackbar value or input is suitably scaled
GraphicsPath gp = new GraphicsPath();
gp.AddPolygon(new Point[] { new Point(0, 0), new Point(imgpic.Width, 0), new Point(0, imgpic.Height) });
//PointF[] pts = gp.PathPoints; // not needed for this task
g.DrawPath(Pens.Black, gp); // draw the path with a simple black pen
g.Transform = mm1; // transform the graphics object so the image is rotated
g.DrawImage(imgpic, test); // if the image needs to be behind the path, draw it beforehand
mm1.Dispose();
gp.Dispose();
g.Disose(); // prevent possible memory leaks
pictureBox1.Refresh();
}
I think this ought to work, if it still has issue, comment here and I'll modify it if need be.
(Edit: looks like there is a lot of stuff to dispose that I didn't quite expect)

Recognizing texts as URLs in Winforms

I am rendering some text in GUI and trying to recoganize the URLs. Also I need to open the URLs in browser when click events are performed. I have attached the model code snippent below. My question is how to make these texts a valid URLs and how to make them to respond to click events. And one more thing this due to some requirements I cant change the structure of the below code snnipet.
namespace Model
{
public partial class ParentView : Form
{
public ParentView()
{
InitializeComponent();
}
private void ParentView_Paint(object sender, PaintEventArgs e)
{
GraphicsState state = e.Graphics.Save();
GraphicsRenderer renderer = new GraphicsRenderer(e.Graphics);
renderer.RenderAsImage();
e.Graphics.Restore(state);
e.Graphics.DrawRectangle(new Pen(Brushes.Black), 0, 0, 300, 300);
//I believe need to do something here
}
}
public class GraphicsRenderer
{
Graphics PageGraphics;
public GraphicsRenderer(Graphics g)
{
PageGraphics = g;
}
public void RenderAsImage()
{
Point currentLocation = new Point(0, 0);
PageGraphics.TranslateTransform(20, 40);
PageGraphics.DrawString("www.google.com", new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Point), Brushes.Black, currentLocation);
PageGraphics.TranslateTransform(20, -40);
PageGraphics.DrawString("www.stackoverflow.com", new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Point), Brushes.Black, currentLocation);
currentLocation = new Point(50, 60);
PageGraphics.DrawString("www.stackoverflow.com", new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Point), Brushes.Black, currentLocation);
}
}
}
Thanks,
Mkn
If you're just writing text to the screen as graphics you can't make it clickable. You'll need to position a LinkLabel or other clickable control at the right position to trigger the url opening in a browser.
Thanks for your response. I have analyzed further and found a way. Drawing rectangles over the text and finding the rectangles in mouse click events using Rectangle. Contains(MouseLeftClikLocation).
Now I am having another problem. If scale transformation is performed I could not able to get the location after restoring the graphics.
Please find the code snnipet below.
private void ParentView_Paint(object sender, PaintEventArgs e)
{
GraphicsState state = e.Graphics.Save();
GraphicsRenderer renderer = new GraphicsRenderer(e.Graphics);
renderer.RenderAsImage();
e.Graphics.Restore(state);
e.Graphics.DrawRectangle(new Pen(Brushes.Black), 0, 0, 300, 300);
//I am changing here
float[] transformPoints = renderer.transformPoints.Elements;
e.Graphics.TranslateTransform(transformPoints[4], transformPoints[5]);
Point currentLocation = renderer.currentLocation;
e.Graphics.DrawRectangle(new Pen(Brushes.Black),new Rectangle(currentLocation.X,currentLocation.Y,190,30));
}
public class GraphicsRenderer
{
Graphics PageGraphics;
internal Matrix transformPoints = new Matrix();
internal Point currentLocation = new Point(0, 0);
public GraphicsRenderer(Graphics g)
{
PageGraphics = g;
}
public void RenderAsImage()
{
currentLocation = new Point(50, 60);
//PageGraphics.ScaleTransform(3, 3);
PageGraphics.DrawString("www.bing.com", new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Point), Brushes.Black, currentLocation);
transformPoints = PageGraphics.Transform;
}
}

Categories