C# DoubleBuffered = white screen - c#

I'm trying to make a simple animated program, which do things whenever i click the button. Whenever that happens though i experience flickering, because the program is drawing a "huge" (1000x700px) bitmap. I want to get rid of that flickering.
I heard that it can be solved using DoubleBuffered, but if i add it, the graphics are not displaying at all. Instead i got my panel will full white background and my single button only.
Could anybody explain me what am i doing wrong?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace test
{
public partial class Form1 : Form
{
private static Bitmap graf_bufor = new Bitmap(1000, 700); //create huge bitmap
static Image green_one = Image.FromFile("green.png"); //load sprite
static int hero = 0; //create "hero" variable for looping
public Form1()
{
InitializeComponent();
//DoubleBuffered = true;
/**
* Without DoubleBuffered:
* Screen flickers when Refresh();
* With BoudleBuffered:
* The whole panel is white rectangular
**/
}
private void button1_Click(object sender, EventArgs e)
{
using (Graphics gr = Graphics.FromImage(graf_bufor)) //call "gr"
{
gr.Clear(Color.Black); //clear screen
gr.DrawImage(green_one, 0+(hero*32), 0); //draw sprite
}
hero = hero + 1; //adjust "hero" variable. not important.
if (hero == 4)
{
hero = 0;
};
this.Refresh(); //refresh panel
}
private void Form1_Paint(object sender, PaintEventArgs e) //painting event
{
Graphics mr_sanchez = e.Graphics; //call Mr Sanchez
mr_sanchez.DrawImage(graf_bufor, 0, 0); //Mr Sanchez draws bitmap
mr_sanchez.Dispose(); //Well done Mr Sanchez
}
}
}
Designer:
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(1107, 561);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1220, 768);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
this.ResumeLayout(false);
}

From my comment: you don't dispose objects you didn't create. Don't do this:
mr_sanchez.Dispose();
A paint event is "passing" a graphic object to you. You aren't creating it, you are simply "referencing" it when you do this:
Graphics mr_sanchez = e.Graphics;
This is different from your earlier code, where you correctly dispose the graphic object you created in this code:
using (Graphics gr = Graphics.FromImage(graf_bufor)) //call "gr"
{
gr.Clear(Color.Black); //clear screen
gr.DrawImage(green_one, 0+(hero*32), 0); //draw sprite
}

Related

winform not loading to its full size while drawing

I just want to draw random rectangles on the form on form1 click event.
What is causing my form to not load to its full size, for example i set it to be 800x600 and when i start the program it looks like this:form1
Also i cant resize it, when i try to do it form just flickers.
I'm just drawing in paint event and invalidating on click, is this code wrong in general? I realize something is overriding it and refreshing it before it can load, sorry for this beginner question but i couldn't find the answer anywhere
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Random rand = new Random();
int pos = rand.Next(0, 100);
Rectangle rect = new Rectangle(pos, pos, 50, 50);
Pen pen = new Pen(Color.Green, Width = 2);
g.DrawRectangle(pen, rect);
}
private void Form1_Click(object sender, EventArgs e)
{
Invalidate();
}
Designer code:
Basically just initialize component and classic override void dispose above.
private void InitializeComponent()
{
this.SuspendLayout();
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(630, 522);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.Click += new System.EventHandler(this.Form1_Click);
this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
this.ResumeLayout(false);
}
Problem is this: "Pen pen = new Pen(Color.Green, Width = 2);" It sets Width of the form to 2. You can write it as:
Pen pen = new Pen(Color.Green, width: 2);
or just
Pen pen = new Pen(Color.Green, 2);

Remove color gradient from scaled unit bitmap

I am trying to create a xs by ys red Bitmap and am having issues.
My function to do so looks like this: (Ref: https://stackoverflow.com/a/12502878/1596244)
private Bitmap getBlankBitmap(int xs, int ys)
{
Bitmap b = new Bitmap(1, 1);
b.SetPixel(0, 0, Color.Red);
return new Bitmap(b, xs, ys);
}
Though the issue is, this creates a color gradient across the Bitmap, I just want each pixel to be the color specified. How can I remove this gradient and "fully" color the Bitmap?
Here is the constructor I am using http://msdn.microsoft.com/en-us/library/334ey5b7.aspx which doesn't mention adding a gradient at all, I'm not even sure why that would be the default behavior.
Here is an SSCCE to work with
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestProject2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
showIssue();
}
void showIssue()
{
pictureBox1.Image = getBlankBitmap(pictureBox1.Size.Width, pictureBox1.Size.Height);
}
private Bitmap getBlankBitmap(int xs, int ys)
{
Bitmap b = new Bitmap(1, 1);
b.SetPixel(0, 0, Color.Red);
return new Bitmap(b, xs, ys);
}
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.pictureBox1 = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.pictureBox1.Location = new System.Drawing.Point(0, 0);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(477, 344);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(477, 344);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
private System.Windows.Forms.PictureBox pictureBox1;
}
}
Just create a new bitmap with the size you want and paint it red:
private Bitmap getBlankBitmap(int width, int height) {
Bitmap b = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(b)) {
g.Clear(Color.Red);
}
return b;
}

