MFC: Changing from CDialog to CWnd now the CStatusBar doesn't show? - winapi

To work around a problem with a CDialog being minimized when main window was minimized I decided to try using a CWnd instead. That works but now the CStatusBar doesn't show? What might I be missing or is there some requirement for it to show?
The new CWnd is created like this:
CString classname=AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, 0, 0, LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE (IDR_MAINFRAME)));
m_pDlgNowACWnd->CreateEx(0, classname, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CRect(0, 0, 0, 0), NULL, 0)
The initialization in OnInitDialog() now being OnCreate() does the nroaml m_StatusBar.Create(this) then initializes it further with:
EnableDynamicLayout(FALSE);
// set our own height so we can scale
CStatusBarCtrl &statusctrl=m_StatusBar.GetStatusBarCtrl();
statusctrl.SetMinHeight(g_DPIHelper.Scale(20));
m_StatusBar.SetIndicators(indicators, _countof(indicators));
m_StatusBar.SetPaneInfo (0, ID_SEPARATOR, SBPS_NORMAL|SBPS_STRETCH, 0);
m_StatusBar.SetPaneInfo (sliderPane, ID_SEPARATOR, SBPS_NORMAL, g_DPIHelper.Scale(128));
m_StatusBar.SetPaneInfo (textPane, ID_SEPARATOR, SBPS_NORMAL|SBPS_POPOUT, g_DPIHelper.Scale(30));
// add this to workaround the GetSystemMatrix() issue above.
m_StatusBar.SetPaneInfo (STATUSBARspacerPane, ID_SEPARATOR, SBPS_NORMAL, 25);
// this is needed to calc location and size of bar
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, IDC_VIEW_ACHILDCWND);
EnableDynamicLayout();
auto pdlmanager=GetDynamicLayout();
if (pdlmanager) {
if (pdlmanager->Create(this)) {
pdlmanager->AddItem(m_CWndView.GetSafeHwnd(), CMFCDynamicLayout::MoveNone(), CMFCDynamicLayout::SizeHorizontalAndVertical(100, 100));
pdlmanager->AddItem(m_StatusBar.GetSafeHwnd(), CMFCDynamicLayout::MoveVertical(100), CMFCDynamicLayout::SizeHorizontal(100));
}
}
It's a status bar with a slider on it and some text.
The main CDialog now CWnd has two children a CWnd and a CStatusBar. The initial size of the dialog/window is 0, but then is resized to correct size when the dialog/window will be shown.
Any idea what I may be missing or doing wrong on converting from CDialog to a CWnd ?
Everything else works, just the CStatusBar not showing?
Thanks.
Update:
It appears to be the CStatusBar height being zero. I did a test of creating the CWnd being CRect(0, 0, 10, 50) instead of all zeros and the CStatusBar shows (although with a height of 11 which is much shorter than it should be). It seems the statusctrl.SetMinHeight(g_DPIHelper.Scale(20)) call doesn't work when using CWnd? The resizing takes place in RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, IDC_VIEW_ACHILDCWND); I set a breakpoint on CStatusBar::OnSize() and noticed when a CDialog it had the correct size but not with CWnd(had zero originally now 11 with using a height of 50 on the CWnd Create()).

Since the height of the CStatusBar won't change once created and calculated during OnCreate() the size of the created CWnd needs to be tall enough for the desired CStatusBar minimum height. So instead of this:
m_pDlgNowACWnd->CreateEx(0, classname, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CRect(0, 0, 0, 0), NULL, 0);
Do this:
CRect rccreate(0, 0, 0, MYDLG_STATUSBAR_MINHEIGHT);
CalcWindowRect(&rccreate);
m_pDlgNowACWnd->CreateEx(0, classname, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, rccreate, NULL, 0);

Related

Resizing an edit window

I have a simple edit window:
hwndEdit = CreateWindow(
TEXT("EDIT"),
TEXT("EDIT"),
WS_BORDER | WS_CHILD | ES_LEFT,
100,
100,
100,
30,
gHwnd,
0,
hInst,
0);
I have noticed that when I paste there a text which is longer than an edit window width I get notification (EN_CHANGE) which contains only a portion of the text which fits a window width. I would like to resize an edit window (SetWindowPos) when a text is longer than the edit window width. I can create an edit window based on MSFTEDIT_CLASS and use EN_REQUESTRESIZE. Do you know any other solution or that is the only option ?
The text is truncated by your edit control on paste.
To allow more text in that control without changing the size (which is not practical for many reasons), simply add ES_AUTOHSCROLL style to your CreateWindow call.

TrackPopupMenuEx not seeing keys inside CWinThread

I'm using TrackPopupMenuEx inside a UI CWinThread,
CMonitor is derived from CWinThread
monitor_ = (CMonitor *)AfxBeginThread(RUNTIME_CLASS(CMonitor));
CMonitor::InitInstance containes
m_pMainWnd = new CWnd();
m_pMainWnd->CreateEx(WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | WS_EX_WINDOWEDGE | WS_EX_TOPMOST, AfxRegisterWndClass(CS_DBLCLKS),
NULL, WS_POPUP | WS_CLIPSIBLINGS | WS_VISIBLE, 50, 50, 50, 50, NULL, NULL);
Then later I do
SetForegroundWindow(AfxGetMainWnd()->m_hWnd);
auto popup_menu_flags = TPM_RETURNCMD | TPM_BOTTOMALIGN | TPM_RIGHTBUTTON | TPM_VERTICAL;
auto menu_item = TrackPopupMenuEx(menu, popup_menu_flags, point.x, point.y, AfxGetMainWnd()->m_hWnd, NULL);
DestroyMenu(menu);
The PopupMenu display correctly and I can use the mouse to select a menu item. However the arrow keys do not work.
I have used Spy++ and m_pMainWnd get messages for WM_KEYUP, VK_DOWN but nothing happens. WM_KEYDOWN is not seen.
What am I missing?

