WS_EX_TOOLWINDOW tool windows doesn't work as expected - c++

In our legacy code Windows extended style WS_EX_TOOLWINDOW is being used.This is basically for showing the title bar narrow.But recently in the later winodws versions the title bar is not drawn as narrow.That is WS_EX_TOOLWINDOW doesnt give a narrow title bar in the newer windows versions.Making the title bar narrow is done on a click event.Let me know if there is another way of achieving this?
I have read that we need to handle WM_NCCALCSIZE.But is there any other way of doing it?.Or if this is the only way,how can I handle it in a button click?
Code Snippet:
HWND hwnd = m_hWnd;
......
DWORD dwStylesEx = ::GetWindowLong( hwnd, GWL_EXSTYLE );
if ( bNarrowTitle == true)
{
dwStylesEx |= WS_EX_TOOLWINDOW;
}
else
{
dwStylesEx &= ~WS_EX_TOOLWINDOW;
}
...
::SetWindowLong( hwnd, GWL_EXSTYLE, dwStylesEx );

MSDN says:
Certain window data is cached, so changes you make using SetWindowLong will not take effect until you call the SetWindowPos function. Specifically, if you change any of the frame styles, you must call SetWindowPos with the SWP_FRAMECHANGED flag for the cache to be updated properly.

The default look just doesn't distinguish it in any way. Which suggests that you will just have to live with it.
It's probably been changed due to not being finger friendly if smaller!
Refer : WS_EX_TOOLWINDOW doesn't give look I want
As you said, handle WM_NCCALCSIZE may be the only way to handle the size of non-client areas.
Refer: How to set the size of the Non-client area of a Win32 window (native)

Related

Can't show/hide buttons in the main window of my C++ Win32 app [duplicate]