Can I draw shapes within buttons?

I've been reading stackoverflow for a while now just to learn, and I've come across a situation where I can finally ask a question. I'm making a Simon Says type memory game, where I flash shapes at the user, and the user has to click a button in the same order the shapes were shown to them. I want to draw the shape that I'm drawing on the screen within the button that they are clicking because it's much easier to remember and compare shapes to shapes rather than shapes to a button that says the shapes name.
Hopefully my question is clear, and thanks for taking a look!
Yes, you can set the Image property of Button. Alternatively, you can draw non-rectangular buttons, that is, buttons of any shape. The following code demonstrates both techniques:
using System;
using System.Drawing;
using System.Windows.Forms;
class ShapeButton : Button {
public Action<PaintEventArgs> DoPaint { get; set; }
protected override void OnPaint(PaintEventArgs e) {
if (DoPaint != null) { DoPaint(e); }
}
}
static class Program {
static void Main() {
// Ellipse button
ShapeButton ellipseButton = new ShapeButton();
ellipseButton.Location = new Point(10, 10);
ellipseButton.Size = new Size(80, 80);
ellipseButton.DoPaint = delegate(PaintEventArgs e) {
Graphics graphics = e.Graphics;
SolidBrush brush1 = new SolidBrush(SystemColors.ButtonFace);
graphics.FillRectangle(brush1, 0, 0, ellipseButton.Width, ellipseButton.Height);
SolidBrush brush2 = new SolidBrush(Color.Red);
graphics.FillEllipse(brush2, 0, 0, ellipseButton.Width, ellipseButton.Height);
};
ellipseButton.Click += delegate(object sender, EventArgs e) {
MessageBox.Show("Ellipse!");
};
// Triangle button
ShapeButton triangleButton = new ShapeButton();
triangleButton.Location = new Point(100, 10);
triangleButton.Size = new Size(80, 80);
triangleButton.DoPaint = delegate(PaintEventArgs e) {
Graphics graphics = e.Graphics;
SolidBrush brush1 = new SolidBrush(SystemColors.ButtonFace);
graphics.FillRectangle(brush1, 0, 0, triangleButton.Width, triangleButton.Height);
SolidBrush brush2 = new SolidBrush(Color.Green);
Point[] points = {
new Point(triangleButton.Width / 2, 0),
new Point(0, triangleButton.Height),
new Point(triangleButton.Width, triangleButton.Height)
};
graphics.FillPolygon(brush2, points);
};
triangleButton.Click += delegate(object sender, EventArgs e) {
MessageBox.Show("Triangle!");
};
// Star button (using image)
Button starButton = new Button();
starButton.Location = new Point(190, 10);
starButton.Size = new Size(80, 80);
starButton.Image = new Bitmap("Star.png");
starButton.Click += delegate(object sender, EventArgs e) {
MessageBox.Show("Star!");
};
// The form
Form form = new Form();
form.Text = "Shape Button Test";
form.ClientSize = new Size(280, 100);
form.Controls.Add(ellipseButton);
form.Controls.Add(triangleButton);
form.Controls.Add(starButton);
form.ShowDialog();
}
}
Result (after clicking on the triangle button):
In winforms to change the button's image at runtime you can use something like this:
button1.Image = new Bitmap(Image.FromFile(#"Pictures\Koala.jpg"));
It should be added to event handler. For example if you want to show the image when the button is clicked you subscribe to Click event of the button and add the code into the handler method:
private void button1_Click(object sender, EventArgs e)
{
button1.Image = new Bitmap(Image.FromFile(#"Pictures\Koala.jpg"));
}
In my example,
I have a pictureBox to show, two buttons, one to control, one to be drawn.
//odd display, even draw
int count = 0;
Image storePicture;
//whenever the background image changed,store it
private void pictureBoxShow_BackgroundImageChanged(object sender, EventArgs e)
{
//you can stored to a Image array if you have series pictures to show
storePicture = pictureBoxShow.BackgroundImage;
}
private void buttonControl_Click(object sender, EventArgs e)
{
count++;
//odd show picture, even draw picture on button
if (count % 2 == 1)
pictureBoxShow.BackgroundImage = new Bitmap("shapes.JPG");
else
{
//in case you want to clear text on the button
buttonDrawn.Text = null;
//recreate the picture so that it fit the button size
buttonDrawn.Image = new Bitmap(storePicture, new Size(buttonDrawn.Width, buttonDrawn.Height));
}
}
Please remember to attach the handlers to corresponding events. ^^
Why not using PictureBox instead of Buttons.
you have just to add your task to its event/OnClick
Of course you can load any Image to any PictureBox in runtime
The code above is great, however you can click outside the circle within a square containing the circle and get the click event.
If you want to capture the click only if the user clicks inside the shape you have to set the region property with something like this
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(0, 0, 100, 100);
Button1.Region = new Region(gp);
}
}

Printing a Form/UserControl in C#

My Program: Contains a form with few textboxes and one button. 'Default Printer' is set as Adobe PDF on my computer.
My Goal: Want to take a screenshot of a form/usercontrol when the user clicks 'Print' button. The screenshot is then saved on the desktop in .pdf format.
My Problem: I have following two problems with the code:
Size of Screenshot: The size of the screenshot is too big and it does not fit the size of the page (default page size) when printed/converted to .pdf. Please refer the two images below. I want the entire screenshot to fit inside the page.
Asks twice where to convert and save: When I click on 'Print Form' button, programs asks me TWICE where to print/convert and save the file. I want the program to ask me only Once, where to print and save the file.
Problem 1: The screenshot captured by the program does not fit the page when printed.
I want the screenshot image to fit like this on one page of .pdf:
Code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
button1.Text = "Print Form";
button1.Click += new EventHandler(button1_Click);
printDocument1.PrintPage += new PrintPageEventHandler(printDocument1_PrintPage);
this.Controls.Add(button1);
}
private void button1_Click(object sender, EventArgs e)
{
CaptureScreen();
printDocument1.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 printDocument1_PrintPage(System.Object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
}
Thanks for your help in advance. I am a newbie, learning c# language and your help will be much appreciated. :)
Ok, check this out, and the modified printDocument1_PrintPage in particular:
private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
// calculate width and height scalings taking page margins into account
var wScale = e.MarginBounds.Width / (float)_memoryImage.Width;
var hScale = e.MarginBounds.Height / (float)_memoryImage.Height;
// choose the smaller of the two scales
var scale = wScale < hScale ? wScale : hScale;
// apply scaling to the image
e.Graphics.ScaleTransform(scale, scale);
// print to default printer's page
e.Graphics.DrawImage(_memoryImage, 0, 0);
}
I moved all the event wireup into InitializeComponent where it's usually supposed to go but it's more involved code:
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
namespace testScreenCapScale
{
public partial class Form1 : Form
{
public Form1() { InitializeComponent(); }
private void button1_Click(object sender, EventArgs e)
{
CaptureScreen();
printDocument1.Print();
}
private Bitmap _memoryImage;
private void CaptureScreen()
{
// put into using construct because Graphics objects do not
// get automatically disposed when leaving method scope
using (var myGraphics = CreateGraphics())
{
var s = Size;
_memoryImage = new Bitmap(s.Width, s.Height, myGraphics);
using (var memoryGraphics = Graphics.FromImage(_memoryImage))
{
memoryGraphics.CopyFromScreen(Location.X, Location.Y, 0, 0, s);
}
}
}
private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
// calculate width and height scalings taking page margins into account
var wScale = e.MarginBounds.Width / (float)_memoryImage.Width;
var hScale = e.MarginBounds.Height / (float)_memoryImage.Height;
// choose the smaller of the two scales
var scale = wScale < hScale ? wScale : hScale;
// apply scaling to the image
e.Graphics.ScaleTransform(scale, scale);
// print to default printer's page
e.Graphics.DrawImage(_memoryImage, 0, 0);
}
}
}
Form1.Designer.cs
namespace testScreenCapScale
{
partial class Form1
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.printDocument1 = new System.Drawing.Printing.PrintDocument();
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// printDocument1
//
this.printDocument1.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(this.printDocument1_PrintPage);
//
// button1
//
this.button1.Location = new System.Drawing.Point(64, 220);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(384, 377);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
private System.Drawing.Printing.PrintDocument printDocument1;
private System.Windows.Forms.Button button1;
}
}

