Alan Baljeu
Alan Baljeu

Reputation: 2443

SetWindowPos with scaled-up dialog on Laptop

Below is a very old function that has worked on numerous computers, never seen a bug, but now this laptop is experiencing problems. According to the tester, "Seems to be fine until I reboot and don’t have another monitor plugged in." It seems Windows 10 scales dialog content in some situations making the actual size differ from the designed size.

void ResizeComponent::SetWidth( int width /*= DEF_WIDTH*/ )
{
  CRect rect;
  this->GetWindowRect(rect);
  this->SetWindowPos(NULL, 0,0, width, rect.Height(), /*resize only*/SWP_NOZORDER|SWP_NOMOVE);   
}

Okay, usage info:

const static int WIDTH_PANEL4 = 585;
SetWidth(WIDTH_PANEL4);

According to a screenshot from that laptop, in one example the window is 581 wide, and when I run it on a development computer, it's also 581 wide. BUT: The laptop dialog is scaled larger, and so 581 is no longer the correct size.

I don't know how to deal correctly with this situation.

Upvotes: 0

Views: 1022

Answers (2)

Adrian McCarthy
Adrian McCarthy

Reputation: 48019

There are several possibilities:

  1. The dialog is specified in "dialog units" for a font that's different than the font the code is actually using.

  2. The border style changes between Windows versions weren't accounted for in the design of the dialog, and thus you're losing a few pixels.

  3. The screen is high-DPI and the program isn't properly accounting for high-DPI, or it is but it hasn't told the OS that it knows how to (via manifest or SetProcessDPIAware or SetProcessDPIAwareness).

There isn't enough information in the question to know for sure the exact problem. I suspect #3, based on the fact that the behavior changes depending upon whether an external monitor is connected and on the fact that Windows 10 introduced more nuanced concepts of DPI awareness, like PROCESS_PER_MONITOR_DPI_AWARE.

Upvotes: 1

franji1
franji1

Reputation: 3156

Because dialogs are laid out in "dialog units", I do not use hard pixel counts in my source. I base my dynamic size/position calculations based on the rendered size of the dialog and/or its controls. If your customer changes the system text size (Control Panel/Display Settings of 100% 125% 150% etc.), then you will definitely see issues if you code "hard 100% rendering" pixel values.

I am guessing that your laptop may be doing this type of "translation" when rendering with monitors that do not match the "native resolution" of the built-in laptop monitor.

Here is an example where I reposition OK/Cancel buttons based on the rendered positions (i.e. after chainback call to CDialog::OnInitDialog)

BOOL CSetupDlg::OnInitDialog()
{
CDialog::OnInitDialog();

if (m_bShowCancel)
    {
    // show/enable Cancel button and re-position the OK/CANCEL buttons (default is OK button is centered and cancel is hidden/disabled)
    CWnd *pWndOK = GetDlgItem(IDOK);
    CWnd *pWndCancel = GetDlgItem(IDCANCEL);
    if (pWndOK->GetSafeHwnd() && pWndCancel->GetSafeHwnd())
        {
        CRect rOKOriginal;
        pWndOK->GetWindowRect(&rOKOriginal);
        this->ScreenToClient(rOKOriginal);

        // move Cancel button to the immediate right of the centered OK button
        pWndCancel->SetWindowPos(NULL, rOKOriginal.right, rOKOriginal.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
        pWndCancel->EnableWindow(true);
        // pWndCancel->ShowWindow(SW_SHOW);

        // move OK button to the immediate left of its original/centered position
        pWndOK->SetWindowPos(NULL, rOKOriginal.left - rOKOriginal.Width(), rOKOriginal.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
        }
    }

return TRUE;  // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}

Upvotes: 1

Related Questions