Windows MFC: adjust child dialog to a tab control display area - c++

I am creating some dialog-based MFC application (C++) and need to use tab control. Here is the code where I try to adjust child dialog to a tab control display area (Visual Studio 2015):
/* main dialog */
BOOL CResourceBrowserDlg::OnInitDialog()
{
....
/*
* `m_Page` is my child dialog instance:
* CDlgFilterPage::CDialogEx *m_Page
*/
m_Page = new CDlgFilterPage();
m_Page->Create(IDD_FILTERPAGE, m_FilterTab.GetWindow(IDD_FILTERPAGE));
RECT rect;
/*
* `m_FilterTab` is a tab control element:
* CTabCtrl m_FilterTab
*/
m_FilterTab.GetWindowRect(&rect);
m_FilterTab.AdjustRect(FALSE, &rect);
m_Page->MoveWindow(&rect);
m_Page->ShowWindow(SW_SHOW);
m_FilterTab.InsertItem(0, L"Page1");
...
}
Running this i got the following:
So how should I act to get child window fit nicely within tab control?

First of all, you probably want to first add a page and then position the other dialog within the client area of the tab. Otherwise, your tab window will not have the tab buttons and the size of the dialog will be larger than what you expect.
Second, you need to position the new dialog inside the client area. You have to retrieve that and then translate it based on the window area.
Here is how you do all that:
m_Page = new CDlgFilterPage();
m_Page->Create(IDD_FILTERPAGE, m_FilterTab.GetWindow(IDD_FILTERPAGE));
m_FilterTab.InsertItem(0, L"Page1");
CRect rcClient, rcWindow;
m_FilterTab.GetClientRect(&rcClient);
m_FilterTab.AdjustRect(FALSE, &rcClient);
m_FilterTab.GetWindowRect(&rcWindow);
ScreenToClient(rcWindow);
rcClient.OffsetRect(rcWindow.left, rcWindow.top);
m_Page->MoveWindow(&rcClient);
m_Page->ShowWindow(SW_SHOW);
The result is this:

Do not try to get the Window position in OninitDialog() function. It will show 0,0 location instead of actual position of dialog.

Related

C++ how to display text in child window at real time

This application creates a child window (which is the white box) when I right click anywhere, and destroys the child window after another right click. I have implemented the mechanics to expand and shrink the red rectangle through Direct 2D. I would like the child window to display the width and height of the rectangle at real time, as I make changes to it. I do not interact with the child window at all: it doesn't need an "x" button for closing and stuff; it just prints out a couple lines of data.
Here is what I have in my main window procedure:
case WM_RBUTTONUP:
{
DemoApp *pDemoApp = reinterpret_cast<DemoApp *>(static_cast<LONG_PTR>(
::GetWindowLongPtrW(hwnd, GWLP_USERDATA)));
pDemoApp->showTextBox = !pDemoApp->showTextBox; //showTextBox is a boolean
if (pDemoApp->showTextBox) {
POINTS cursor = MAKEPOINTS(lParam);
pDemoApp->child_hwnd = CreateWindowEx(
WS_EX_TOPMOST,
"LISTBOX",
"I dont need a title here",
WS_CHILDWINDOW,
cursor.x,
cursor.y,
100,
200,
pDemoApp->main_hwnd,
NULL,
HINST_THISCOMPONENT,
pDemoApp
);
ShowWindow(pDemoApp->child_hwnd, SW_SHOWNORMAL);
UpdateWindow(pDemoApp->child_hwnd);
}
else {
DestroyWindow(pDemoApp->child_hwnd);
}
}
break;
How may I go from here? I would like to know:
Is using Direct Write to draw text in the child window my only option? I see the dashed lines in the white box so I assume there must be a way to display plain text.
I used LISTBOX here, which is a predefined windows class name. How do I set a procedure for it? What else predefined class name can better suit my need? Or do I have to register a custom one;
I would like to drag the child window around, how can I set it up so that the system handles dragging for me.
Would popping a dialog box to display text be better than popping a child window?
Thanks.
Since you are using a Win32 LISTBOX control as the child window, then you have a couple of options for displaying the rectangle's dimensions in it:
give the ListBox the LBS_HASSTRINGS style, and add 1-2 items to it. Then, any time you change the rectangle, send LB_DELETESTRING and LB_ADDSTRING messages to the ListBox's HWND to display the updated dimensions as needed. A ListBox does not have a way to update an existing item, so to change an existing item's text, you have to remove the item and then re-add it with the new text.
give the ListBox an LBS_OWNERDRAW... style, and add 1-2 blank item(s) in it. Then have the ListBox's parent window handle WM_MEASUREITEM and WM_DRAWITEM notifications from the ListBox to display the rectangle's current dimensions in the item(s) as needed. Whenever the rectangle is changed, call InvalidateRect() on the ListBox's HWND to trigger a redraw.

