I have a Windows Forms control (a subclass of Panel) that serves as a panel that displays an image. The background of the control serves as the image that is displayed to the user.
The image itself is generally a screenshot of whatever is behind the application. The method of obtaining this screenshot is to hide the application and have the user press a button.
When that button is pressed, the screenshot is saved as the background of the Windows Forms control, and then the application is shown again. The background doesn't appear to update
until the control is visible again, and this causes a noticeable flicker of sorts as the old background switches to the new background. Is there a way to cause the background to
change while the control is hidden and remove this flicker?
Code:
public void updateBackground()
{
Image bg = null;
do
{
// this just gets the background using gdi32 and user32 calls
bg = Utilities.getDesktopImage();
}
while (bg == null);
// this function invokes the GUI thread to change the BackgroundImage of the
// drawPanel
drawPanel.setBackground(bg)
// drawPanel is a child control to the main Form
mainForm.show();
}
I have also tried using various forms of Refresh() and Invalidate() to get the control to update before it is shown. Application.DoEvents() seems to improve the speed, but there is still a noticible change from the old background to the new one.
Is there something that I'm missing? I can't seem to find what I'm looking for on Google, or elsewhere on StackOverflow.
Thanks.
Try moving your logic to another thread (Task, Backgroundworker or ThreadPool). This shall remove the lag you see.
The flicker occurs because (I assume) you do some relatively lengthy work in the UI thread, which blocks graphic message loop and everything "freeze" for a fraction of a second.
Are you using Win7 or Vista and is the Desktop Window Manager Service running?
Does the problem go away when the DWM is disabled (Control Panel --> Administrative Tools --> Services --> Desktop Window Manager Session Manager)?
It sounds like an issue with Aero - the way the DWM works is that the form's graphics buffer is not updated while it is hidden. The DWM stores the data from the last visible paint and doesn't refresh until the form is visible again. This causes the previous form canvas to be visible briefly until Windows gets around to repainting the changes since it was last visible (ie: the flicker).
This article discusses some of the topics :
http://blogs.msdn.com/b/greg_schechter/archive/2006/05/02/588934.aspx
There is probably a way to override some of this behaviour but I'm not familiar with it off the top of my head. Tagging this with GDI+ may help get better answers.
Related
When a form loads, I'd like it to show a loading image (within a Picture Box) and a standard Windows label with some text. However, all I see are white boxes, or sometimes I see another form underneath. How do I get the image and label to display properly.
I've tried setting AllowTransparency to false when the form loads, and also setting the Transparency Key of the form to some other colour, but nothing has worked.
The project is C# .Net v3.5 (also tried v4 and v4.5).
Any ideas?
First, you can't display an image, busy-wait, and then change the image - this will never redraw anything, leading to the symptoms you describe. To "wait" you will need to return control to your main application loop so it can continue to process messages (e.g. to handle redraw requests for your window). One way to do what you want is to display your initial state (splash screen) and then use a timer to call you back later to change the display to your second state.
The next problem you face is using forms controls with transparency. Most controls treat "transparent" as "fill your background with your parent controls color", which is not what you want. An easy way around this is to implement a Paint handler and draw the image and text for yourself - this gives you much more control of how your display looks, and will also allow you to get a cleaner redraw (no flicker or other problems caused by the display being built up but by bit in several controls)
Lastly, consider implementing your splash screen display as a separate control/form that you show above your main form during loading, as that makes it easy to "overlay" on your main form without having to change its design at all.
Just write formObjectName.Refresh() after formObjectName.Show()
I have a winforms C# application that opens multiple dialog boxes. To suit the style of the application, I have removed the default title bars for each window and created my own (with control buttons and drag-to-move function).
The problem that now faces me is that without a titlebar, the user has no way of telling which window is the 'active' window when they are manually moved apart (so they are not overlapping).
In any windows application (that uses titlebars), when you try to navigate away from a dialog box back to the main program (without closing the dialog box) - it wont let you. The border of the dialog box flashes and you hear a windows error sound. Some kind of equivalent visual feedback would be great without needing to have the default titlebars - and tinting an entire window darker seems like it would do the trick nicely.
Something like this in pseudo-code, which would nicely tint the parent window whilst a dialog is open:
// tint window now
window.ShowDialog();
// un-tint window
I have tried to place a panel covering everything with colour set to 'transparent' (with the intention of later controlling the opacity of the panel) but the transparency does not seem to work. Any other ideas of accomplishing this? Or does anyone have a better suggestion to achieve the same level of visual feedback?
Summary:
Is there any way to tint an entire window, or overlay it with a colour? If not, could anyone suggest an alternate method of making the window appear 'inactive'?
I would suggest you to create a method in forms you want to disable:
void DisableForm()
{
//some fancy color
this.BackColor = System.Drawing.Color.Khaki;
//and disable all controls owned by form, just to be sure
foreach (var s in this.Controls)
{
((Control)s).Enabled = false;
}
}
and functions which enables back those forms of course.
edit.
also you can set visibility property of controls to false
I am currently working on a windows form application (C# visual studio).
Is it possible to grey out the entire windows screen when a button is pressed?
How can I work that out?
Is it also possible to grey out the entire screen but leaving an ungreyed space in the middle for a message box for showing some text?
Answers to your question:
Is it possible to grey out the entire windows screen when a button is
pressed?
You can put a control like a panel over the entire window and hide it.
In the button event you then make it visible. Set the background of the panel to gray and vary the transparency to adjust it so until your window visibility beneath it looks right.
This will force the window into a "modal mode" without any way out. So you better have logic for undoing this as well.
How can I work that out?
Make sure you have some event such as completion of an event or query to hide the control or the user will never get back into your application again.
Is it also possible to grey out the entire screen but leaving an
ungreyed space in the middle for a message box for showing some text?
That is more complex and to be honest with you I haven't played with WinForm is some time -- instead doing WPF for desktop. You MAY be able to use clipping but you will have to do quite a bit of research into how to do it. Use Google -- it can be your best friend.
easiest way:use XAML pop-up as described below
<Popup x:Name="pop" IsOpen="False" >
</Popup>
For more details visit below link. http://www.c-sharpcorner.com/UploadFile/mahesh/using-xaml-popup-in-wpf/
After this to blur the main grid on eventhandler for the event which shows the pop-up,set the opacity as shown in below C# code
if (pop.IsOpen == false)
{
pop.IsOpen = true;
grdMain.Opacity = 0.4;
}
else
{
pop.isopen=false;
}
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.
We have a mapping form in our application that needs a Google Earth background image, and as you can't use the Google Earth plugin in a browser that is under a panel, we use a second form to show the background image. We have a transparent panel on the mapping form that the drawing is done on while Google Earth is drawn on a form held in sync below.
We achieve transparency by giving the form a transparency key of 255, 250, 250 and setting the panel background to this color before drawing on it. Although now after looking at the information available online it appears that the panel shouldn't ever get cursor events.
This works perfectly in most cases, but on one or two customers machines (one is definatly Windows 7) the cursor will not work correctly on the panel where it is transparent. If the cursor is placed over a drawn area of the map then it all work fine.
I think the issue is due to transparancy click through but as it works in most cases I'm not sure what is exactly going on. We've updated all of the graphics drivers to see if there is a custom setting on the customers machine but this hasn't helped.
Does someone have a definative description of what the transparency key does? Is there a way to absolutly set that the panel should recieve the mouse events?
EDIT
Added detail about transparency key.
Try intercepting the WM_HITTEST message in the WndProc for the Form window and when you know it is over the client area return the appropriate HTCLIENT value. It could be that the default window processing is sometimes returning a different value.
Stevo - Have you ever figured out an answer to this? I had the same problem and figured out to change the transparency key of the main form to some odd color. May or may not help you. I had a custom control with transparency but the forms key color was also my drawing color, thus allowing it to click through (strangely). I changed it and it worked!