This question already has answers here:
Access a variable from a different switch case (from WM_CREATE to WM_CTLCOLORSTATIC in the WinApi)
(2 answers)
Closed last month.
I have created a basic button in case: WM_CREATE in the windows procedure with the following.
/*The "new_game_button" is declared as type HWND at the
start of the windows procedure function but not initialized.*/
new_game_button = CreateWindow ( "BUTTON", "New Game",
WS_CHILD | WS_BORDER ,
50, 50, 100, 100,
hwnd, NULL, NULL, NULL);
My intent is to create an instructions and "start new game" button as the first thing in my simple tictactoe app. It will immediately show as expected if I give the parameter WS_VISIBLE.
Further in the same case:WM_CREATE if I use the lines
if (!start_Game){ //global variable default is false
ShowWindow( new_game_button, SW_SHOW);
}
The button will show as expected.
Outside of those two cases I cannot get the button to show at a later stage.
Further, if I use one of those two methods to show the button I can never get it to go away using
ShowWindow ( new_game_button, SW_HIDE);
Once the button is showing, it stays for the duration of the programs execution. Doesn't matter which case. Command/Create/Paint
I have tried using
if (start_Game){
ShowWindow( new_game_button, SW_HIDE);
UpdateWindow ( new_game_button );
//UpdateWindow ( hwnd ); tried this as well
}
inside case WM_CREATE.
I have also tried the same SW_HIDE line inside case: WM_COMMAND where a new game is generated (compiles but doesn't hide the button.)
I have tried declaring the button child window outside the WM_CREATE inside the windows procedure function. Then using WM_CREATE to show the window - works -- still WM_COMMAND will not hide the window.
I have also tried creating the button window inside of case:WM_PAINT which works to show the button but not to get rid of it. I have even tried DestroyWindow which just fails. [returns 0]
In trying to understand the behaviour of the button window - I have found that I cannot get
ShowWindow( new_game_button, SW_SHOW);
to work in the case:WM_COMMAND.
You said (in a code comment in the question).
new_game_button is declared as type HWND at the start of the windows procedure function but not initialized.
Each incoming message means a new call to your window procedure. Variables which are local to a function don't retain their value between calls unless they are marked static.
When your window procedure returned from processing WM_CREATE, you lost the value of new_game_button. When you try to use it during WM_COMMAND processing later, it is uninitialized and your program causes undefined behavior by passing it to ShowWindow.
Every comment helped me solve this which I appreciate. I am too new to give reputation sadly.
case WM_CREATE:
{
new_game_button = CreateWindow ("BUTTON", "New Game",
WS_CHILD | WS_BORDER ,
50, 50, 100, 100,
hwnd, (HMENU) 1, NULL, NULL);
if (!start_Game){
ShowWindow( new_game_button, SW_SHOW);
}
}
break;
After I had an ID for the dialog I am able to use GetDlgItem function to show or hide as I please.
new_game_button = GetDlgItem (hwnd, 1);
ShowWindow( new_game_button, SW_HIDE);

How to set control focus inside an MFC custom control

Experts!
I am using a class that inherits CWnd to make the content visible using a horizontal scroll bar
The control I want to create looks like this:
However, I have some problems and leave a question
When the button receives focus, it changes to blue. If another button is pressed, the button that received the existing focus should be unfocused.
The button does not release focus as shown in the second picture.
However, the above problem occurs when implemented in Dialog, not in SDI.
I need help solving this problem.
Custom Control Create Code;
m_ScrollWnd.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, 1234);
BOOL CScrollWnd::Create(DWORD dwStyle, CRect &rect, CWnd *pParent, UINT nID)
{
dwStyle |= ((WS_HSCROLL) );
return CWnd::Create(CScrollWnd::IID, nullptr, dwStyle, rect, pParent, nID);
}
m_Button3.Create(_T("Hello3"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(0, 0, 0, 0), this, 1238);
The so called "default button handling" is done by a function named IsDialogMessage.
The easiest way to control this is to make your parent control a window derived from CDialog, or if it's a view derive from CFormView. The MFC will handle all this for you in the appropriate PreTranslateMessage handler.
If you want to do this by your own you might insert your own PreTranslateMessage handler and use IsDialogMessage. The CWnd class also has a predefined implementation named CWnd::PreTranslateInput.
So this might be sufficient:
BOOL CYourParentClass::PreTranslateMessage(MSG* pMsg)
{
// allow standard processing
if (__super::PreTranslateMessage(pMsg))
return TRUE;
return PreTranslateInput(pMsg);
}
Using CFormView / CDialog is the better way from my point of view, because also other "problematic things about dialogs" are solved in it. Including loosing and getting focus and activation...
Official document from MSDN: Dialog Box Keyboard Interface
BTW, xMRi explains it very well.

win32 - Using the default button font in a button

I'm creating a small WinAPI application in C++. I am trying to create a button on my form by using the code:
HWND hwndButton = CreateWindow(
TEXT("BUTTON"),
TEXT("Click Here"),
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, // Styles
10,
10,
100,
30,
hwnd,
NULL,
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
NULL);
This code is based off of an MSDN sample. My issue is that it uses a bold font on the button like this:
When I want to use the standard font like this:
I already have the preprocessor directive at the top of my file to enable visual styles.
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
What steps should I take to use the standard system wide font?
Thanks
GetStockObject isn't the recommended way of retrieving the GUI font (it doesn't take themes into account, and different fonts can be chosen for buttons, menus, etc). Instead you should use SystemParametersInfo (see Remarks section of GetStockObject).
It is not recommended that you employ this method to obtain the current font used by dialogs and windows. Instead, use the SystemParametersInfo function with the SPI_GETNONCLIENTMETRICS parameter to retrieve the current font. SystemParametersInfo will take into account the current theme and provides font information for captions, menus, and message dialogs.
NONCLIENTMETRICS metrics = {};
metrics.cbSize = sizeof(metrics);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
HFONT guiFont = CreateFontIndirect(&metrics.lfCaptionFont);
// When you're done with the font, don't forget to call
DeleteObject(guiFont);
There's no such thing as default system wide font for controls, initially you get a control created with "System" font, that's what you see on first picture. When button is created as part of a dialog, it uses a font from dialog template, so using something like "MS Shell Dlg" with appropriate size + WM_SETFONT on a button should give you the same result as on picture 2. Note that there's no physical MS Shell Dlg font on a system, it's mapped to particular font according to registry settings.
Common control manifest has nothing to do with this, behavior has not changed with comctl32 version 6.
The default GUI font is stored in DEFAULT_GUI_FONT, and can be retrieved via
GetStockObject(DEFAULT_GUI_FONT);
To set the font of the button you can use:
HWND yourButton; // use CreateWindow or anything else to get this
SendMessage(yourButton, WM_SETFONT, (LPARAM)GetStockObject(DEFAULT_GUI_FONT), true);
A convenient way of doing this without calling SendMessage on every single child window manually is to use the EnumChildWindows function with the following callback function -
Create the callback function EnumChildProc:
BOOL CALLBACK EnumChildProc(
HWND hWnd,
LPARAM lParam
)
{
HFONT hfDefault = *(HFONT *) lParam;
SendMessageW(hWnd, WM_SETFONT, (WPARAM) hfDefault, MAKELPARAM(TRUE, 0));
return TRUE;
}
At the start of your (w)WinMain function, add the code:
NONCLIENTMETRICSW ncm;
HFONT hfDefault;
ZeroMemory(&ncm, sizeof(NONCLIENTMETRICSW));
ncm.cbSize = sizeof(NONCLIENTMETRICSW);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, FALSE);
hfDefault = CreateFontIndirectW(&ncm.lfMessageFont);
Then, after the ShowWindow call, add this line:
EnumChildWindows(hWnd, EnumChildProc, (LPARAM)&hfDefault);