How to check mouse click position is on required application?

I know the mouse click position using API GetCursorPos and the handle of application (HWND).
How can I check mouse click position is on this application?
My view:
Get the bounding box of application from its handle. (GetWindowRect(hWnd, &rect);)
Check cursor position lies in this bounding box. (PtInRect(&rect, p))
This is not working if windows are overlapping.
As we know the handle of targeted screen handle and click cursor position:
// hWnd : Already known windows handle
GetCursorPos(&p);
HWND hWndFromPoint = WindowFromPoint(p);
// If the handle got from click point is child of the desire window means it is clicked on the desire window itself.
if (IsChild(hWnd, hWndFromPoint))
{
// Do something on Mouse click
}

MFC CStatusBar not Topmost into resizable CDialog

I made an MFC application based on a dialog. Into this, I added a CStatusBar into bottom of the dialog addin this code into CMyDialog::InitDIalog() :
//Create status bar
BOOL bReturn = m_wndStatusBar.Create(this);
m_wndStatusBar.SetIndicators(indicators,1);
// Find the Size of Dialog box
CRect rect;
GetClientRect(&rect);
// Size the two panes
m_wndStatusBar.SetPaneInfo(0,IDD_INDICATOR_STATUS, SBPS_NORMAL, rect.Width());
// This is where we actually draw it
RepositionBars( AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, IDD_INDICATOR_STATUS ) ;
Note in the dialog editor, I had to keep some space at the bottom for the status bar. Work fine so far, status bar is correctly displayed :
BUT problem occurs when I resize the dialog. I put this code into CMyDialog::OnSize() :
RepositionBars( AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, IDD_INDICATOR_STATUS) ;
m_wndStatusBar.SetForegroundWindow();
The position of the CStatusBar window is correctly adapted... but status bar is displayed behind other controls.
Any idea how to solve this ? Why the call to SetForegroungWindow() is not working in this case ?

How to Make CMDIChildWnd as Dockable in MFC?

I want to Make CMDIChildWnd as Dockable.... My Code which Create Window Frame While click on ribbon Button and I want Docking all window in tabbed format, when i place Drag My Frame is show Docking Manager Format[DT_SMART]...
This Code is Button Click event create multiple Frame....
pDocTemplate_New1 = new CMultiDocTemplate ( IDR_RiboonCFormViewTYPE,
RUNTIME_CLASS(CRiboonCFormViewTestDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CDepartement));
AfxGetApp () -> AddDocTemplate (pDocTemplate_New1);
// Create a new child window
CMDIChildWnd * pMDIActive = MDIGetActive (); // get the pointer of the currently active child window
//CDocument * pDoc = (CDocument *) pMDIActive-> GetActiveDocument (); // get the document pointer
CMDIChildWnd * pNewFrame = (CMDIChildWnd *) (pDocTemplate_New1 -> CreateNewFrame (NULL, NULL));
pNewFrame->EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
// Create a new frame window
if (pNewFrame == NULL)
{
AfxMessageBox("new window can not be established ", MB_OK, 0);
}
pDocTemplate_New1 -> InitialUpdateFrame (pNewFrame, NULL); // display window
MDITile (MDITILE_HORIZONTAL); // tile multiple windows
Create a dockable pane first, To create a dockable pane you must first derive from the CMDIFrameWndEx.
Add that pane member in CMainFrame
Styles that matter, CBRS_FLOAT_MULTI make the dockable pane float as a unit when attached to a tab.
An alignment style like CBRS_LEFT gives the pane the initial alignment.
Tabbed pane is a concept of docking panes to each other to form a regular tab control with individual panes inside.
Use AttachToTabWnd() to add your pane

