How do you place sub controls inside a group box? - c

When I enable common control visual style support (InitCommonControls()) and I am using any theme other then Windows Classic Theme, buttons inside a group box appear with a black border with square corners.
Windows Classic Theme appears normal, as well as when I turn off visual styling.
I am using the following code:
group_box = CreateWindow(TEXT("BUTTON"), TEXT("BS_GROUPBOX"),
WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_GROUP,
10, 10, 200, 300,
hwnd, NULL, hInstance, 0);
push_button = CreateWindow(TEXT("BUTTON"), TEXT("BS_PUSHBUTTON"),
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
40, 40, 100, 22,
group_box, NULL, hInstance, 0);
EDIT: The issue occurs with radio buttons as well
EDIT: I am not using any dialogs/resources, only CreateWindow/Ex.
I am compiling under Visual C++ 2008 Express SP1, with a generic manifest file
Screenshot http://img.ispankcode.com/black_border_issue.png

The problem is having the groupbox as the controls' parent. Groupboxes are not supposed to have any children and using them as parents will cause all kinds of errors (including painting, keyboard navigation and message propagation). Just change the parent in the buttons' CreateWindow call from group_box to hwnd (i.e. the dialog).
I'm guessing you used the groupbox as the parent in order to position the other controls easily inside it. The proper way to do this is to get the position of the groupbox client area and map it to the client area of the dialog. Everything placed in the resulting RECT will then appear inside the groupbox. Since groupboxes don't actually have a client area, it can be calculated with something like this:
// Calculate the client area of a dialog that corresponds to the perceived
// client area of a groupbox control. An extra padding in dialog units can
// be specified (preferably in multiples of 4).
//
RECT getClientAreaInGroupBox(HWND dlg, int id, int padding = 0) {
HWND group = GetDlgItem(dlg, id);
RECT rc;
GetWindowRect(group, &rc);
MapWindowPoints(0, dlg, (POINT*)&rc, 2);
// Note that the top DUs should be 9 to completely avoid overlapping the
// groupbox label, but 8 is used instead for better alignment on a 4x4
// design grid.
RECT border = { 4, 8, 4, 4 };
OffsetRect(&border, padding, padding);
MapDialogRect(dlg, &border);
rc.left += border.left;
rc.right -= border.right;
rc.top += border.top;
rc.bottom -= border.bottom;
return rc;
}
Note that the same applies to Tab controls. They too are not designed to be parents and will exhibit similar behavior.

Just a guess here, but it looks like you are inheriting either the Static Edge or Client Edge style from you theme. I create most of my dialogs from the resource editor and set these properties there.
In your case, you can replace your CreateWindow with a CreateWindowEx to set these extended styles, which are probably being defaulted in CreateWindow. Specifically check out WS_EX_STATICEDGE, WS_EX_WINDOWEDGE and WS_EX_CLIENTEDGE
Edit: I'm assuming that this is not happening because you button is the default control in the dialog, which would also give a black edge.

Apparently group boxes are not meant to group controls (be a parent hwnd)
So in order to get rid of the black borders/painting issues I would have to subclass group box and implement WM_PAINT and WM_PRINTCLIENT

Ahh yes the black background with radio buttons and group boxes. Although I'm not sure if this will work for VC++ 2008, but back-in-the-day the solution for VB6 themed apps was to put the radio controls on a PictureBox (a generic container really) first and then add that to the group box.
Its worth a shot!

Related

How can I remove an arbitrary HWND border (WinAPI)?