Switch between edit controls using Tab?

The Window is non DialogBox based so WS_TABSTOP doesn't work. Moreover I don't want to Tab through all the controls, I just want to Tab through few Edit controls.
What I did is I superclassed the Edit control and handled the WM_KEYDOWN message, switching between edit controls, by getting next window in the line thorugh ::GetWindow(hwnd,GW_HWNDNEXT); Also I would like to switch focus back to the first Edit control when I have reached the last one.
The Code doesn't work for when I have reached the last Edit control, the ::GetWindow simply returns the next window in the line(?), which happens to be a non superclassed edit control. And there are more hidden child windows(SW_HIDE).
Maybe if I know how to know the class name of the window's HWND ?
Note: Pure Win32 api, c++ oop.
else if ( ( int ) wParam == VK_TAB )
{
HWND nextInLine;
nextInLine = ::GetWindow ( hwnd, GW_HWNDNEXT );
if ( hwnd == NULL ) nextInLine = ::GetWindow ( hwnd, GW_HWNDPREV );
::SendMessage ( nextInLine, EM_SETSEL, ( WPARAM ) 0, ( LPARAM ) -1 );
::SetFocus ( nextInLine );
return 0;
}
You get keyboard navigation for free in any window by using the IsDialogMessage API call. To consume the service a window message loop has to be modified to include a call to IsDialogMessage and only pass the message on to regular message handling if it hasn't been handled by the dialog manager already.
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0)) {
if (IsDialogMessage(hwnd, &msg)) {
/* Already handled by dialog manager */
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Don't forget to set the WS_EX_CONTROLPARENT extended window style on the parent window, so that the dialog manager recurses into child windows.
It's possible to get away with just calling IsDialogMessage, but the result isn't quite 100% dialog-like. To make an ordinary window behave like a dialog:
Specify DLGWINDOWEXTRA as the cbWndExtra field of your WNDCLASS (don't forget to add on extra space you might already be using and offset your data's indexes)
Call DefDlgProc rather than DefWindowProc
Since this makes your window a dialog, you need to use the DWLP_USER window long instead of GWLP_USERDATA, if you're using that, when calling GetWindowLongPtr or SetWindowLongPtr.
(From memory, the main thing you get from doing the above is support for WM_NEXTDLGCTL, which I've found useful to use for supporting changing focus using the Enter key, using Method I described in http://support.microsoft.com/kb/102589.)
Then in your message pump, call IsDialogMessage for each dialog-like window in your message pump.
Finally, when creating controls for your dialog-like window, set the WS_TABSTOP window style for each window you want to participate in the tabbing, and set the WS_EX_CONTROLPARENT window exstyle (aka Control Parent in the resource editor) for child windows that contain dialog controls.

Flickering using WM_DRAWITEM

It seems like I can't get pass this issue with owner-draw controls. I've super-classed a status control. I am trying to customize but still retain the same functionality. Basically, I want to change the background and text. I'm using Direct2d (or ID2D1DCRenderTarget interface) for the drawing. I have successful changed the background by using WM_NCPAINT; although, you can use WM_ERASEBKGRND if you want. However, both methods acted as a control in my experiment and flickering still occurred. Moreover, flickering doesn't occur when the WPARAM of SB_SETTEXT is NOT SET to SBT_OWNERDRAW. Therefore, I came to a conclusion that WM_DRAWITEM is the culprit. Is there anyway I can fix this flickering issue with owner-draw statusbar?
You can avoid flickering if you turn on double buffering for you control.
Set the WS_EX_COMPOSITED extended style:
http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx
e.g. when handling WM_CREATE, call (WTL or MFC):
ModifyStyleEx(0, WS_EX_COMPOSITED);
Well, seems like I figured it out. When super-classing a status-bar follow these sets to avoid flickering.
**Note: This has only been tested with visual styles turned off. SetWindowTheme(hWndStatus, L"", L"");
Also, the parent window must have WS_CLIPCHILDREN set in the style parameter during window creation.
1: Override WM_SIZE. Make a call to InvalidateRect(m_hWnd, NULL, TRUE) and return 0 unless you want the default sizing; in this case, call CallWindowProc.
2: Override WM_ERASEBKGND and return -1.
3: Override WM_NCPAINT and place your drawing code here.
Handling WM_NCPAINT. People seem to have trouble understanding how to handle WM_NCPAINT. Here is how I do it.
if (wParam == 1) {
hdc = GetWindowDC(m_hWnd);
} else {
hdc = GetDCEx(m_hWnd, (HRGN) wParam, DCX_WINDOW | DCX_INTERSECTRGN | DCX_CACHE);
}
Then do drawing with the DC.
4: In the parent procedure (WndProc or whatever) call SetWindowPos(..., SWP_DRAWFRAME) with the handle to the statusbar. This will resize your statusbar.
5: Send a message via SendMessage(hWndStatusbar, SB_SETPARTS, 1, (LPARAM) &parts);
6: Send a message via SendMessage(hWndStatusbar, SB_SETTEXT, LOBYTE(0) | SBT_OWNERDRAW, L"Ready"). Sample code for WM_DRAWITEM:
...
WM_DRAWITEM:
LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) lParam;
m_pFramework->m_pD2D1RenderTarget->BindDC(lpDIS->hDC, &lpDIS->rcItem);
m_pFramework->m_pD2D1RenderTarget->BeginDraw();
m_pFramework->m_pD2D1RenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::CadetBlue));
D2D1_RECT_F rf = D2D1::RectF(
PixeltoDipX(lpDIS->rcItem.left),
PixeltoDipY(lpDIS->rcItem.top),
PixeltoDipX(lpDIS->rcItem.right),
PixeltoDipY(lpDIS->rcItem.bottom)
);
m_pFramework->m_pD2D1RenderTarget->DrawText(
(LPCWSTR) lpDIS->itemData,
wcslen((WCHAR*) lpDIS->itemData) + 1,
m_pFramework->m_pTextFormat,
rf,
m_d2dCaptionTextColor
);
m_pFramework->m_pD2D1RenderTarget->EndDraw();
break;
....
This should stop flickering. Also, do not call InvalidateRect(hWndStatus, NULL, TRUE) in the parent's WM_SIZE. This was the main reason it flickered.