How to change height of Owner-draw Listbox items whiling resizing Window?

I have Listbox with LBS_OWNERDRAWVARIABLE style, and trying resize items height with WM_MEASUREITEM on WM_SIZE.
I wrote code next in WM_SIZE procedure, referred http://www.codeproject.com/Articles/1401/Changing-Row-Height-in-an-owner-drawn-Control :
WINDOWPOS wp;
ZeroMemory (&wp, sizeof(WINDOWPOS));
wp.hwnd = hwndListbox;
wp.cx = iWidht;
wp.cy = iHeight;
wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
// WM_WINDOWPOSCHANGED for force generate WM_MEASUREITEM:
SendMessage (hwndListbox, WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
however, It dosen't work... (dosen't generate WM_MESUREITEM.)
Question: How to force generate WM_MESUREITEM, or Resizing of items height dynamically?
p.s I using C++ with Win32, not MFC.
Use the LB_SETITEMHEIGHT message to change the height of listbox items.

How can I update a progress bar?

How can I update this progress bar in win32api? You can find the full code here Code is here
hProgress=CreateWindowEx(0, PROGRESS_CLASS, NULL,
WS_CHILD | WS_VISIBLE,
20, 20, 260, 17,
hwnd, NULL, g_hInst, NULL);
The message you are looking for is PBM_SETPOS. The usage of this depends on what the range is currently set to (defaults from 0-100). For example, assuming the default range, setting the position to halfway would be done as so:
SendMessage(hProgress, PBM_SETPOS, 50, 0);
Alternatively, the progress bar can be incremented in steps through PBM_STEPIT. The usage of this depends on what the step increment is (default to 10). For example, assuming the default range and initial position of the progress bar, stepping the position to 10 would be done as so:
SendMessage(hProgress, PBM_STEPIT, 0, 0);
Assuming you have initialised common controls :
INITCOMMONCONTROLSEX InitCtrlEx;
InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCtrlEx.dwICC = ICC_PROGRESS_CLASS;
InitCommonControlsEx(&InitCtrlEx);
Set the range:
SendMessage(hProgress, PBM_SETRANGE, 0, MAKELPARAM(min, max));
Set the position:
SendMessage(hProgress,PBM_SETPOS,pos,0);
See: MSDN docs
You could use the PMB_STEPIT message to move the current position based on the step size:
int max_range = 1000;
// set range of progress bar
SendMessage(hProgress, PBM_SETRANGE, 0, MAKELPARAM(0, max_range));
// set the step size
SendMessage(hProgress, PBM_SETSTEP, (WPARAM) 1, 0);
// increment by step size
SendMessage(hProgress, PBM_STEPIT, 0, 0);
Here is a good example How to Use Progress Bar Controls
In addition to updating the progress in the progress bar, you must also give it a chance to repaint. Usually you're showing a progress bar because you're busy working, and so the normal message loop isn't running and no WM_PAINT messages are generated. You can call UpdateWindow to repaint the window immediately.

How to add a custom button to windows' minimize/maximize/close (x)

I was wondering if there is a way to add (programatically, of course) an icon/button/whatever besides plain text to a window (Microsoft Windows window...)'s title bar or next to where the minimize/maximize/close buttons are. I could draw it myself and create an illusion it is a part of the window, but I wonder if in the user32 api there is such a method.
So far, I found a way to disable the minimize/maximize/close buttons but not a way to add a custom one to them. It seems strange to me.
Here is what I am trying to achieve:
I have been wondering how it is done here, since drawing a button for every window using gdi/gdi+ and then detecting if it is overlapped by another window and then displaying only the non-overlapped part seems to me like an unlikely solution. Probably the button has been registered in the window class so that every window has this button. Any pointers what to do?
In addition, how do I create a button at all, assuming I DON'T have Unicode enabled. Then in the following piece of code:
HWND hwndCommandLink = CreateWindow(
L"BUTTON", // Class; Unicode assumed.
L"", // Text will be defined later.
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_COMMANDLINK, // Styles.
10, // x position.
10, // y position.
100, // Button width.
100, // Button height.
hDlg, // Parent window.
NULL, // No menu.
(HINSTANCE)GetWindowLong(hDlg, GWL_HINSTANCE),
NULL); // Pointer not needed.
SendMessage(clHwnd, WM_SETTEXT, 0, (LPARAM)L"Command link");
SendMessage(clHwnd, BCM_SETNOTE, 0, (LPARAM)L"with note");
I have to substitute all the nice Windows constants with their long equivalent....However, when I search for them, all i get is this:
http://msdn.microsoft.com/en-us/library/bb775951(v=VS.85).aspx
Any pointers?

Resources