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;
}
}
Related
So I am trying to create a smart crosshair controlled by win 10 voice recognition engine for a game.
The form 1 is used to turn on and turn off voice recognition .If it hears my saying "slow", it will draw a line on another transparent overlaying form
public partial class Form1 : Form
{
formoverlay overlayform = new formoverlay();
SpeechRecognitionEngine dasSpeechEngine = new SpeechRecognitionEngine();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
dasSpeechEngine.RecognizeAsync(RecognizeMode.Multiple);
btnDisable.Enabled = true;
}
private void Form1_Load(object sender, EventArgs e)//load event
{
Choices commands = new Choices();
commands.Add(new string[] { "slow", "medium", "fast","ultra","x"});
GrammarBuilder gbuilder = new GrammarBuilder();
gbuilder.Append(commands);
Grammar thegrammar = new Grammar(gbuilder);
dasSpeechEngine.LoadGrammarAsync(thegrammar);
dasSpeechEngine.SetInputToDefaultAudioDevice();
dasSpeechEngine.SpeechRecognized += dasSpeechEngine_SpeechRecognized;
overlayform.timestart = DateTime.Now.Second;
//MessageBox.Show(overlayform.timestart.ToString());
//for (si=1,si)
}
private void dasSpeechEngine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
switch (e.Result.Text)
{
case "slow":
if (ModifierKeys.HasFlag(Keys.Control))//prevent accidentally sight change
{
//clear current canvas
//draw all the lines that has true bool flag
//draw all the marks
overlayform.theclearform();
overlayform.paintHorline(15, slowAimSet.lineStartY,slowAimSet.lineEndY,1);
break;
}
break;
}
}
}
On the overlay form, the code (not including the partial class declaration):
Graphics g;
Pen myPen = new Pen(Color.Green);
Pen smallPen = new Pen(Color.GreenYellow);
public formoverlay()
{
InitializeComponent();
}
private void formoverlay_Load(object sender, EventArgs e)
{
this.BackColor = Color.Wheat;
this.TransparencyKey = Color.Wheat;
this.TopMost = true;
this.FormBorderStyle = FormBorderStyle.None;
int initialStyle = GetWindowLong (this.Handle, -20);
SetWindowLong(this.Handle, -20, initialStyle | 0x80000 | 0x20);
//enable click through
//get wows window size;
GetWindowRect(handle, out rect);
this.Size = new Size(rect.right - rect.left, rect.bottom - rect.top);
this.Top = rect.top;
this.Left = rect.left;
smallPen.Width = 2.0f;
}
public void paintHorline(int theTgtSpd,int tStartY, int tEndY, int thisRngMarkerDir)
{
int rngMarkerOffset = 10;
//aimlineForSpeed[] thisAimLine = new aimlineForSpeed [4];
//g.DrawLine(myPen, 500,500, 600, 600);
g.DrawLine(myPen, 0,tStartY, 1920, tEndY);
}
public void theclearform()//everytime user say, re-draw everything
{
Invalidate();
}
When I run the program, when I say "slow", there us an errorenter image description here
saying system argument exception: {"Parameter is not valid."}
It does not make any difference if I write constant values in my draw calls, for example, g.DrawRectangle(myPen, 100, 100, 200,200);
Apparently, the program calls "painthorline" function, but it does not draw correctly.
If I create a new graphics in painthorline method, it won't cause this error, but it does not draw anything at all..
Where did I go wrong?
Did I need to create a sperate event in order to get the drawline/drawrectangle call works?
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
}
I'm trying to dynamically create a picture box by clicking a button. However, I want to have the code that creates the picture box (and also creates some graphs in that picture box) in a dll file. When i move the code from my main form to a method in a dll file and then call that method in the button click event in my main form nothig happens.
I've been searching high and low for an answer but with little success. The most relevant thing that I found is here. However, I struggle to create an instance of my main form to pass to the method in the dll...The answer might be bluntly obvious but I am very new to c#... Also, I am using Visual Studio 2013 if that is of any relevance.
Here is the method in the dll:
namespace DrillGraph
{
public class DrillGraph : UserControl
{
public DrillGraph() { }
public void CreateGraph()
{
PictureBox pb = new PictureBox();
pb.Dock = DockStyle.Fill;
pb.BackColor = Color.Bisque;
pb.Name = "pb";
pb.Size = new Size(50, 50);
pb.Location = new Point(20, 20);
Graphics g = pb.CreateGraphics();
g.DrawEllipse(new Pen(Color.Red), 0, 0, 50, 50);
this.Controls.Add(pb);
}
}
}
And this is what i have in my main form:
using DrillGraph;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
DrillGraph.DrillGraph dg = new DrillGraph.DrillGraph();
private void button1_Click(object sender, EventArgs e)
{
dg.CreateGraph();
}
}
}
Adding where? you should provide the reference in your dll.
public void CreateGraph(Panel pnl)
{
PictureBox pb = new PictureBox();
pb.Dock = DockStyle.Fill;
pb.BackColor = Color.Bisque;
pb.Name = "pb";
pb.Size = new Size(50, 50);
pb.Location = new Point(20, 20);
Graphics g = pb.CreateGraphics();
g.DrawEllipse(new Pen(Color.Red), 0, 0, 50, 50);
pnl.Controls.Add(pb);
}
Then call below code
dg.CreateGraph(YourPanelName From Form);
I have a window form. I want to print the contents of the form without the window appearance. I mean I want to print it like a receipt, without window borders. How do I do this?
You can take the MSDN example on how to Print to a Windows Form, Change the Surface being printed from the Form to a Panel Control, which will enable you to print without Borders. Your Contents will have to be added to the Panel instead of the Form but it will work. Here is a modified example of the MSDN example.
public class Form1 : Form
{
private Panel printPanel = new Panel();
private Button printButton = new Button();
private PrintDocument printDocument1 = new PrintDocument();
public Form1()
{
printPanel.Size = this.ClientSize;
this.Controls.Add(printPanel);
printButton.Text = "Print Form";
printButton.Click += new EventHandler(printButton_Click);
printDocument1.PrintPage += new PrintPageEventHandler(printDocument1_PrintPage);
printPanel.Controls.Add(printButton);
}
void printButton_Click(object sender, EventArgs e)
{
CaptureScreen();
printDocument1.Print();
}
Bitmap memoryImage;
private void CaptureScreen()
{
Graphics myGraphics = printPanel.CreateGraphics();
Size s = printPanel.Size;
memoryImage = new Bitmap(s.Width, s.Height, myGraphics);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
Point screenLoc = PointToScreen(printPanel.Location); // Get the location of the Panel in Screen Coordinates
memoryGraphics.CopyFromScreen(screenLoc.X, screenLoc.Y, 0, 0, s);
}
private void printDocument1_PrintPage(System.Object sender,
System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
public static void Main()
{
Application.Run(new Form1());
}
}
you can just get a blank screen by doing something like this
this.FormBorderStyle = System.Windows.Forms.FormsBorderStyle.None;
this.ControlBox = false;
this.Text = String.Empty;
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 :-)