I am using BufferedGraphics to redraw my form. I wish to redraw the form's controls all by myself, so I can draw lines wherever I want while I can still use the Form Designer to align my controls.
I've tried SuspendLayout but it make no use here.
Code:
using System;
using System.Drawing;
using System.Windows.Forms;
public partial class Form1 : Form
{
BufferedGraphicsContext context;
BufferedGraphics grafx;
PictureBox pic1, pic2;
public Form1()
{
SetStyle((ControlStyles)(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint), true);
InitializeComponent();
//Add picturebox
pic1 = new PictureBox();
pic1.BackColor = Color.Black;
pic1.SetBounds(50, 50, 100, 50);
Controls.Add(pic1);
pic2 = new PictureBox();
pic2.BackColor = Color.Gray;
pic2.SetBounds(75, 50, 50, 100);
Controls.Add(pic2);
}
private void Form1_Load(object sender, EventArgs e)
{
context = BufferedGraphicsManager.Current;
context.MaximumBuffer = new Size(Width, Height);
grafx = context.Allocate(CreateGraphics(), new Rectangle(0, 0, Width, Height));
}
public override void Refresh() { }
protected override void OnPaintBackground(PaintEventArgs e) { }
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = grafx.Graphics;
g.Clear(BackColor);
Bitmap bmp = new Bitmap(Width, Height);
foreach (Control c in Controls)
c.DrawToBitmap(bmp, new Rectangle(c.Left, c.Top, c.Width, c.Height));
g.DrawImage(bmp, 0, 0);
g.DrawLine(new Pen(Color.Red, 4), 0, 0, ClientSize.Width, ClientSize.Height);
grafx.Render(Graphics.FromHwnd(Handle));
}
private void Form1_Resize(object sender, EventArgs e)
{
context.MaximumBuffer = new Size(this.Width, this.Height);
if (grafx != null)
{
grafx.Dispose();
grafx = null;
}
grafx = context.Allocate(this.CreateGraphics(), new Rectangle(0, 0, Width, Height));
base.Refresh();
}
}
I need the line to be drawn at the top of the controls (picturebox), but the code turns out to be drawn below the controls.
Related
It is as simple as it sounds I need to draw a rectangle but no matter what I do I cant seem to get it to work. This is done on a windows form and all I want is to output one rectangle, I managed to do this at school but now at home it doesn't work.
using System.Drawing;
namespace Rectanglr
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void FormPaint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Red, 3);
Rectangle rect = new Rectangle(0, 0, 100, 100);
e.Graphics.DrawRectangle(pen, rect);
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
any help would be greatly appreciated.
You can try overriding the OnPaint method of your form:
This code should do the trick:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Pen pen = new Pen(Color.Red))
{
Rectangle rect = new Rectangle(0, 0, 100, 100);
e.Graphics.DrawRectangle(pen, rect);
}
}
}
It's also recommended to wrap it with a using block to ensure that the Pen resource will be properly disposed of when you are finished drawing.
Here's a project that I set up to draw a rectangle:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
using (Pen pen = new Pen(Color.Red, 3))
{
Rectangle rect = new Rectangle(0, 0, 100, 100);
e.Graphics.DrawRectangle(pen, rect);
}
}
}
The important part to recognize here is the partial keyword. That's a hint that there is a second file, or maybe more, that defines this class. In this case, it's the designer file - Form1.Designer.cs.
If I look in the designer I can see this line:
this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
That's the magic that makes sure this works. Without it the event isn't wired up.
Now, having said that, events are usually used by external classes to your form. The preferred approach to modify the Paint method is to override it.
That looks like this:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Pen pen = new Pen(Color.Red, 3))
{
Rectangle rect = new Rectangle(0, 0, 100, 100);
e.Graphics.DrawRectangle(pen, rect);
}
}
There's no need to wire this up as an event handler.
As a sidenote, please make sure you dispose every disposable in your code. A Pen is disposable and the using statement does the disposing for you.
The code below is showing me half part of the group box in print preview:
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) {
// Bitmap bmp = new Bitmap(groupBox1.ClientRectangle.Width, groupBox1.ClientRectangle.Height);
// groupBox1.DrawToBitmap(bmp, groupBox1.ClientRectangle);
// e.Graphics.DrawImage(bmp, 0, 0);
Bitmap bmp = new Bitmap(groupBox1.Width, groupBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
groupBox1.DrawToBitmap(bmp, new Rectangle(0, 0, groupBox1.Width, groupBox1.Height));
e.Graphics.DrawImage((Image) bmp, 0, 0);
}
private void button1_Click(object sender, EventArgs e) {
PrintPreviewDialog ppd = new PrintPreviewDialog();
PrintDocument Pd = new PrintDocument();
Pd.PrintPage += this.printDocument1_PrintPage;
ppd.Document = Pd;
ppd.ShowDialog();
}
You need to draw within the bounds of the page.
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
var g = e.Graphics;
var srcRect = new Rectangle(0, 0, groupBox1.Width, groupBox1.Height);
var desRect = new Rectangle(e.PageBounds.X, e.PageBounds.Y, e.PageBounds.Width, srcRect.Height);
//Or to draw within the margin
//var desRect = new Rectangle(e.MarginBounds.X, e.MarginBounds.Y, e.MarginBounds.Width, srcRect.Height);
using (var bmp = new Bitmap(srcRect.Width, srcRect.Height))
{
groupBox1.DrawToBitmap(bmp, srcRect);
g.DrawImage(bmp, desRect, srcRect, GraphicsUnit.Pixel);
}
}
Also, create the PrintDocument object and register its PrintPage event in the Form's constructor or Load event to avoid repeating that again and again in the button1_Click event. And don't forget to dispose the disposable objects.
I' ve drawn roundRectangle using Graphics Path OnPaintEvent
and I already added mouseevent to know if cursor was over the g.p .
void Round_MouseMove(object sender, MouseEventArgs e)
{
Point mousePt = new Point(e.X, e.Y);
if (_path != null)
if (_path.IsVisible(e.Location))
MessageBox.Show("GraphicsPath has been hovered!");
}
Question: is there a way to resize or redraw(hide previous then draw new) a graphicsPath runtime?
Invoke Invalidate for redrawn the Form, so the OnPaint(PaintEventArgs e) will be executed.
Check the following example:
public sealed partial class GraphicsPathForm : Form
{
private bool _graphicsPathIsVisible;
private readonly Pen _pen = new Pen(Color.Red, 2);
private readonly Brush _brush = new SolidBrush(Color.FromArgb(249, 214, 214));
private readonly GraphicsPath _graphicsPath = new GraphicsPath();
private Rectangle _rectangle = new Rectangle(10, 30, 100, 100);
public GraphicsPathForm()
{
InitializeComponent();
_graphicsPath.AddRectangle(_rectangle);
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.Bilinear;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.DrawPath(_pen, _graphicsPath);
if (_graphicsPathIsVisible)
g.FillPath(_brush, _graphicsPath);
base.OnPaint(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
var isVisible = _graphicsPath.IsVisible(e.Location);
if (isVisible == _graphicsPathIsVisible)
return;
const int zoom = 5;
if (isVisible)
{
if (!_graphicsPathIsVisible)
{
_rectangle.Inflate(zoom, zoom);
_graphicsPath.Reset();
_graphicsPath.AddRectangle(_rectangle);
}
}
else
{
if (_graphicsPathIsVisible)
{
_rectangle.Inflate(-zoom, -zoom);
_graphicsPath.Reset();
_graphicsPath.AddRectangle(_rectangle);
}
}
_graphicsPathIsVisible = isVisible;
Invalidate();
base.OnMouseMove(e);
}
}
I hope it helps.
I want to save image from panel to bitmap and then I want to load the saved image after my Form comes out of minimizing mode.
Bitmap bmp = new Bitmap(panel1.Width, panel1.Height);
panel1.DrawToBitmap(bmp, panel1.Bounds);
bmp.Save(#"C:\Test");
panel1.BackgroundImage = Image.FromFile(#"C:\Test");
And what event should I use for minimizing event?
P.S. I am a C# beginner.
EDITED
Drawing your panel's contents. This should be done inside its Paint event handler, like this:
private void panel1_Paint(object sender, PaintEventArgs e)
{
using (Pen p = new Pen(Color.Red, 3))
{
// get the panel's Graphics instance
Graphics gr = e.Graphics;
// draw to panel
gr.DrawLine(p, new Point(30, 30), new Point(80, 120));
gr.DrawEllipse(p, 30, 30, 80, 120);
}
}
Saving your panel's contents as an image. This part should be done somewhere else (for example, when you click on a "Save" button):
private void saveButton_Click(object sender, EventArgs e)
{
int width = panel1.Size.Width;
int height = panel1.Size.Height;
using (Bitmap bmp = new Bitmap(width, height))
{
panel1.DrawToBitmap(bmp, new Rectangle(0, 0, width, height));
bmp.Save(#"C:\testBitmap.jpeg", ImageFormat.Jpeg);
}
}
I am trying to print a form using this code:
private void btnPrint_Click(object sender, EventArgs e)
{
Graphics g1 = this.CreateGraphics();
Image MyImage = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height, g1);
Graphics g2 = Graphics.FromImage(MyImage);
IntPtr dc1 = g1.GetHdc();
IntPtr dc2 = g2.GetHdc();
BitBlt(dc2, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height, dc1, 0, 0, 13369376);
g1.ReleaseHdc(dc1);
g2.ReleaseHdc(dc2);
MyImage.Save(#"c:\PrintPage.jpg", ImageFormat.Jpeg);
FileStream fileStream = new FileStream(#"c:\PrintPage.jpg", FileMode.Open, FileAccess.Read);
StartPrint(fileStream, "Image");
fileStream.Close();
if (System.IO.File.Exists(#"c:\PrintPage.jpg"))
{
System.IO.File.Delete(#"c:\PrintPage.jpg");
}
}
But is gives me an error at: MyImage.Save.
The error:
ExternalException was Unhandled: A generic error occurred in GDI+.
Can someone give me a fix for this problem,and explain, why I'am getting this error?
Thanks in Advance!
private void btn_print_Click(object sender, EventArgs e)
{
CaptureScreen();
printDocument1.Print();
printDocument1.PrintPage += new PrintPageEventHandler(printDocument1_PrintPage);
}
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 printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
}
private void printDocument1_PrintPage_1(object sender, PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
Add a print_document by dragging it from the toolbox to form. Execute this code, it will work fine.
http://csharpprobsandsoln.blogspot.in/2013/04/print-windows-form-in-c.html
Add:
using System.Drawing.Printing;
and in your code, add:
PrintDocument printDocument1 = new PrintDocument();
More info here
I had the same task and I have created a class (like printable form).
All you have to do is to inherit your Form from that class and call PrintForm(); method.
Here is the class:
public class CustomForm : Form
{
protected Bitmap _prnImage;
protected PrintPreviewDialog _prnpreviewdlg = new PrintPreviewDialog();
protected PrintDocument _printdoc = new PrintDocument();
public CustomForm()
{
_printdoc.PrintPage += new PrintPageEventHandler(printdoc_PrintPage);
}
protected void PrintForm()
{
Form form = this;
_prnImage = new Bitmap(form.Width, form.Height);
form.DrawToBitmap(_prnImage, new Rectangle(0, 0, form.Width, form.Height));
_printdoc.DefaultPageSettings.Landscape = true;
_printdoc.DefaultPageSettings.Margins = new Margins(10, 10, 10, 10);
_prnpreviewdlg.Document = _printdoc;
_prnpreviewdlg.ShowDialog();
}
protected void printdoc_PrintPage(object sender, PrintPageEventArgs e)
{
Rectangle pagearea = e.PageBounds;
e.Graphics.DrawImage(_prnImage, e.MarginBounds);
}
protected override void OnPaint(PaintEventArgs e)
{
if (_prnImage != null)
{
e.Graphics.DrawImage(_prnImage, 0, 0);
base.OnPaint(e);
}
}
}
I understand that interface is a more academic and correct way to do that but in my particular case that solution satisfied me.