My question is related to this one: How to get a screen capture of a .Net WinForms control programmatically?
I want to take a screenshot of a System.Windows.Forms.Control in C#. I'm using the DrawToBitmap method suggested in the question linked above and that works most of the time. However there are a few problems.
Problem 1:
I have two tabpages, let's call them A and B. The Control I want to take a screenshot of is in tabpage B. I want to take the screenshot when a button in tabpage A is pressed. This works most of the time, except when tabpage B hasn't been accessed yet: then the screenshot is just white. If I first access tabpage B, then go back to tabpage A and click the button to take the screenshot then it works fine. I'm guessing this is because of some loading or building of the control in the tab that hasn't been done yet, but I'm not sure what exactly (or it could be something else entirely). I've been trying to force that loading or building using ResumeLayout, PerformLayout, Show, Update, Invalidate but that doesn't work.
EDIT: Managed to solve this by using DrawToBitmap on the containing tabpage control instead of the Control itself and doing a Show on that tabpage.
Problem 2:
When I take a screenshot of a certain custom Control (a subclass of UserControl) there is a small rectangular white area in the screenshot (where there shouldn't be one obviously). The rectangular area isn't on one particular part of the control like a button or textbox so I'm not sure what's causing this. On other custom Controls (also subclasses of UserControl) it works fine, so that couldn't be the problem itself.
EDIT: Solved it, there was an empty control there that was being drawn on top of it. Setting Visible to false for that control solved it.
You can do with this code, the rest of the work and finding the correct coordinates is for the reader to do the homework.
int screenWidth = Screen.GetBounds(new Point(0, 0)).Width;
int screenHeight = Screen.GetBounds(new Point(0, 0)).Height;
Bitmap bmpScreenShot = new Bitmap(screenWidth, screenHeight);
Graphics gfx = Graphics.FromImage((Image)bmpScreenShot);
gfx.CopyFromScreen(0, 0, 0, 0, new Size(screenWidth, screenHeight));
bmpScreenShot.Save("test.jpg", ImageFormat.Jpeg);
For problem 1: If "If I first access tabpage B, then go back to tabpage A and click the button to take the screenshot then it works fine" then add in formloadevent imitating of that actions:
tabControl.SelectedIndex = IndexOfTabB;
tabControl.SelectedIndex = IndexOfTabA;
That is trick but it will work.
For problem 2: Can you compare sizes of your control and screenshot of It and give results to us? If Control.Width is not equal wirdth of bitmap screen then It is a real problem.
Related
TL;DR: Look at the picture below
So I'm trying to make a little picture, and I and people around me are kinda out of ideas.
I have a table (the sitting+eating one) in the middle (seen from above), and people sitting around it. Those people are round, as isthe table.
Every person has their own picturebox, I just use one picture, rotate it, and set it as image in the next box.
Thep roblem now is: The PictureBoxes of people on corners overlap the table with empty corner, in the image there is transparency there. It should show the table below it, but instead it shows the background of the Form :(
Edit: All backgrounds are set to transparent, the Form has the marble as background and white ("Window") as background colour.
I put one person in the back and one in the front, so it's easy to see:
Edit 2 (same as ocmment):
In the last two days I read this question about 10 times, and not one that described this exact problem has had an actual answer. When trying to push one of those, I was told I should post a new question.
Example: How to make picturebox transparent?
Transparency in winforms is kind of misleading, since it's not really transparency.
Winforms controls mimic transparency by painting the part of their parent control they would hide instead of their own background.
However, they will not paint the other controls that might be partially covered by them.
This is the reason your top most picture boxes hides your big picture box.
You can overcome this by creating a custom control that inherits from PictureBox and override its OnPaintBackground method (taken, with slight adjustments, from this code project article):
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
Graphics g = e.Graphics;
if (this.Parent != null)
{
var index = Parent.Controls.GetChildIndex(this);
for (var i = Parent.Controls.Count - 1; i > index; i--)
{
var c = Parent.Controls[i];
if (c.Bounds.IntersectsWith(Bounds) && c.Visible)
{
using (var bmp = new Bitmap(c.Width, c.Height, g))
{
c.DrawToBitmap(bmp, c.ClientRectangle);
g.TranslateTransform(c.Left - Left, c.Top - Top);
g.DrawImageUnscaled(bmp, Point.Empty);
g.TranslateTransform(Left - c.Left, Top - c.Top);
}
}
}
}
}
Microsoft have published a Knowledge base article to solve this problem a long time ago, however it's a bit out-dated and it's code sample is in VB.Net.
Another option is to paint the images yourself, without picture boxes to hold them, by using Graphics.DrawImage method.
The best place to do it is probably in the OnPaint method of the form.
TL;DR: Look at the picture below
So I'm trying to make a little picture, and I and people around me are kinda out of ideas.
I have a table (the sitting+eating one) in the middle (seen from above), and people sitting around it. Those people are round, as isthe table.
Every person has their own picturebox, I just use one picture, rotate it, and set it as image in the next box.
Thep roblem now is: The PictureBoxes of people on corners overlap the table with empty corner, in the image there is transparency there. It should show the table below it, but instead it shows the background of the Form :(
Edit: All backgrounds are set to transparent, the Form has the marble as background and white ("Window") as background colour.
I put one person in the back and one in the front, so it's easy to see:
Edit 2 (same as ocmment):
In the last two days I read this question about 10 times, and not one that described this exact problem has had an actual answer. When trying to push one of those, I was told I should post a new question.
Example: How to make picturebox transparent?
Transparency in winforms is kind of misleading, since it's not really transparency.
Winforms controls mimic transparency by painting the part of their parent control they would hide instead of their own background.
However, they will not paint the other controls that might be partially covered by them.
This is the reason your top most picture boxes hides your big picture box.
You can overcome this by creating a custom control that inherits from PictureBox and override its OnPaintBackground method (taken, with slight adjustments, from this code project article):
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
Graphics g = e.Graphics;
if (this.Parent != null)
{
var index = Parent.Controls.GetChildIndex(this);
for (var i = Parent.Controls.Count - 1; i > index; i--)
{
var c = Parent.Controls[i];
if (c.Bounds.IntersectsWith(Bounds) && c.Visible)
{
using (var bmp = new Bitmap(c.Width, c.Height, g))
{
c.DrawToBitmap(bmp, c.ClientRectangle);
g.TranslateTransform(c.Left - Left, c.Top - Top);
g.DrawImageUnscaled(bmp, Point.Empty);
g.TranslateTransform(Left - c.Left, Top - c.Top);
}
}
}
}
}
Microsoft have published a Knowledge base article to solve this problem a long time ago, however it's a bit out-dated and it's code sample is in VB.Net.
Another option is to paint the images yourself, without picture boxes to hold them, by using Graphics.DrawImage method.
The best place to do it is probably in the OnPaint method of the form.
I have an XNA project that utilizes the Windows.Forms to create the GUI. Our GUI consists of a left panel and right panel. They both have a image laid over them(let's call them the panel images). Those images have buttons with images over them. Now the panel images don't completely cover the panel. Now what we want to do is make the panel invisible or transparent so you only see the panel images. In the picture below I circled what I want to be transparent/invisible. As you can see on the upper part of the project it already looks transparent but that is only because it blends in with the background on the XNA scene. On the bottom where the panel is over the ground you can see how the panel extends further than the panel images. So, does anyone know how I can make those parts invisible/transparent.
Alright, we've messed around with making the panel color Color.Transparent, magenta(XNA transparent color) and those attempts haven't worked. Any input/advice is welcome and much appreciated.
Here is the code that sets up the panel:
this.pnlLeftSide.BackgroundImage = global::Referenceator_UI.Resources.LeftBar;
this.pnlLeftSide.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.pnlLeftSide.Controls.Add(this.btnScreenShot);
this.pnlLeftSide.Controls.Add(this.btnScale);
this.pnlLeftSide.Controls.Add(this.btnMove);
this.pnlLeftSide.Controls.Add(this.btnRotate);
this.pnlLeftSide.Controls.Add(this.btnSelect);
this.pnlLeftSide.Location = new System.Drawing.Point(0, 0);
this.pnlLeftSide.Name = "pnlLeftSide";
this.pnlLeftSide.Size = new System.Drawing.Size(197, Screen.PrimaryScreen.WorkingArea.Height);
this.pnlLeftSide.Dock = DockStyle.Left;
this.pnlLeftSide.BackColor = controlColor; //this what we want invisible/transparent
-Thank you stackoverflow community
Try setting Region property of your panels. You can create necessary Region objects manually (by enumerating lines describing visible polygon) or use some method which converts image with transparency color key to Region (easily googled - https://stackoverflow.com/questions/886968/how-do-i-convert-an-images-transparency-into-a-region for example).
Since geometry of your panels does not seem to be too complex, you can create Region manually following way:
using(var gp = new System.Drawing.Drawing2D.GraphicsPath())
{
// Here goes series of AddLine() calls.
// You must
// gp.AddLine(0, 0, leftPanel.Width, 0);
// ...
gp.CloseFigure();
return new Region(gp);
}
Note that you'll get sharp edges with this method (even if it works). Consider rendering all that GUI using XNA.
I've got an app which will run on two different devices - one with a screen size of 240x320, the other 480x640.
For all forms bar one the VS generated code is fine:
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.AutoScroll = true;
For one form i'm capturing a signature. I'm doing this by a panel with a graphics handler; capturing mouse down and move events; this generates a list of vector points which I can draw lines with.
On the smaller res screen this is fine. On the higher res, I can't display my lines.. and I think this is because the panel is beyond the windows form size.
The form is created with a size of 240 x 268; a standard size I think - i've not manually set it, VS does this for me.
In order to get the panel in the right spot on the high res device, the co-ordinates are 3, 290; ie, 290 is past 268. Also the width of the panel is 448 which is somewhat larger than 240.
I'm using .net 2.0 (can't use later). I think I need to resize the form to make it larger but I do want to keep the existing re-sizing for the other controls on the form.
I'm not sure how to do this.
Make the form dock to fill, then use the Anchor properties to ensure controls inside the form resize as expected.
If you want the option of customizing how an individual control resizes, then DONT set the anchor properties on it, and instead handle the Resize event and perform custom resizing/repositioning within code there.
eg
private void form_Resize(object sender, EventArgs e)
{
// Center the control without changing width. Other controls are anchored.
this.control.Left = (this.Width - this.control.Width) / 2;
}
I'm writing this answer for the benefit of those who may have a similar problem in the future. PaulG pointed me in the right direction but I found the root cause to be something else.
The PDA project i've got uses "FormFactor WindowsMobile 6 Classic" which has a default size of 240 x 268.
Changing this to "Windows Mobile 6 Professional VGA" created a much larger form size.
This allowed me to get things positioned correctly for the larger size; then AutoScaleMode to DPI; and manually resizing the panel smaller made it all work.
IE, going from larger to smaller was easy; I didn't get smaller to larger working.
I have a form in an application developed using C#. In that form I have created a graphic shape (a circle). At run-time I want my form also to be of that shape only. That is, I want to display only that graphic and not the form back ground or title bar or anything. I want to display only that graphic. But the thing is I'm not able to shape my form. I have that graphic control as a User-Control which I have added to my form.
I suspect you're trying to make a splash-screen like effect. This isn't terribly hard to do. Here's a good tutorial to get you started.
The trick essentially is to set the transparency key of the form to the color you wish to be transparent (in this case, everything except your circle. Additionally, you need to set the form to be borderless.
As an aside, you might edit your question to add some information about why you want to do this - I am curious what your goal is, in terms of user-experience.
You could also check MSDN for the Region property. You can use System.Drawing objects to draw whatever shape you want then set the forms Region property before its shown and it will take whatever shape you give it...heres a short example:
http://www.vcskicks.com/custom_shape_form_region.php
If you want a circular form you can put the following code in the form load event handler:
System.Drawing.Drawing2D.GraphicsPath myPath = new System.Drawing.Drawing2D.GraphicsPath();
//this line of code adds an ellipse to the graphics path that inscribes
//the rectangle defined by the form's width and height
myPath.AddEllipse(0,0,this.Width,this.Height);
//creates a new region from the GraphicsPath
Region myRegion = new Region(myPath);
this.Region = myRegion;
and then set the FormBorderStyle property of the form to None.