In my project, I create a form with the opacity controlled by the user. If the form was fully transparent the mouse events 'fell through' (without my intervention), otherwise my form handled them.
After reading this question and overriding the CreateParams property to set the WS_EX_TRANSPARENT flag on my form, it now allows mouse events to fall through when the opacity is any value <255.
This is exactly what I want, but it concerns me that I don't understand why it works.
From what I've read, WS_EX_TRANSPARENT is meant to make the form appear transparent by 'stealing bits' from the form below it in its Paint method, therefore:
The Paint method of my form and all the controls in it should never be called, right? As WS_EX_TRANSPARENT should cause Windows to override them, so why does it affect input handling but not the drawing of my form?
The opacity should have no impact on the handling of mouse events, as if Paint is being overridden the 'local' opacity should not matter, no?
Could someone explain, what this flag really does? How does it work?
WS_EX_TRANSPARENT makes your events (like mouse clicks) fall through your window, amongst other things. Opacity is a separate concept, it instructs window manager to apply alphablending when drawing your form. Those two things are not related, but when you combine them you get the effect you need in your case.
So:
Paint method of your form is called normally as it should, opacity has nothing to do with it.
Opacity does not have anything to do with mouse events, as described in the first paragraph.
It makes the window invisible to mouse events, or -as Microsoft puts it- it doesn't obscure the windows below. I believe it doesn't actually steal pixels from the windows below, but Windows itself will probably blend those two pictures together, using the level of transparancy you supplied.
Transparent windows can be useful for showing some progress or a splash screen, but you'll have to program a way to close them, because just click the X won't work since the mouse click will pass through it.
So not only does it change the level of visual transparency, but it modifies the behaviour too. I wonder where you would have read otherwise.
[edit]
Don't Windows in C# just have an opacity property?
Related
I'm attempting to create a window with the following properties:
Completely invisible except for a small, moving region
Can be clicked through to windows below it, EXCEPT if you click in that small region
Doesn't show up on the taskbar (although this one isn't as pressing at the moment)
I can figure out how to make the WHOLE window transparent (partially or entirely) and click-through using WS_EX_LAYERED and WS_EX_TRANSPARENT, setting TopMost, and changing the opacity, but I can't figure out how to make these requirements true for the window EXCEPT for a limited part. Any idea where to start?
EDIT: It's been pointed out to me that making a huge, invisible window is rather pointless, and it would be smarter to create a small window and use FormBorderStyle.FixedToolWindow and ShowInTaskbar to make it borderless and not present on the task bar, then move it around. I still need to figure out how to make the "background" of the window transparent and click-through, so I'm leaving this question up.
So, I managed to figure it out through trial and error, and I apologize for taking people's time.
The solution here is to:
Override OnPaintBackground to be an empty method, so nothing actually gets painted on the back
Set the style so it supports Transparent as a back color, then set the back color and TransparencyKey to Transparent
Set FormBorderStyle to None, TopMost to True, ControlBox to False, ShowInTaskbar to False, and Text to String.Empty
End result: A form that is completely invisible and that can be clicked through, while still letting the user interact with any controls placed on the form.
It seams to be a bug, if you change a Form size to a previously transparent region, mouse events will no longer be detected on it.
How to reproduce it:
Create a new Windows form project
Set Form1 TransparencyKey to Magenta
Add a Panel to Form1 and config it as:
Dock fill
BackColor to Magenta
Run, now try to change the Form size, if you reduce it (enough so the new border will be placed over a current transparent region), the mouse will no longer "detect" the window border on that side. If you minimize/restore the window, it will work again. How can I fix that? I tried Refresh on Form Layout/Resize event, but it didn't work.
Just to confirm, yes this is a bug in the current Aero implementation on Windows 8.1. Possibly before. Been around for quite a while, seems like it is a pretty structural problem. It is part of a set of bugs related to layered windows with the transparency key set, and getting the mouse to be transparent to such a window, it also doesn't work properly with certain color selections for the key. In this specific case, it inappropriately makes the frame transparent to clicks as well.
Hard to give specific advice, this does require calling Microsoft Support to get ahead. Technically you can take advantage of another bug, the window is never transparent to mouse clicks when you pick, say, Red as the transparency key:
public Form1() {
InitializeComponent();
this.TransparencyKey = panel1.BackColor = Color.Red;
}
Solves the bug you are dealing with, but of course disables mouse transparency completely. A workaround you almost definitely won't like is:
protected override void OnResizeEnd(EventArgs e) {
base.OnResizeEnd(e);
this.RecreateHandle();
}
Too noticeable. Programmers are starting to take advantage of these bugs, sometimes they want such lack of transparency intentionally. Makes you wonder how Microsoft is ever going to get this fixed without breaking some program. Not pretty.
I've created a semi-transparent form (60% opacity with black background color) that my app launches, maximized, over the entire screen. Basically, it casts a gray color on the entire desktop.
When the user mouses-over a window on the desktop, I want to get that window's handle (hWnd).
The easy way to do this, which is working for me, is:
Temporarily hide my form (OR, temporarily set my form's opacity to 0.0)
Call [GetCursorPos][1]
Call [WindowFromPoint][2]
Show my form again
The problem with this approach is that my form / the screen blinks, which I don't like.
I've tried to fix this in two ways:
I figure there should be a way to get the hWnd of the window directly underneath my form by calling ChildWindowFromPointEx (passing-in the hWnd of the desktop and CWP_SKIPTRANSPARENT), but it doesn't seem to work. I also played with [ChildWindowFromPoint][4] and [RealChildWindowFromPoint][5] with no success. (P.S. Raymond Chen discusses the differences between these calls, here and it seems to me that ChildWindowFromPointEx is designed to do exactly what I need)
I tried preventing the entire desktop from refreshing (kind of "freezing" the screen momentarily) by using (1) SendMessage(GetDesktopWindow(), WM_SETREDRAW, false, 0) before I hide my form and (2) SendMessage(GetDesktopWindow(), WM_SETREDRAW, true, 0) after I hide my form. This didn't work quite right: some areas of the screen would freeze, some weird black blocks would appear, etc. I do know, however, that (1) does work, because one time I called (1) and didn't call (2) and my desktop appeared completely frozen (had to reboot, even TaskMgr didn't render correctly). I also tried using SuspendLayout and ResumeLayout on my form, but I don't think they are meant to handle my case.
Any help would be greatly appreciated.
You can do the checking yourself since your need to customise beyond that what the standard functions offer.
Call EnumWindows() to get a list of top-level windows.
Remove your semi-transparent window from this list.
For each window in the list use PtInRegion() to determine whether or not the mouse is over the window. Remove any windows that don't fit the bill.
Use GetNextWindow(), starting from one of the remaining windows to walk the z-order and find out which of the candidates is at the top.
I'm pasting an image from the game im building.
the matrix of empty cells you see are made of PictureBox[][].
I wan't whenever I drop a coin to one of the columns... I want it to go down but the purple stuff will hide the falling coin and the gray color you see wont hide it.
How do I make this effect?
please notice that in each PictureBox control I have set the BG Image as you can see
Don't do it like that.
Create custom control. In custom control, override Paint, and then draw COIN sprite first, then draw mask over it. Be sure that you use double-buffered painting here.
It will work like a charm, trust me!
And, since you are (I gueess) building 5-in-a-row game here, your custom control will be able to paint occupied slots as well.
By designing custom control, you'll be able to hide all the animation and graphics stuff away from your main form.
I don't think it is possible like that. Controls in WinForms cannot be transparent, that is the problem
I would think in three directions:
Forgetting about controls and
painting everything OnPaint event of
the form. It is not too complicated
(well it would be more complicated
to detect some mouse events like you
did now, as you wouldn't know which
graybox is hit, but rather just
mouse coordinates)
Experimenting with coin as a form
(forms can be transparent)
Possibly using WPF with same logic
you did, as controls can be
transparent there
Controls in Windows Forms can be transparent. You need to set the TransparencyKey of the Form to some color that you never plan on using (many people seem to love/hate Magenta for this), and then set the BackgroundColor of each PictureBox to the same color. The result should be a transparent PictureBox with its Image drawn over it. I'm pretty sure this won't work with the BackgroundImage property, mind you- just the Image property.
One potentially unwanted side effect of this method is that you'll be able to see whatever's behind your form (the desktop, other application windows, etc.) through the transparent places in the PictureBox.
I am just trying to create a form control in winform in .net with custom shaped of balloon shape.
There is need of a balloon tooltip which is transparent and I can put buttons on tooltip,but
tooltip in .net does not provide facality that we can put the buttons on tooltip control so
I want to make a form control looks like a balloon tooltip and so I can put buttons on that form looking like a tooltip.But I cannot show window form control look like a balloon tooltip.
So what should I do??
I tried in one way that I create a image in powerpoint of balloon shape and set it to as background image of form property.But there is no solution with that.
The Control class supports a BackColor with an alpha < 255, it is automatic. It asks the Parent to draw itself to produce the background of the control, then draws itself on top of that. However, you'll want a top-level window for a balloon. That's a window type that can arbitrarily overlap another window and isn't confined by the client area of an underlying window. It has no Parent. A ToolTip is such a window.
The only control available in Windows Forms that can be an top-level window is a Form. Problem is: the transparency trick no longer works. Since a top-level window doesn't have a Parent, there isn't any obvious window to ask to draw the background. It could be many windows, belonging to other processes. You can get transparency in a Form with its TransparencyKey property. But that's a "hard" transparency, equivalent to an alpha of 0. You probably want a soft one. Another nasty problem is that drawing anti-aliased (ClearType) text no longer works since there is no reliable background pixel color anymore.
Long story short: you can't make this work well unless you confine the balloon to the client area of a form. A control, not a form.
You can try to hook on the Paint event of the control and draw the Visual of the button there.