Since there is no way to deep customizing (a gradient background for example) win32 controls (such as buttons, menu items e.t.c) many people advise to create an own custom control.
And if I need a custom button I will use WM_MOUSEMOVE, WM_LBUTTONDOWN and a shadow buffer. I will draw all controls on the shadow buffer and then use BitBlt(hDC, ...) for my window.
But if I want to create a custom menu I must to foresee that menu can be drawn outside of the client area.
At first I need to mouse tracking outside of the client area. SetCapture(hWnd) seems to be a bad solution as it blocks mouse tracking for windows below.
Then I need to draw/erase items outside of my window. Erasing with InvalidateRect(NULL, NULL, TRUE/FALSE) seems to be a bad solution too as it cause of blinking.
What is the best approach to create custom menu with WinAPI?
Runtime menus that can appear anywhere on the screen can be shown with TrackPopupMenu() function. Create the menu with CreateMenu(), AppendMenu() etc, then show it with TrackPopupMenu().
Related
In the Win32 API (pure win32), The Menu bar does not occupy any area from the client area of the window. Which means the origin coordinates of the client area is right under the menu bar to the left.
When we create child window controls using CreateWindow (or any other method), that window takes some area of the client-area.
eg:- Creating a button which is at (xPos = 0, yPos = 0) and (width=width_of_client_area, height=20).
After creating the button if you'll use a GDI function like this, it'll be drew below the button:
Rectangle(hdc, 0,0, 200, 200);
But when creating a menu bar, it doesn't occupy client area. (GDI will not be drew under menu).
FINAL QUESTION:
How can i create a control on my parent window like the menu bar ?
The menu is rendered in the non-client area of the window, which is driven by a completely different set of window messages. Keep in mind that you don't actually create child windows for these types of controls. You will need to provide all the rendering and event handling for the customization you want to add. This means that if you want to add a button or checkbox you will need to implement it yourself. You can get your started with a handful of steps but there may be other things that need to be done depending on your requirements.
The first step is to process the WM_NCCALCSIZE message. This will allow you to adjust the size of the non-client area so that you have more space to draw the custom control. Basically you will pass this message on to the default window proc then modify the location and dimensions (just drop the top down X pixels) before returning.
The next step is to handle WM_NCPAINT message. Pass the message on to the default window proc then draw your custom visuals in the area you have reserved. You will be working with a window DC so you can draw to the entire window. It's important to keep this in mind so you don't destroy anything in the client area.
The last item that needs to be done is to handle mouse messages like WM_NCMOUSEMOVE. If the mouse event occurs outside the area where your control is located pass the message to the default window proc, otherwise handle the message yourself and skip the default proc. you will need to manage some state data for keeping track of when a button is down or not so as not to cause conflicts with the default window proc.
Keep in mind that when you want to draw directly to the non-client area you need to call GetWindowDC() instead of GetDC() to acquire a device context.
[Note: A good Google dance will be something like "WinAPI non-client area"]
This is a screenshot of Steam's client window being resized.
Steam's client window has two cool features.
Custom window which is very responsive.
Cool glass resize effect, different from standard windows (Thought it might be a side effect strongly related to 1)
Let's say I wanna create similar window using winapi. How can I do it?
I don't ask about widget-management related stuff, but about technical winapi tricks.
Basically, you can do almost anything with your window. But most of the tricks are to be implemented manually.
What is 'very responsive' I don't know. If you mean that the window has no standart border, it is easy to implement: do not specify WS_BORDER and WS_CAPTION when creating a WS_POPUP window. After that you will have to draw a border and a caption yourself. Handle WM_ERASEBKGND and WM_PAINT messages, draw background, menus, all as usual.
This effect seems to me more like a bug. It happens this way: the window is resized, it gets a WM_SIZE message, processes it, Windows sends a WM_ERASEBKGND message which the window ignores. Thus, the system draws a new shadow around new window frame which is not yet filled with new window image. And here we get this cool glass effect: old image of underlaying windows with a windows aero shadow. You can try to disable windows shadows and look at this effect.
In order to create a custom resizing border, you might find useful these functions: LoadCursor, SetCursor, MoveWindow.
In order to draw your custom borders, you can use standart GDI functions. Also you can create a handful of child windows and delegate drawing to them. This is basics of winapi.
I have a popup dialog( CDialog ) that handles WM_CTLCOLOR message to color itself. It is having some controls (like bitmap buttons) that draws themselves using OwnerDraw. It is also having a control that displays an image with size that takes up to 70% of the dialog.
When user re-sizes the dialog, some of the controls in the dialog should be re-positioned (not re-sized). It also involves re-sizing of the image inside the dialog. As the re-sizing of image makes the whole process slow, individual re-positioning of the controls are causing a visual effect of flickering.
I need to get rid of these. One idea is to put the controls as the children of an intermediate dialog that is the child of the original popup dialog. So, when there is a re-size, I can re-position the dialog only instead of moving each controls individually. (Re-position happens only in one direction (x or y), so moving the intermediate dialog should be enough.
As it involves some coding effort, before going this way, I need answers to the following questions:
Will this work?
If yes, whats the complexity involved in this method?
Is there a better way?
Please help!
Simple fixes are:
creating the slow window last so that it doesn't hold up drawing of the simple controls
turning on the WS_EX_COMPOSITED style flag so Windows double-buffers the entire window, including its children. Beware of painting artifacts
turning off the WS_CLIPCHILDREN style flag so the holes are not so noticeable. Making the background white would accomplish the same
keeping the drawing of slow controls simple between WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE
using less controls, burning up an expensive window on a simple string or image is unnecessary
It will probably work, but you should try solutions that don't alter your control hierarchy before, because it has other subtle consequences (focus, tab order, message notifications, etc).
Try one or all of the following:
Use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos functions to move the children.
Set the WS_CLIPCHILDREN style flag in the dialog.
Set the WS_EX_LAYERED extended style flag in the dialog.
I want to create a Window like when a context menu pops up or clicking the menubar. I want a Window that will be like this and that I can take over its paint event. Sort of like what is created when you select a sub tool in Photoshop.
EDIT:I want to know how to create controls like the one that comes when you select a sub tool in Photoshop, these do not seem to have a parent window. Those little description popups are a good example of this type of window, and menu items, those rectangles have no parent window.
Thanks
EDIT2: see this: http://cdn-viper.demandvideo.com/media/CB3C805F-421E-45AE-8359-39D59D8F0165/jpeg/20412728-192C-462A-AF8E-1F30BA77AE05_2.jpg
You will notice the window for the sub tools, it is not constrained to a parent window.
But how do they get a nice shadow
around it, and how does it still stay
with the main window without a parent?
That's your real question.
There are several ways of getting the shadow. One is that the window is actually two windows, the "shadow" plus the "main" window.
When you create the flyout window (that's what it's called), you position it near the toolbar. If the toolbar gets a WM_MOVE message, it's your responsibility to call MoveWindow() on the flyout to keep it lined up.
Edited to add
The dwExStyle parameter of CreateWindowEx() should include WS_EX_LAYERED and probably WS_EX_TRANSPARENT, because the 'shadow' will use alpha blending. The hWndParent parameter is the application's main window. The x and y parameters must be calculated as an offset of whatever button the window is to be associated with.
I'm trying to create a custom dropdown for a derivative of CComboBox. The dropdown will be a calendar control plus some 'hotspots', e.g.
So I figure the best way to achieve this is to have a simple CWnd-derived class which acts as the parent to the calendar control, and have it paint the hotspots itself.
The window needs to be a popup window - I think - rather than a child window so that it isn't clipped. But doing this causes the dialog (on which the combobox control is placed) to stop being the topmost (foreground?) window, leading to its frame being drawn differently:
alt text http://img693.imageshack.us/img693/3474/35148785.png
This spoils the illusion that the dropdown is part of the combobox since its acting more like a modal dialog at this point. Any suggestions on how I make the custom dropdown behave like the regular dropdown?
Are there any other pitfalls I need to watch out for, e.g. focus and mouse capture issues?
When you create your popup window, you need to specify its owner. Owned popup windows will activate their owner when you activate them. Not specifying an owner will cause your window to get activated, which causes the change in the owner you're seeing.
Yeah I had this problem once. A quick google makes me suspect I solved this by using CreateWindowEx() and specifying WS_EX_NOACTIVATE. I have some other code that achieves the same effect by making the window with WS_EX_TOOLWINDOW rather than as a popup window, but I'm not sure of why that was done that way, my intuition would say that making it a popup window would be the way to go.
You can find in the following links two sample project that put in the CComboBox dropdown window a CTreeCtrl or a CListCtrl controls ... similar, you can put whatever you need there. Here is the links:
Tree ComboBox Control
and
List ComboBox Control
I hope this help you.