I'm trying to get my screen shot image to be displayed in a picture box held on my Control panel form. But the image is not getting passed over.
I have been informed that the issue may be laying within the following lines of code:
ScreenCapture capture = new ScreenCapture();
capture.CaptureImage(showCursor, curSize, curPosition, startPoint, Point.Empty, bounds, _screenPath, fi);
As I'm creating a new screen capture, the data isn't getting passed over to the my picture box. When I run my program the errors originate with the following lines always returning null:
Image img = (Image)bitmap;
if (OnUpdateStatus == null) return;
ProgressEventArgs args = new ProgressEventArgs(img);
OnUpdateStatus(this, args);
Then in my control panel winform I'm trying to display the image as follows:
private ScreenCapture _screenCap;
public ControlPanel()
{
InitializeComponent();
_screenCap = new ScreenCapture();
_screenCap.OnUpdateStatus += _screen_CapOnUpdateStatus;
}
private void _screen_CapOnUpdateStatus(object sender, ProgressEventArgs e)
{
imagePreview.Image = e.CapturedImage;
}
The advice I was given was as follows:
You're looking at the value of OnUpdateStatus within the CaptureImage
method, right? So it matters which instead of ScreenCapture you call
the method on. I suspect you need to pass _screenCap to the
constructor of Form1 (which would need to store it in a field) so that
you could use the same instance when you call CaptureImage within
Form1
I have no idea how to implement the advice that was given to me. In my first two lines of code I simply tried to take away the creation of a new instance of my ScreenCapture class and write
ScreenCapture.CaptureImage(showCursor, curSize, curPosition, startPoint, Point.Empty, bounds, _screenPath, fi);
But this generates the following error:
Error 1 An object reference is required for the non-static field, method, or property 'DotFlickScreenCapture.ScreenCapture.CaptureImage(bool, System.Drawing.Size, System.Drawing.Point, System.Drawing.Point, System.Drawing.Point, System.Drawing.Rectangle, string, string)'
So to get rid of this error I turned the Method being called to a static class but this generated a whole host of different errors with my code trying to store the image taken:
Image img = (Image)bitmap;
if (OnUpdateStatus == null) return;
ProgressEventArgs args = new ProgressEventArgs(img);
OnUpdateStatus(this, args);
It claims that my OnUpdateStatus require an object reference and that using the THIS keyword where I have is not valid in a static field or environment.
Is anyone able to help with getting my image to be displayed in an image box?
Sincerely I could not understand your code. But I understood the advice was given to you. It says that pass the object of captured screen to the form's constructor:
Lets say you have a form name form1. Here is the constructor and little code you must have in the form1 class:
public partial class Form1 : Form
{
Image CapturedImage;
public Form1(Image imgObj) //"you need to pass _screenCap to the constructor of Form1"
{
InitializeComponent();
CapturedImage = imgObj; //"which would need to store it in a field"
}
}
The constructor is taking the captured image as an object(Image imgObj) and assign it to the field(Image CapturedImage;).
If you want to display it in the picturebox. Simply add this line in the constructor as well:
picturebox.Image = CapturedImage;
Now to call it from another form, do it like this:
Capture screen as you are doing (your first code is correct in which you create object of ScreenCapture class) and save it in an object:
Image CapturedImageObj = capture.CaptureImage(showCursor, curSize, curPosition, startPoint, Point.Empty, bounds, _screenPath, fi);
Now create instance of form1 and pass captured image to the constructor of the form:
form1 ImageForm = new form1(CapturedImageObj);
and display it:
form1.Show();
Related
I am trying to print automatically a series of Windows-Forms. I don't need to show them. The code examples I found on the internet work only when I display the Form with show()! I need to initialize the form with data and send it to the printer Here is the code I am using:
public partial class Form2_withoutShow : Form{
PrintDocument PrintDoc;
Bitmap memImage;
public Form2_withoutShow (Data data)
{
InitializeComponent();
/*
Initialize Data (texboxes, charts ect.) here
*/
this.PrintDoc = new PrintDocument();
this.PrintDoc.PrintPage += PrintDoc_PrintPage;
this.PrintDoc.DefaultPageSettings.Landscape = true;
}
public void Print()
{
this.PrintDoc.Print();
}
void PrintDoc_PrintPage(object sender, PrintPageEventArgs e)
{
int x = SystemInformation.WorkingArea.X;
int y = SystemInformation.WorkingArea.Y;
int width = this.Width;
int height = this.Height;
Rectangle bounds = new Rectangle(x, y, width, height);
Bitmap img = new Bitmap(width, height);
this.DrawToBitmap(img, bounds);
Point p = new Point(10, 10);
e.Graphics.DrawImage(img, p);
}
private void Form2_withoutShow_Load(object sender, EventArgs e)
{
// remove TITLEBar
this.ControlBox = false;
this.Text = String.Empty;
}
}
I call the Print() method from another class in for-loop and pass the Data to be initialized through the constructor.
The MSDN example captures the part on the screen where the forms should be displayed. This doesn't work for me. The approach I am using now yields only the print of the empty Window if I don't call show(). How do I get the data into the form without having to call the show() method? Approaches like mimize the windows when displaying it, also don't work because that is also the print result: a minimized window.
Before showing the form, the form and its controls are not in Created state. To force the form and its controls to be created it's enough to call internal CreateControl(bool fIgnoreVisible) method of your form:
var f = new Form1();
var createControl = f.GetType().GetMethod("CreateControl",
BindingFlags.Instance | BindingFlags.NonPublic);
createControl.Invoke(f, new object[] { true });
var bm = new Bitmap(f.Width, f.Height);
f.DrawToBitmap(bm, new Rectangle(0, 0, bm.Width, bm.Height));
bm.Save(#"d:\bm.bmp");
Also remove codes which you have in your form Load event handler, and put them in constructor of your form.
Note
There are also other workarounds for the problem:
For example you can show the form in a location outside of boundary of the screen and then hide it again. Set the Location to (-32000, -32000) and set StartPosition to be Manual then Show and Hide the form before drawing to bitmap.
Or as another example, you can show the form with Opacity set to 0 and then Show and Hide the form before drawing to bitmap.
I'am using winforms.
I created an application which is nearly finished. Consider the following: I have two forms, the first form starts at application startup, the second form needs to be opened right next to the first form.
Example:
How can I access the location of the first form at the second form? Should I send "this" to the constructor of the second form?
EDIT
following code helped me out:
private void changelogToolStripMenuItem_Click(object sender, EventArgs e)
{
if (_changelog.IsDisposed)
{
_changelog = new Changelog();
}
_changelog.Location = new Point((Left + Width), Top);
_changelog.Show();
}
A basic rule to keep in mind when designing one's constructor: Never give any unnecessary information to the constructor.
So, what you need here is not the other window, but rather it's position.
Even better, you need the position where your new window should be located at.
This means that you shouldn't let the second form know about the first form, instead it's constructor should take either:
One parameter Point location
Two parameters int x, int y
Depending on your preferance.
You could (should) of course have both constructors, so you can decide whether to give Point location or int x, int y.
This all being said, forget what you read.
Better than using a constructor at all, I would just set the property manually when creating the second form:
SecondForm form = new SecondForm()
{
Location = new Point(this.Right, this.Top)
};
Which is just an other way of saying:
SecondForm form = new SecondForm();
form.Location = new Point(this.Right, this.Top);
Why do not position the new form when you open it?
Form2 f = Form2();
f.Location = new Point(this.Left + this.Width, this.Top);
f.Show(); // Or ShowDialog()
Of course, this requires that the second form property StartPosition is set to FormStartPosition.Manual
I already had an image inside PictureBox control, and now I want to pass a new one to it.
What happens, is that allpication Disposes (and I catch an exception: "Parameter is not valid").
This is my code:
using (Image img = Image.FromFile(open.FileName))
{
part.Picture = img;
pictureBox1.InitialImage = null;
pictureBox1.Image = img;
}
So when the code goes out of the method, it goes streight to Displose of this and main form. I catch the exception only on line where Form1 was started. On this one there is no excpetions what so ever.
It must be something wrong while pictureBox is painting (inside Paint event), but I am not surbsribed to it.
I really dont have any more clue how to salve this issue. I have even tried to use to clear all resources (by calling garbage collection), but nothing seems to work.
One more thing: "part" is a reference of the List, so when I try to Delete the current image (to replace it with a new one) I got another exception, like:
"The process cannot access the file because it is being used by another process".
Does this has something to do with the 1st exception (when new image is not painted in pictureBox)?
As Reed noted, the Image you are pulling from open.Filename is being disposed once you exit the using() statement. Your picturebox is still referencing this image in memory, so when it is disposed, you lose what was stored in your picturebox too.
What you really need is a unique copy of the image you are pulling.
using (Image sourceImg = Image.FromFile(open.Filename))
{
Image clonedImg = new Bitmap(sourceImg.Width, sourceImg.Height, PixelFormat.Format32bppArgb);
using (var copy = Graphics.FromImage(clonedImg))
{
copy.DrawImage(sourceImg, 0, 0);
}
pictureBox1.InitialImage = null;
pictureBox1.Image = clonedImg;
}
This way, your file will be unlocked as soon as you exit this block, and you'll keep a unique copy of your image in the picturebox.
The problem is that, after this code executes, pictureBox1.Image is referring to an Image which has been disposed.
If you do not wrap the Image creation in a using, it should correct your issue.
Image img = Image.FromFile(open.FileName);
part.Picture = img;
pictureBox1.InitialImage = null;
pictureBox1.Image = img; // You can't dispose of this, or it won't be valid when PictureBox uses it!
You could also do something like the following create a method that loads the images and then pass it back to the Image Control for example this is what I am using when I want to populate an Image Ctrl
I have a windows form with 3 different Images that I want to load but I am only showing the code for One since I call the same method for all 3 Image Controls
#region Codes for browsing for a picture
/// <summary>
/// this.picStudent the name of the Image Control
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStudentPic_Click(object sender, EventArgs e)
{
Image picture = (Image)BrowseForPicture();
this.picStudent.Image = picture;
this.picStudent.SizeMode = PictureBoxSizeMode.StretchImage;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
private Bitmap BrowseForPicture()
{
// Bitmap picture = null;
try
{
if (this.fdlgStudentPic.ShowDialog() == DialogResult.OK)
{
byte[] imageBytes = File.ReadAllBytes(this.fdlgStudentPic.FileName);
StudentPic = new Bitmap( this.fdlgStudentPic.FileName);
StuInfo.StudentPic = imageBytes;
}
else
{
StudentPic = Properties.Resources.NoPhotoAvailable;
}
}
catch (Exception)
{
MessageBox.Show("That was not a picture.", "Browse for picture");
StudentPic = this.BrowseForPicture();
}
return StudentPic;
}
#endregion
Yes, this is now working, but strange, I would almost swear I tried this way too.
Ok, never mind, just that it works.
What is troubling me is something else too, which is in my opinion the same as your code, but its not working, its again trying to Dispose application (with same exception).
This is an example code:
using(Image img = Image.FromFile(open.FileName))
{
part.Picture = img;
}
pictureBox1.InitialImage = null;
pictureBox1.Image = part.Picture; //Picture is a propery in a class
Now I pass an actual image into a generic list, and try to assign new image to pictureBox from it, but, again as I said, exception is thrown (and application is terminated).
Why?
How can I clear draw image on picturebox?
The following doesn't help me:
pictbox.Image = null;
pictbox.Invalidate();
Please help.
EDIT
private void pictbox_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
vl.Draw(g, ref tran.realListForInsert);
}
public void Draw(Graphics g, ref List<double> arr)
{
g.DrawRectangle(new Pen(Brushes.Red, 3), nodeArr[Convert.ToInt32(templstName)].pict.Location.X, nodeArr[Convert.ToInt32(templstName)].pict.Location.Y, 25, 25);
g.DrawRectangle(new Pen(Brushes.Green, 3), nodeArr[Convert.ToInt32(templstArgName)].pict.Location.X, nodeArr[Convert.ToInt32(templstArgName)].pict.Location.Y, 25, 25);
nodeArr[Convert.ToInt32(templstName)].text.Text = arr[Convert.ToInt32(templstArgName)].ToString();
arr[Convert.ToInt32(templstName)] = arr[Convert.ToInt32(templstArgName)];
}
Setting the Image property to null will work just fine. It will clear whatever image is currently displayed in the picture box. Make sure that you've written the code exactly like this:
picBox.Image = null;
As others have said, setting the Image property to null should work.
If it doesn't, it might mean that you used the InitialImage property to display your image. If that's indeed the case, try setting that property to null instead:
pictBox.InitialImage = null;
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
pictureBox1.Image = null;
}
You need the following:
pictbox.Image = null;
pictbox.update();
private void ClearBtn_Click(object sender, EventArgs e)
{
Studentpicture.Image = null;
}
I assume you want to clear the Images drawn via PictureBox.
This you would be achieved via a Bitmap object and using Graphics object. you might be doing something like
Graphics graphic = Graphics.FromImage(pictbox.Image);
graphic.Clear(Color.Red) //Color to fill the background and reset the box
Is this what you were looking out?
EDIT
Since you are using the paint method this would cause it to be redrawn every time, I would suggest you to set a flag at the formlevel indicating whether it should or not paint the Picturebox
private bool _shouldDraw = true;
public bool ShouldDraw
{
get { return _shouldDraw; }
set { _shouldDraw = value; }
}
In your paint just use
if(ShouldDraw)
//do your stuff
When you click the button set this property to false and you should be fine.
For the Sake of Understanding:
Depending on how you're approaching your objective(s), keep in mind that the developer is responsible to Dispose everything that is no longer being used or necessary.
This means: Everything you've created along with your pictureBox (i.e: Graphics, List; etc) shall be disposed whenever it is no longer necessary.
For Instance:
Let's say you have a Image File Loaded into your PictureBox, and you wish to somehow Delete that file.
If you don't unload the Image File from PictureBox correctly; you won't be able to delete the file, as this will likely throw an Exception saying that the file is being used.
Therefore you'd be required to do something like:
pic_PhotoDisplay.Image.Dispose();
pic_PhotoDisplay.Image = null;
pic_PhotoDisplay.ImageLocation = null;
// Required if you've drawn something in the PictureBox. Just Don't forget to Dispose Graphic.
pic_PhotoDisplay.Update();
// Depending on your approach; Dispose the Graphics with Something Like:
gfx = null;
gfx.Clear();
gfx.Dispose();
Hope this helps you out.
I've had a stubborn image too, that wouldn't go away
by setting the Image and InitialImage to null.
To remove the image from the pictureBox for good, I had to use the code below,
by calling Application.DoEvents() repeatedly:
Application.DoEvents();
if (_pictureBox.Image != null)
_pictureBox.Image.Dispose();
_pictureBox.Image = null;
Application.DoEvents();
if (_pictureBox.InitialImage != null)
_pictureBox.InitialImage.Dispose();
_pictureBox.InitialImage = null;
_pictureBox.Update();
Application.DoEvents();
_pictureBox.Refresh();
I had to add a Refresh() statement after the Image = null to make things work.
I used this method to clear the image from picturebox. It may help some one
private void btnClear1_Click(object sender, EventArgs e)
{
img1.ImageLocation = null;
}
Its so simple!
You can go with your button click event,
I used it with a button property Name: "btnClearImage"
// Note 1a:
// after clearing the picture box
// you can also disable clear button
// by inserting follwoing one line of code:
btnClearImage.Enabled = false
// Note 1b:
// you should set your button Enabled property
// to "False"
// after that you will need to Insert
// the following line to concerned event or button
// that load your image into picturebox1
// code line is as follows:
btnClearImage.Enabled = true;
You should try. When you clear your Graphics you must choose color. SystemColors.Control is native color of form
Graphics g = pB.CreateGraphics();
g.Clear(SystemColors.Control);
clear pictureBox in c# winform Application
Simple way to clear pictureBox in c# winform Application
I have a program, which creates one pictureBox in Form1, and then creates an instance of a class that I called InitialState. The InitialState puts the source to the Image so that it is displayed, and after some time has passed, for which I used a Timer, it creates the next class, MainMenuState. Now, in that MainMenuState class that I've created, I would like to create another pictureBox and make it display on that Form1. Later on, I would like to make the pictures inside it change a bit, and then (possibly) destroy that pictureBox. After that, the program enters the next state (which is in yet another class), and again I would like that class to add a picture box to the original form, and so on.
Basically, I would like to dynamically add controls to the main Form1, but not in the said form, but from the classes I create later on. I've been searching on the internet for a way to do that, and it seems like I would have to use a delegate in order to invoke the Controls.Add method of the Form1 class. I've tried that, and the code compiles, but the pictureBox still doesn't show up.
Here's my code:
Form1 class:
public const string RESOURCE_PATH = "C:/Users/Noel/Documents/Visual Studio 2010/Projects/A/Resources/Animations/";
public Form1()
{
InitializeComponent(); //here, the first pictureBox shows
iInitializeComponent();
zacetnaAnimacija.Dock = DockStyle.Fill; //zacetnaAnimacija is the first pictureBox that appears
zacetnaAnimacija.Anchor = AnchorStyles.Top | AnchorStyles.Left;
zacetnaAnimacija.SizeMode = PictureBoxSizeMode.StretchImage;
InitialState intialState = new InitialState(this, zacetnaAnimacija); //entering InitialState
}
InitialState class:
class InitialState : State
{
System.Timers.Timer initialTimer;
PictureBox pictureBox1;
Form1 form;
public InitialState (Form1 form, PictureBox pictureBox1) {
this.form = form;
GifImage zacetnaSlika = new GifImage(Form1.RESOURCE_PATH + "Presenting.gif"); //this is just a .gif picture I'm displaying
Image trenutnaSlika = zacetnaSlika.GetFrame(0); //a method that plays the .gif
pictureBox1.Image = trenutnaSlika; //makes the first .gif display
this.pictureBox1 = pictureBox1;
initialTimer = new System.Timers.Timer(2500);
initialTimer.Enabled = true;
initialTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
initialTimer.Enabled = false;
MainMenuState menuState = new MainMenuState(form, pictureBox1); //enters main menu state with the Form1 argument passed on
}
MainMenuState class:
class MainMenuState : State
{
Form1 form;
public MainMenuState (Form1 form, PictureBox pictureBox1) {
this.form = form;
GifImage zacetnaSlika = new GifImage(Form1.RESOURCE_PATH + "animated.gif");
Image trenutnaSlika = zacetnaSlika.GetFrame(0);
pictureBox1.Image = trenutnaSlika; //this simply makes another .gif appear in the picture box instead of the first one
PictureBox a = new PictureBox(); //HERE'S my problem, when I want to add ANOTHER pictureBox to that form.
a.BackgroundImage = trenutnaSlika;
a.Location = new System.Drawing.Point(0, 0);
a.Name = "zacetnaAnimacija";
a.Size = new System.Drawing.Size(150, 150);
a.TabIndex = 1;
a.TabStop = false;
AddControl(a); //calling the delegate
}
public delegate void AddControls(PictureBox a);
public void AddControl(PictureBox a)
{
if (form.InvokeRequired)
{
AddControls del = new AddControls(AddControl);
form.Invoke(del, new object[] { a });
}
else
{
form.Controls.Add(a);
}
}
As I've said, the code compiles, but it doesn't create the PictureBox a on the Form1, when the MainMenuState is created. The thing is, if I don't use the delegate in the MainMenuState and just try to do something like form.Controls.Add(a), then I get a "cross-thread operation not valid" exception, and it doesn't even compile. That's why I used the delegate, but even now, it doesn't work.
Can someone please help me?
initialTimer = new System.Timers.Timer(2500);
That's part of the reason you're having trouble. The Elapsed event runs on a threadpool thread, forcing you to do the BeginInvoke song and dance. Use a System.Windows.Forms.Timer instead, its Tick event runs on the UI thread.
You'll also run into trouble with memory management, these classes need to implement IDisposable.
Oh my God, I just found the reason X_x
It was the fact that since the first pictureBox was covering the entire form, and the second one, which was created by the delegate, showed behind it! I just need to bring it to front!
Thank you guys, nonetheless, I probably wouldn't have come to that without you.
Edit: However, may I ask how to bring that control to the front? The a.BringToFront() function doesn't seem to work.
Instead of
form.Invoke(del, new object[]{a});
try:
form.Invoke(new ThreadStart(delegate
{
form.Controls.Add(a);
}
));