How to draw a screenshot "preview" window?

I have a Winforms application that the user uses to take a region based screenshot. I want to have a small preview pane, but i'm not sure how to do it. So far i tried recreating a bitmap on mouse move and its just way too laggy to be usable. So i thought if i used a pre-defined image (screenshot of the whole screen) and moved it inside the picturebox based off the mouse location so that you get a zoomed in look at the screen (to select the precise pixels you want to take the screenshot with easier). I'm not sure how i can implement this, i am also pretty new to drawing so i will show you what i have now.
private void falseDesktop_MouseMove(object sender, MouseEventArgs e)
{
zoomBox.Image = showZoomBox(e.Location);
zoomBox.Invalidate();
}
private Image showZoomBox(Point curLocation)
{
int x = 0;
int y = 0;
if (curLocation.X - 12 <= 0)
{
x = curLocation.X - 12;
}
else
{
x = curLocation.X;
}
if (curLocation.Y - 11 <= 0)
{
y = curLocation.Y - 11;
}
else
{
y = curLocation.Y;
}
Point start = new Point(curLocation.X - 12, curLocation.Y - 11);
Size size = new Size(24, 22);
Rectangle rect = new Rectangle(start, size);
Image selection = cropImage(falseDesktop.Image, rect);
return selection;
}
private static Image cropImage(Image img, Rectangle cropArea)
{
if (cropArea.Width != 0 && cropArea.Height != 0)
{
Bitmap bmpImage = new Bitmap(img);
Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
bmpImage.Dispose();
return (Image)(bmpCrop);
}
return null;
}
EDIT:
Here is a mock up like requested:
The black part of this image is a panel, of course the text being a label and the area where you see the image (stack overflow) would be the picturebox (called zoomBox) the lines on top of the zoomBox would be a guide and where the 2 lines intersect would be the mouse position. Hope this is a better assist to help you understand my issue.
Another thing that might help explain my issue is The form actually fills the entire screen with a "false desktop". its a picturebox that covers the entire screen with a screenshot of the desktop when "printscreen" was pressed. So I want this little "preview pane" to basically be a zoomed in location of where the mouse is.
This is a little bit laggy, but worth a try:
It's a WInForms app in a single file showing how a "live" zoom might work. It doesn't paint the cross hairs etc. that's up to you.
Key Parts:
_scale
PictureBoxSizeMode.StretchImage
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
public class Form1 : Form {
private Bitmap _myImage = new Bitmap(#"C:\Users\Public\Pictures\Sample Pictures\LightHouse.jpg");
private int _scale = 10; // keep this < 15
private PictureBox pboxMain;
private PictureBox pboxZoom;
private System.ComponentModel.IContainer components;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
pboxMain.Image = _myImage;
}
private void pboxMain_MouseMove(object sender, MouseEventArgs e) {
try {
Rectangle rc = new Rectangle(
new Point(e.X - _scale, e.Y - _scale),
new Size(_scale * 2, _scale * 2));
pboxZoom.Image = _myImage.Clone(rc, PixelFormat.DontCare);
}
catch (OutOfMemoryException ex) {/* ignore... */}
}
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent() {
this.pboxMain = new PictureBox();
this.pboxZoom = new PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pboxMain)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pboxZoom)).BeginInit();
this.SuspendLayout();
this.pboxMain.Dock = DockStyle.Fill;
this.pboxMain.Location = new System.Drawing.Point(0, 0);
this.pboxMain.Name = "pboxMain";
this.pboxMain.Size = new System.Drawing.Size(767, 435);
this.pboxMain.TabIndex = 0;
this.pboxMain.TabStop = false;
this.pboxMain.MouseMove += new MouseEventHandler(this.pboxMain_MouseMove);
this.pboxZoom.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))),
((int)(((byte)(255)))), ((int)(((byte)(192)))));
this.pboxZoom.BorderStyle = BorderStyle.FixedSingle;
this.pboxZoom.Location = new System.Drawing.Point(12, 12);
this.pboxZoom.Name = "pboxZoom";
this.pboxZoom.Size = new System.Drawing.Size(106, 83);
this.pboxZoom.SizeMode = PictureBoxSizeMode.StretchImage;
this.pboxZoom.TabIndex = 1;
this.pboxZoom.TabStop = false;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(767, 435);
this.Controls.Add(this.pboxZoom);
this.Controls.Add(this.pboxMain);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.pboxMain)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pboxZoom)).EndInit();
this.ResumeLayout(false);
}
}
This should be of great help TeboScreen: Basic C# Screen Capture
Why reinvent the Wheel :-)

Categories

Resources