Long story short, I'm building an i3-style tiling window manager, and need to override the chrome of arbitrary windows to compeltely remove borders, the titlebar, and associated buttons.
Having tried just about every logical combination of WS_STYLE and WS_EX styles relating to chroming, I'm getting nothing for most apps. It's fine with simple native programs (terminals work as expected), but for the vast majority of other apps, the same problem occurs;
The above result is present in most cases. There is a surrounding border which is of the same size, but with variant behaviour per app. As far as I can tell, this is the "transparent" (obviously not in this case) border used for mouse drag hittesting (although with the frame disabled in styling, this shouldn't be present). It seems that the framebuffer isn't being cleared in this area (i.e. if the window is resized into itself, the border is filled with previous pixels at that location).
This is a quick weekend project- my job isn't related to WinAPI programming, so this is all new to me, but if I'm assuming right then this border is effectively the non-client area? In other words, the non-clientarea must be zeroed so that the client area takes up the entire window rect. I've attempted to handle this by subclassing all target windows with GWL_WNDPROC and zeroing WM_NCCALCSIZE, but I'm getting the same result.
How can I force an arbitrary window (which I don't create myself) to completely remove it's entire non-client area?
I use the following function to remove/restore the borders of a window:
void WndSetFrame(HWND hWnd, int bSmall)
{
static int wwStyle=0; // remember initial style
int ww= GetWindowLong(hWnd, GWL_STYLE);
if (bSmall) {
wwStyle= ww;
ww &= ~(WS_OVERLAPPED|WS_CAPTION|WS_MAXIMIZEBOX|WS_MINIMIZEBOX|WS_SIZEBOX|WS_SYSMENU);
ww |= (WS_POPUP /*|WS_DLGFRAME*/);
if (ww==wwStyle) return;
SetWindowLong(hWnd, GWL_STYLE, ww);
}
else {
if (!wwStyle || ww==wwStyle) return;
SetWindowLong(hWnd, GWL_STYLE, wwStyle);
}
SetWindowPos (hWnd,0,0,0,0,0,SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);
}

How do I retrieve the correct size of native Windows controls?

I use this line to create an EDIT control:
hMyEdit = CreateWindowEx(
WS_EX_CLIENTEDGE,
L"EDIT",
L"",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_LEFT,
10,
10,
200,
25,
hParentWnd,
(HMENU)IDC_MY_EDIT,
hInst,
NULL
);
Next to it, there is a COMBOBOX:
hMyCombo = CreateWindowEx(
WS_EX_CLIENTEDGE,
L"COMBOBOX",
L"",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_VSCROLL | ES_LEFT | CBS_DROPDOWNLIST| CBS_HASSTRINGS,
220,
10,
90,
200,
hParentWnd,
(HMENU)IDC_MY_COMBO,
hInst, NULL
);
There are two problems I cannot figure out:
If I reduce the height (currently 200) of my COMBOBOX, this also limits the maximum height of the actual dropdown list. However, the actual height of the control without the dropdown list is not affected at all. Is the COMBOBOX supposed not to use more than the given height for the dropdown list?
How can I make my EDIT control the same height as the text field of my COMBOBOX control?
I was unable to find any documentation about default sizes, but I hope there is a proper way to size controls.
To sum it up, my questions are:
Which height should I apply to my COMBOBOX to allow the dropdown list to expand as far as necessary?
Which height should I apply to my EDIT to have the same height for the text field of the COMBOBOX and the EDIT control?
Behavior depends on the style you selected for the combobox. If it is CBS_SIMPLE then the height is determined by the nHeight argument you pass to CreateWindowEx(). But if it is CBS_DROPDOWN/LIST then nHeight sets the dropdown extent and it figures out by itself what the height of the textbox portion needs to be. Based on the font, sending WM_SETFONT changes the height.
Which height should I apply to my COMBOBOX to allow the dropdown list to expand as far as necessary?
It is entirely up to you. A sane choice is to have at least ~8 items visible. Consider the location of the combobox in its parent's client area. You'd normally favor the dropdown list staying inside the parent. But that's not always practical, if the combobox is near the bottom of the window then you have no option but letting it extend beyond the parent's bottom. Beware the usability problem that this causes, the list won't be completely visible if the parent window is located near the bottom of the desktop.
Which height should I apply to my EDIT to have the same height for the text field of the COMBOBOX and the EDIT control?
This tends to drive UI designers pretty batty, you can't get the same height when you give these controls the same font. The combobox will be two pixels taller. Text aligns properly however. Strange quirk and I don't have a very good explanation for that, 30 years of appcompat can be hard to reverse-engineer. I'd assume it has something to do with the space needed for the focus rectangle that is displayed in the CBS_DROPDOWNLIST style. You could tinker with the font, giving the combobox an intentionally smaller font but that does not look very good either. Anyhoo, use WM_SETFONT to ensure the combobox and textbox display text in the same font.
Is the COMBOBOX supposed not to use more than the given height for the dropdown list?
No, a scrollbar will appear when the content does not fit inside the listbox part. And you can even add CBS_DISABLENOSCROLL to force the scrollbar to be always visible.
How can I make my EDIT control the same height as the text field of my COMBOBOX control?
EDIT: Use GetComboBoxInfo to get the handle of the edit part of the combo box (among other things), then use GetWindowRect to gets its rectangle:
COMBOBOXINFO cbi;
cbi.cbSize = sizeof(cbi);
GetComboBoxInfo(hMyCombo, &cbi);
GetWindowRect(cbi.hwndCombo, &r);
Now the height is r.bottom - r.top and that returned 24 on my test, which is very close to the 25 you got experimentally.
That said, it's easier to use a dialgo box. You can create a dialog box from resource or dynamically using the CreateDialogIndirect function.

flicker on tab control - WIN32

I have a WIN32 application. Its main window is hwndMain, one of its child is hwndView. There is one tab control hwndTab on hwndView.
When I resize hwndMain, hwndView is resized and so is hwndTab. It flicker a little, but not much.
I have tried to use WS_EX_COMPOSITED style ( for hwndView or hwndTab), but it just gave me blank window. I tried to use WS_EX_TRANSPARENT and it solves flicker, but when the windows is resized to be larger, the childs are updated very slow, e.g I see black region for one second, then the region is updated.
I have successfully sloved the flicker issue for TreeView by using WS_CHIPCHILDREN style. (See remark below). But using WS_CHIPCHILDREN stlye for hwndView doesn't fix the flicker issue for tab control.
I have paid attention to WM_ERASEBKGND and Not set hbrBackground also.
I want to use double buffer for tab control, but I can't find a tutorial for this purpose. All the tutorial I found is: In WM_PAINT, after creating CompatibleDC and CompatibleBitmap, draw what you want in memdc and.....; But I don't want to do any custom drawing in WM_PAINT for hwndTab. I just want to leave the tab control do this job, but shows the final result only.
Could someone show me a small example how to double buffer a tab control (if you think this will fix the flicker issue of tab control), in the language c + winapi, since I don't have the knowledge of C#, Net,..etc.
Remark: For my TreeView, it is a child of a window hwndContainer. It is created as:
win->hwndContainer = CreateWindowEx(
WS_CLIPCHILDREN,
_T("SUMATRA_PDF_TOCBOX"), NULL,
WS_CHILD,
0, 0, gGlobalPrefs.sidebarDx, 0,
win->hwndPanel, NULL,
ghinst, NULL);
Using WS_CLIPCHILDREN fix the flicker, even if I don't use double buffer. But it is strange to put
WS_CLIPCHILDREN in the first parameter position. If I put it after WS_CHILD, i.e
win->hwndContainer = CreateWindowEx(
NULL,
_T("SUMATRA_PDF_TOCBOX"), NULL,
WS_CHILD | WS_CLIPCHILDREN,
0, 0, gGlobalPrefs.sidebarDx, 0,
win->hwndPanel, NULL,
ghinst, NULL);
,then the flicker still occurs.
So I also tried to use the first way when I created hwndView, but it just gave blank white window.
I am really confused with these stuff.
Here is the blank window picture when I used WS_EX_COMPOSITED for hwndView.
There is no such problem when I used it for hwndContainer.
hwndView in fact has two child: a Tab Control hwndTab and a child which has its own double buffer and drawing. I am not sure if this cause the problem for using WS_EX_COMPOSITED.
You are using the WS_EX_COMPOSITED style. When you pass WS_CLIPCHIDREN as the first argument to the CreateWindowEx, it's interpreting the value of WS_CLIPCHILDREN as an extended window style. Since the value of WS_CLIPCHILDREN is 0x02000000L, the same as WS_EX_COMPOSITED, you've just created a composited window.
And a composited window, according to the documentation, has all of its descendants painted in a bottom-to-top painting order using double-buffering.
I'm not sure what you mean when you say:
I have tried to use WS_EX_COMPOSITED style ( for hwndView or hwndTab), but it just gave me blank window.
You'll have to post code the reproduces this problem. But your second-to-last code snippet is producing a composited window.

How to hide window from "Applications" tab in task manager?

I have question regarding the CreateWindowEx function. I have 2 windows, a main one and a popup one. I want a popup window to hide everywhere. It is currently not displayed in taskbar and it is not even visible in alt+tab menu. However it is visible on "Applications" tab in task manager. What flags do I need to use in CreateWindowEx to hide my popup window from there?
Current code:
hHistoryWindow = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE | WS_EX_LAYERED, szAppName, L"HistoryWindow", WS_EX_TOPMOST | WS_POPUP, WIDTH, TOP, width, height, NULL, NULL, hInstance, NULL);
I also wanted to ask, whether I need to release a bitmap resource from "static" window before using DestroyWindow() function? I set image to a "static" window this way:
SendMessage (hStatic, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hWhiteStone);
Is it enough to release hWhiteStone or do I need to release also handle returned by SendMessage() (- or is it done automatically by DestroyWindow)?
Thank you for any info.
Kra
Make it a child of your main window. Do this by changing the fourth last parameter to the HWND of your main window. This SHOULD make windows treat your popup window as part of the same application as your main window.

Button background transparency using Win32 and Visual Styles

Edit: If anyone's tried this in win32 before, am I going in the right direction by using DrawThemeBackground()?
I'v recently enabled Visual Styles using a manifest for version 6 of ComCtl32.dll. Example of Visual Styles in Win32: Visual Styles
The buttons look great, but I can't figure out how to make the background around the buttons transparent. Please see example image: http://www.freeimagehosting.net/image.php?2bdeff33ba.jpg
My main window background color is set to dark grey with:
a.hbrBackground = GetStockObject(DKGRAY_BRUSH);
The common controls are initialized with:
INITCOMMONCONTROLSEX stylesStruct;
stylesStruct.dwSize = sizeof(stylesStruct);
stylesStruct.dwICC = ICC_STANDARD_CLASSES;
InitCommonControlsEx(&stylesStruct);
And I create the button windows with:
j = CreateWindow(L"BUTTON", L"hello",
WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 100, 100,
100, 100, h, 0, hInst, 0);
Buttons look fine over a white background, but the border becomes visible over anything else. Is it possible to make the border around buttons transparent?
Have you tried WS_EX_TRANSPARENT?
I think you can set it in the resource editor in Visual Studio, if you're using that.

Resources