Search code examples
c++mfc

Child dialog dislocated with regards to the parent when switching monitors


I have an options dialog in my MFC application which I have created like this. There is a parent dialog with a treeview on the left and depending on the selected element, a different child window is shown on the right. All of them are designed in the VS 2022 designer.

The generated parent code:

IDD_GLOBAL_OPTIONS DIALOGEX 0, 0, 413, 337
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_CONTROLPARENT | WS_EX_APPWINDOW
CAPTION "Global Options"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,291,315,50,14
    PUSHBUTTON      "Cancel",IDCANCEL,348,315,50,14
    EDITTEXT        IDC_EDIT_GLOBAL_OPTIONS_NAME,123,14,275,12,ES_UPPERCASE | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_CLIENTEDGE
    CONTROL         "",IDC_GLOBAL_OPTIONS_TREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_NOHSCROLL | WS_BORDER | WS_TABSTOP,7,15,108,294
END

The generated child code:

IDD_GLOBAL_OPTIONS_CONFIGPATHS DIALOGEX 0, 0, 297, 291
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 400, 0, 0x0
BEGIN
    GROUPBOX        "Configuration directory",IDC_STATIC,10,15,279,52
    LTEXT           "Configuration data store location",IDC_STATIC,22,31,106,8
    CONTROL         "",IDC_MFCEDITBROWSE1,"MfcEditBrowse",WS_BORDER | WS_TABSTOP | 0x80,22,42,260,14
    GROUPBOX        "Personal data directory",IDC_STATIC,10,74,279,77
    LTEXT           "Personal data such as usernames, passwords and automated login information can be stored separately from all other configuration data",IDC_STATIC,22,89,260,23
    CONTROL         "Store personal data separately",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,116,115,10
    CONTROL         "",IDC_MFCEDITBROWSE2,"MfcEditBrowse",WS_BORDER | WS_TABSTOP | 0x80,32,128,250,14
END

Then, on OnInitDialog() for each child, I position the child window using MoveWindow()

BOOL CGlobalOptionsConfigPaths::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    //CWnd *pWnd = CGlobalOptionsConfigPaths::GetParent();

    CGlobalOptionsConfigPaths::MoveWindow(173, 30, 450, 480, true);
...

Everything looks fine when I run the application on my external monitor, but when I switch to the laptop screen, it falls apart.

External monitor screenshot

Laptop screen screenshot

I have put some code to get the RECTs for both the parent dialog and the child one, believing that somehow I would see some discrepancy between laptop and external monitor. Unfortunately(!?) this is not the case, so I am at the end of my wit.

On both cases the child follows the MoveWindow(173, 30, 450, 480, true) as it of course should. Parent RECT on external monitor: {LT(305, 170) RB(941, 757) [636 x 587]} Child RECT on external monitor: {LT(478, 200) RB(928, 680) [450 x 480]} Parent RECT on laptop: {LT(306, 177) RB(1047, 898) [741 x 721]} Child RECT on laptop: {LT(479, 207) RB(929, 687) [450 x 480]}

On both cases child_left/top = parent_left/top + MoveWindow arguments. So why I am getting this?


Solution

  • So, as it happens the solution from @user20716902 didn't work for me. It just shifted the window to the right side xD

    However, the comment from @markransom gave me a nice tip.

    So here's what worked for me:

    In parent class in ::OnInitDialog()

    RECT rcPos;
    position1.GetWindowRect(&rcPos);
    ScreenToClient(&rcPos);
    
    POINT childLocation = { 0 };
    childLocation.x = rcPos.left;
    childLocation.y = rcPos.top;
    

    The position1 is just a static text on the top left of the parent window, which I am going to hide. Position marker

    Then for every child class:

    ->SetLocationInMotherForm(childLocation);
    

    Each child class extends CDialogEx

    void CDialogExtended::SetLocationInMotherForm(POINT p)
    {
        locationInMotherForm.x = p.x;
        locationInMotherForm.y = p.y;
    }
    

    And finally on each child in ::OnInitDialog()

    CGlobalOptionsConfigPaths::SetWindowPos(NULL, locationInMotherForm.x, locationInMotherForm.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);