How does one resize the form(dialog) in a MFC SDI CFormView application?

I've tried
MoveWindow(50,50,150,200,TRUE) in CMyFormView::OnInitialUpdate();
Also, I have tried following code in
CWinApp::InitInstance();
RECT desktop;
const HWND hDesktop = ::GetDesktopWindow();
::GetWindowRect(hDesktop,&desktop);
MoveWindow(hDesktop,0,0,900,400,TRUE);
I am having no luck resizing the form(dialog).
I would appreciate any suggestions.
In an SDI program the dialog is sized by the mainframe window to fill the client area. Resize the frame window and the dialog will follow. Put this in the formview's OnInitialUpdate
AfxGetMainWnd()->MoveWindow(....);
KEY THINGS:
MINIMUM SIZE - YOU SET - The dialog template - or form view - you make IS the absolute minimum size CFormview will use
MAXIMUM SIZE - AUTOMATICALLY SIZED - The dialog template has no maximum. CFormview dynamically stretches it out to fit the CMainFrame window.
STARTING THE APPLICATION TO THE TEMPLATE SIZE
Naturally you might want the CMainFrame window to be as compact as possible, this is achieved using 3 mandatory lines of code in your CFormView::OnInitialUpdate()
void CSimpleSDIView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit(); // FORCES CMainframe to be as small as the dialog template
}
FORCE CMainFrame to LIMIT MINIMUM SIZE - If necessary. Using WM_GETMINMAXINFO Here's the code:
void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
lpMMI->ptMinTrackSize.x = 500; // absolute minimum width for CMainFrame
lpMMI->ptMinTrackSize.y = 500; // absolute minimum height for CMainFrame
CFrameWnd::OnGetMinMaxInfo(lpMMI);
}
SET TO IDEAL SIZE This can achieved in CFormView ::OnInitialUpdate by using the following code (Step 3 is still required):
AfxGetMainWnd()->MoveWindow(0, 0, 1024, 600, 1);
TWEAK CONTROL POSITIONS With the advent of the ribbon in MFC things are looking good, but using steps 1 - 5 doesn't work without extra tweaking. Basically, the ribbon sends the main window an extra resize as it would seem, so even if you sent a minimum template size, things get a little out of proportion due to the extra resizing -- mainly because a group within a ribbon can be collapsed into a single icon. ** BEFORE DOING STEP 5** you might want to add the following code:
if(::GetSystemMetrics(SM_CXSCREEN) > 1024)
{
RECT r;
CWnd *someControl = GetDlgItem(IDC_SOMECONTROL);
someControl->GetWindowRect(&r);
ScreenToClient(&r);
r.right += 300;//r.right += 30;
r.bottom += 150;
someControl->MoveWindow(&r)
}
EXPLANATION:
The short answer, you don't! Basically, I had the same issue, made a dialog box template for use in a CFormView derived class. When I wanted to stretch the CMainFrame window out like any normal window, I wanted the content of the formview to resize accordingly. That worked fine with some code, but the problem came when I made the window very small. When I did that, I would get these ugly scrollbars. My thought was the scrollbars were there because they are trying to respect the original dialog template size. That thought is correct! For example, you make your dialog box 500 x 500 and you resize small less than that, you will get scrollbars - since CFormview respects that the application MUST BE AT A MINIMUM 500x500. The minimum size is governed by the template you make and you can not dynamically make it smaller.
Usually, child window's size, position is changed in child's init code.
If you change this in parent window code, you always have to check whether the child window handle value is valid.
I input this code WM_CREATE handler of CAboutDlg.
int CAboutDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialogEx::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
RECT desktop;
const HWND hDesktop = ::GetDesktopWindow();
::GetWindowRect(hDesktop,&desktop);
MoveWindow(&desktop,TRUE);
return 0;
}