I want to use fully transparent Modal form in my application, with being able to fill it with partially-transparent image; For this, I used to remove all visible elements from the form and got the code below.
class WinScreenshotWindow : Form
{
public WinScreenshotWindow()
{
// Create from without erasing background with a color
// Going not to use transparent form instead, it will produce context menu bugs in textboxes for child form
this.SuspendLayout();
this.MaximizeBox = false;
this.MinimizeBox = false;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.FormBorderStyle = FormBorderStyle.None;
this.StartPosition = FormStartPosition.Manual;
this.ControlBox = false;
this.Visible = false;
this.Size = new Size(100, 100);
this.Location = new Point(200, 200);
this.ResumeLayout();
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Erase Background Windows message:
}
protected override void OnPaint(PaintEventArgs e)
{
Rectangle clientRect = e.ClipRectangle;
e.Graphics.FillRectangle(Brushes.Transparent, clientRect);
}
}
static void Main()
{
Form form = new Form();
form.Size = new Size(400, 400);
form.Show();
var ww = new WinScreenshotWindow();
ww.ShowDialog(form);
}
But the result is something strange:
When I remove filling in OnPaint(), it is not visible at all.
The question is - why does this happen? If the background is transparent why do it shows the form in such way? And what can be done in this situation?
Any help appreciated.
Wouldn't it be easier to open a borderless form with a red backcolor and set the TransparencyKey = red?
Related
I have a floating borderless form that contains two buttons. When the user moves the mouse over the form, the FormBorderStyle changes to SizableToolWindow and then returns after a set time using a timer. When this happens the form shifts to accommodate the title bar and Form edge. I am able to compensate for this however when it happens you get a flicker of the form being shifted before being placed back into place.
Is there any way I can stop the window refreshing until after I have already shifted it back into place?
Here's my shifting code:
if (this.FormBorderStyle != FormBorderStyle.None)
{
// Suspend layout of Form
this.SuspendLayout();
// Suspend layout of button controls
this.cbBlankDisplay.SuspendLayout();
this.btnPurgeMessages.SuspendLayout();
this.FormBorderStyle = FormBorderStyle.None;
this.Left += this.change.Width;
this.Top += this.change.Height;
// Resume layout of buttons and Form
this.btnPurgeMessages.ResumeLayout();
this.cbBlankDisplay.ResumeLayout();
this.ResumeLayout();
}
I ended up doing as Hans Passant suggested and creating a duplicate of my ClientRectangle area which is displayed on an already transparent full screen overlay.
My MouseLeave Event just starts the Timer.
This is the Code in my MouseEnter Event:
private void FloatingButtons_MouseEnter(object sender, EventArgs e)
{
if (this.FormBorderStyle != FormBorderStyle.SizableToolWindow)
{
if (this.Tag is Bitmap)
{
Owner.overlay.CreateGraphics().DrawImage(
(Bitmap)this.Tag,
new Rectangle(
Point.Add(this.Location, this.change),
this.ClientRectangle.Size),
new Rectangle(this.Location, this.ClientRectangle.Size),
GraphicsUnit.Pixel
);
}
this.Hide();
this.SuspendLayout();
this.cbBlankDisplay.SuspendLayout();
this.btnPurgeMessages.SuspendLayout();
if (this.change.Height == 0)
{
this.FormBorderStyle = FormBorderStyle.SizableToolWindow;
Rectangle scrPosition = RectangleToScreen(this.ClientRectangle);
this.change.Width = (scrPosition.Left - this.Left);
this.change.Height = (scrPosition.Top - this.Top);
}
this.Left -= this.change.Width;
this.Top -= this.change.Height;
this.FormBorderStyle = FormBorderStyle.SizableToolWindow;
this.btnPurgeMessages.ResumeLayout();
this.cbBlankDisplay.ResumeLayout();
this.ResumeLayout();
this.Show();
if (this.Tag != null && this.Tag is Bitmap)
{
((Bitmap)this.Tag).Dispose();
this.Tag = null;
Overlay.performUpdate = true;
}
}
}
This is the code in my Timer_Tick Event:
if (this.FormBorderStyle != FormBorderStyle.None)
{
// Create a bitmap the size of my Form
Bitmap bmp = new Bitmap(this.Bounds.Width, this.Bounds.Height);
// Copy the form to the newly created Bitmap
this.DrawToBitmap(bmp, new Rectangle(Point.Empty, this.Bounds.Size));
// Create a rectangle of the Location and Size of the ClientArea
Rectangle rect = new Rectangle((Point)this.change, this.ClientRectangle.Size);
// The Owner Form contains a class that already performs overlays on the screen
Owner.overlay.CreateGraphics().DrawImage(
bmp,
new Rectangle(
Point.Add(this.Location, this.change),
this.ClientRectangle.Size),
rect,
GraphicsUnit.Pixel
);
// Store the Bitmap in the Tag for Disposal after being used
this.Tag = bmp;
// Now I can hide my Form and perform necessary changes
this.Hide();
this.SuspendLayout();
this.cbBlankDisplay.SuspendLayout();
this.btnPurgeMessages.SuspendLayout();
this.FormBorderStyle = FormBorderStyle.None;
this.Left += this.change.Width;
this.Top += this.change.Height;
this.btnPurgeMessages.ResumeLayout();
this.cbBlankDisplay.ResumeLayout();
this.ResumeLayout();
this.Show();
}
I'd like to show an instance of a form class for a specific time. The form needs to be topmost and not steal focus. Here is my code:
public class mSplashForm : Form
{
public mSplashForm()
{
this.FormBorderStyle = FormBorderStyle.None;
this.BackColor = Color.LightBlue;
this.Opacity = 0.92D;
this.ShowInTaskbar = false;
this.MinimumSize = new System.Drawing.Size(5, 5);
}
}
public static void mSplash(int time = 500)
{
mSplashForm SF = new mSplashForm();
Application.EnableVisualStyles();
SF.Width = 500;
SF.Height = 100;
SF.Left = 500;
SF.Top = 500;
SetWindowPos(SF.Handle, HWND_TOPMOST, SF.Left, SF.Top, SF.Width, SF.Height, SWP_NOACTIVATE);
ShowWindow(SF.Handle, mEnumShowWindowCommands.ShowNoActivate);
Application.DoEvents();
Thread.Sleep(time);
SF.Close();
}
It works, but the form is not shown in the right position defined using Top and Left parameters. What is wrong please?
You've got your form set to start in FormStartPosition.WindowsDefaultLocation. Add this into your mSplash function:
SF.StartPosition = FormStartPosition.Manual;
This is why it's trying to position successively down the page (as per your comment) on each opening.
set the start position to manual:
this.StartPosition = FormStartPosition.Manual;
Try this
SF.StartPosition = FormStartPosition.Manual;
SF.Width = 500;
SF.Height = 100;
SF.Left = 500;
SF.Top = 500;
After seeing that drawing to the desktop is extremely messy, I decided just to research around. I figured out that many people suggest creating a transparent WinForm that is the size of the screen and smacking a panel on there and using that to draw graphics. So I tested it out but ran into many errors. At first, my second form (Form2) wouldn't show, so I had to put it into another thread and put Form2.ShowDialog(); on that thread. After I got that problem out of the way, I actually drew to the panel. Now my form will never show, but I can see it running on my taskbar. Everytime I try to make it the focused window, it never works, and whenever I hover the task I can see the graphics being created. My question is, is it possible to draw to a panel on a transparent WinForm and make it visible? Here's the code I used, it's mostly for looking for errors (drawing the states and stuff).
void Draw()
{
while (true)
{
SolidBrush redpen = new SolidBrush(Color.Red);
Font font = new Font("Arial", 16);
PointF point = new PointF(700, 150);
Graphics g = panel1.CreateGraphics();
g.DrawString(Main.state.ToString(), font, redpen, point);
Main.beginTime.Stop();
Main.TimeRan = Main.beginTime.Elapsed;
string amountOfTime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", Main.TimeRan.Hours, Main.TimeRan.Minutes, Main.TimeRan.Seconds, Main.TimeRan.Milliseconds / 10);
point = new PointF(700, 200);
g.DrawString(amountOfTime, font, redpen, point);
Thread.Sleep(10);
panel1.Refresh();
}
}
private void Form2_Shown(object sender, EventArgs e)
{
Draw();
}
Somewhere in my main class
// In a method
Thread F2T = new Thread(FormHandlers);
F2T.Start();
private void FormHandlers()
{
Form2 Form2 = new Form2();
Form2.Opacity = 0.00;
Form2.ShowDialog();
}
Edit: After some testing, I noticed that with the decrease of opacity the letter's opacity decreases as well, can I make it so the panel is transparent but the string I'm drawing to draw inside of it is not?
I guess you want to draw a message on a transparent child form? if that, I think you could do as follow: because the form.Opacity =0.00 makes all the controls in it be transparent, so we can't see anything. Another way, we use form.TransparencyKey to get that. code like this:
public Form2()
{
InitializeComponent();
//hide the border of form
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.BackColor = Color.White;
//set the TransparencyKey the same as the back color
this.TransparencyKey = this.BackColor;
}
protected override void OnPaint(PaintEventArgs e)
{
SolidBrush redpen = new SolidBrush(Color.Red);
Font font = new Font("Arial", 16);
PointF point = new PointF(400, 150);
Graphics g = e.Graphics;
string state = "running";
g.DrawString(state, font, redpen, point);
string amountOfTime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", 1, 2, 3, 11111 / 10);
PointF point2 = new PointF(500, 150);
g.DrawString(amountOfTime, font, redpen, point2);
//base.OnPaint(e);
}
by the way, you want to show message in a child form, I don't prefer to use multi-threading, you just invoke the Form2 in Show() not in ShowDialog(), and set Form2.TopMost=True, than you can operate your main form as well. try it.
my result is bellow:
I'm trying to make an image appear on top of another and still show the image underneath via a transparent background. I've got it so the new image appears on top of the other however setting BackColor to Color.Transparent just results in a black background.
Full Code:
public partial class frm_airportApplication : Form
{
PictureBox PicBox;
public frm_airportApplication()
{
InitializeComponent();
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x000000200;
return cp;
}
}
private void button1_Click(object sender, EventArgs e)
{
AllowTransparency = true;
plane p = new plane();
p.getPB().Parent = pb_airport;
this.Controls.Add(p.getPB());
this.Update();
}
protected void InvalidateEx()
{
if (Parent == null)
return;
Rectangle rc = new Rectangle(this.Location, this.Size);
Parent.Invalidate(rc, true);
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
//do not allow the background to be painted
}
private void button2_Click(object sender, EventArgs e)
{
AllowTransparency = true;
ResourceManager resourceManager = new ResourceManager("Airport_Application.Properties.Resources", GetType().Assembly);
PicBox = new PictureBox();
PicBox.BackColor = Color.Transparent;
PicBox.Image = (Bitmap)resourceManager.GetObject("plane_icon");
PicBox.Top = 100;
PicBox.Width = 120;
PicBox.Height = 120;
PicBox.Left = 10;
PicBox.SizeMode = PictureBoxSizeMode.Zoom;
PicBox.Parent = pb_airport;
Controls.Add(PicBox);
PicBox.BringToFront();
}
}
public class plane
{
PictureBox pb;
Bitmap image;
ResourceManager resourceManager;
public plane()
{
resourceManager = new ResourceManager("Airport_Application.Properties.Resources", GetType().Assembly);
image=(Bitmap)resourceManager.GetObject("plane_icon");
pb = new PictureBox();
pb.Image = image;
pb.Top = 500;
pb.Width = 100;
pb.Height = 100;
pb.Left = 50;
pb.SizeMode = PictureBoxSizeMode.Zoom;
pb.BackColor = Color.Transparent;
}
public PictureBox getPB()
{
return pb;
}
}
I've found a lot of people who have had similar issues but none of the solutions helped.
It has been awhile but I think you have to set your form to Allow Tranparencies
this.AllowTransparency = true;
or
YourForm.AllowTransparency = true;
that would get rid of the black
I had the same issue but I had just a Panel which should've been transparent so I could see everything underneath it.
The problem was with DoubleBuffered property, it should be set to false.
this.DoubleBuffered = false;
No blackness anymore.
You can create an irregularly shaped form easily by setting its "Region" property. Here's an example:
Irregularly shaped form
As for truly transparent Controls, here's an excellent resource with step-by-step instructions:
Transparent Controls
In simple words, you cannot easily achieve transparency using the default PictureBox control in Windows Forms.
Either you switch to WPF, which by default supports transparency in every bits, or you use a custom control. Once I created such a control called AppIcon, but it is released under GPL, not commercial friendly,
http://mymobilepack.codeplex.com/SourceControl/changeset/view/39314#512415
For forms you can try this:
this.BackColor = System.Drawing.Color.XXX;
this.TransparencyKey = System.Drawing.Color.XXX;
You can try to solve it on the bitmap level:
Make a image in bitmap format and make the backgroundcolor transparant with this method:
bm.MakeTransparent(Color.XXX);
I seemed to solve a similar problem with my splashscreen bij setting a timer every 100ms,
and call DoEvents in it:
private void timer1_Tick(object sender, EventArgs e)
{
//BringToFront();
Application.DoEvents();
}
Hope this helps
If you want to overlay images over images (and not images over form), this would make the trick:
overImage.Parent = backImage;
overImage.BackColor = Color.Transparent;
overImage.Location = thePointRelativeToTheBackImage;
Where overImage and backImage are PictureBox with png (with transparent background).
Is it possible to make a poup screen with high opacity around the popup screen in winform? If yes, how?
How do I make the pop up message or GUI screen to be in the middle of the computer screen?
Please remember that I don't have any source code yet.
An example:
To show your Form at center of screen, use StartPosition property of form to CenterScreen.
this.StartPosition = FormStartPosition.CenterScreen;
Now, to grey rest of the portion of screen.
Take a new form name it frmBlur and set these properties.
this.BackColor = SystemColors.ControlDark;
this.FormBorderStyle = FormBorderStyle.None;
this.Opacity = 0.8;
this.ShowInTaskbar = false;
this.TopMost = true;
this.WindowState = FormWindowState.Maximized;
Now, use the below code to display MessageBox or winform
private void button1_Click(object sender, EventArgs e)
{
using (frmBlur ob = new frmBlur())
{
ob.Show();
frmMessage f = new frmMessage();
f.TopMost = true;
f.ShowDialog();
}
}