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.
Related
In a geographical software written in C#, a PictureBox is used to show GIS map that is saved as a png file in a temporary directory. There is some geometric shapes we need to be drawn on map. We used System.Drawing methods to perform this action.
Sometimes we need to change some properties these shapes or delete them, we need to remove the shapes without making beneath them black. Drawing them again with Color.Transparent obviously doesn't work, using Graphics#Clear(Color.Transparent) doesn't work too for the same reason.
We even tried using another picture box with transparent background that is used only for purpose of drawing shapes on; so that when we use Graphics#Clear(Color.Transparent) map container remains untouched. Sounded like a perfect idea at first, but because i don't know how and why it makes map container PictureBox invisible and map viewer panel is totally black, this idea failed too.
MapViewerForm
|-- Toolbar
|-- StatusBar
|-- MapViewer Panel (Provides scrollbars)
|-- MapContainer Pictutebox
|-- Shapes drawing canvas PictureBbox (The same size and location as map container, only difference is z-order)
I prefer to use the two PictureBoxes and making 'layers' idea, i think it's less unprofessional than the other idea (I am actually a java developer and this is a C# project!), I think there should be something like java's JLayeredPane in C# to adjust z-order of those two picture boxes and omit black screen bug, But if there is a solution to draw shapes on map container itself and then clear them without losing portions of maps lying behind them i'd appreciate that answer too.
P.S: If we load map picture from file and store it in a Bitmap or Image private field and when we need to clear drawings, load image from that field with a piece of code like picMapArea.Image = MapViewer.getInstance().getMapImage(); (Note: MapViewer is a singleton class) the painted shapes will be gone but it's obviously not anything like a "good idea" because of poor performance and lagging.
Thanks in advance.
Simply draw the shapes in an event handler for the picturebox Paint event.
To restore the view, all you have to do is call the picturebox Invalidate() method, so it repaints the Image, and not draw anything in your Paint event handler.
Just use an additional Bitmap:
Bitmap original = LoadBitmap(...);
Bitmap copy = new Bitmap(original);
Graphics graph = Graphics.FromImage(copy);
// draw some extra
PictureBox1.Image = copy;
I created a simple stick man in a Windows Form User-Control (consisting of a radio button and three labels and one progress bar).
I set the back-color of the new user-control to transparent so that when I drag it onto my form, it blends with other colors and drawings on the form.
I am not getting what I'm trying to achieve.
Here is the picture:
UserControl already supports this, its ControlStyles.SupportsTransparentBackColor style flag is already turned on. All you have to do is set the BackColor property to Color.Transparent.
Next thing you have to keep in mind in that this transparency is simulated, it is done by asking the Parent of the control to draw itself to produce the background. So what is important is that you get the Parent set correctly. That's a bit tricky to do if the parent is not a container control. Like a PictureBox. The designer will make the Form the parent so you will see the form's background, not the picture box. You'll need to fix that in code, edit the form constructor and make it look similar to this:
var pos = this.PointToScreen(userControl11.Location);
userControl11.Parent = pictureBox1;
userControl11.Location = pictureBox1.PointToClient(pos);
In constructor set style of control to support a transparent backcolor
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
and then set Background to transperent color
this.BackColor = Color.Transparent;
From MSDN
A more complex approach (and possibly working one) is described here - with overrding of CreateParams and OnPaint.
Why all those things?
UserControl class has property Region.
Set this to what ever shape you like and no other adjustments are needed.
public partial class TranspBackground : UserControl
{
public TranspBackground()
{
InitializeComponent();
}
GraphicsPath GrPath
{
get
{
GraphicsPath grPath = new GraphicsPath();
grPath.AddEllipse(this.ClientRectangle);
return grPath;
}
}
protected override void OnPaint(PaintEventArgs e)
{
// set the region property to the desired path like this
this.Region = new System.Drawing.Region(GrPath);
// other drawing goes here
e.Graphics.FillEllipse(new SolidBrush(ForeColor), ClientRectangle);
}
}
The result is as in the image below:
No low level code, no tweaking, simple and clean.
There is however one issue but in most cases it can go undetected, the edges are not smooth and anti-aliasing will not help either.
But the workaround is fairly easy. In fact much easier than all those complex background handling..
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.
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.
I want to draw directly on the desktop in C#. From searching a bit, I ended up using a Graphics object from the Desktop HDC (null). Then, I painted normally using this Graphics object.
The problem is that my shapes get lost when any part of the screen is redrawn. I tried a While loop, but it actually ends up drawing as fast as the application can, which is not the update rate of the desktop.
Normally, I would need to put my drawing code in a "OnPaint" event, but such thing does not exist for the desktop.
How would I do it?
Example code: https://stackoverflow.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c
I posted two solutions for a similar requirement here
Basically you have two options.
1- Get a graphics object for the desktop and start drawing to it. The problem is if you need to start clearing what you have previously drawn etc.
Point pt = Cursor.Position; // Get the mouse cursor in screen coordinates
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
g.DrawEllipse(Pens.Black, pt.X - 10, pt.Y - 10, 20, 20);
}
2- The second option that I provide in the link above is to create a transparent top-most window and do all your drawing in that window. This basically provides a transparent overlay for the desktop which you can draw on. One possible downside to this, as I mention in the original answer, is that other windows which are also top-most and are created after your app starts will obscure your top most window. This can be solved if it is a problem though.
For option 2, making the form transparent is as simple as using a transparency key, this allows mouse clicks etc. to fall through to the underlying desktop.
BackColor = Color.LightGreen;
TransparencyKey = Color.LightGreen;
When you draw to HDC(NULL) you draw to the screen, in an unmanaged way. As you've discovered, as soon as windows refreshes that part of the screen, your changes are overwritten.
There are a couple of options, depending upon what you want to achieve:
create a borderless, possibly
non-rectangular window. (Use
SetWindowRgn to make a window
non-rectangular.) You can make this a child of the desktop window.
subclass the desktop window. This is not straightforward, and involves
injecting a DLL into the
Explorer.exe process.
To get an OnPaint for the desktop you would need to subclass the desktop window and use your drawing logic when it receives a WM_PAINT/WM_ERASEBKGND message.
As the thread you linked to says, you can only intercept messages sent to a window of an external process using a hook (SetWindowsHookEx from a DLL).
As mentioned a transparent window is another way to do it, or (depending on the update frequency) copying, drawing and setting a temporary wallpaper (as bginfo does).
This is difficult to do correctly.
It will be far easier, and more reliable, to make your own borderless form instead.