当 PC 使用缩放文本时,恢复的对话框正在裁剪控件
Restored dialog is cropping the controls when PC is using scaled text
我有这个基础 class 用于调整对话框大小并记住它们的 window 状态。
BOOL CResizingDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Save Initial window size to m_rcInit
GetWindowRect(&m_rcInit);
//if (!m_bOnlyStorePosition && !m_bDoNotShowResizeIcon)
//InitialiseResizeIcon(m_bmpResize, m_lblResize, this);
RestoreWindowPosition(m_strWindowID, this, true);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CResizingDialog::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
// Set the minimum window size to initial size.
lpMMI->ptMinTrackSize.x = m_rcInit.Width();
lpMMI->ptMinTrackSize.y = m_rcInit.Height();
CDialogEx::OnGetMinMaxInfo(lpMMI);
}
void CResizingDialog::RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState)
{
int max_x, max_y;
RECT rtWindow;
if (pWindow == nullptr)
return;
// Only restore if there is a previously saved position
if ((rtWindow.top = AfxGetApp()->GetProfileInt(strWindow, _T("Top"), -1)) != -1 &&
(rtWindow.left = AfxGetApp()->GetProfileInt(strWindow, _T("Left"), -1)) != -1 &&
(rtWindow.bottom = AfxGetApp()->GetProfileInt(strWindow, _T("Bottom"), -1)) != -1 &&
(rtWindow.right = AfxGetApp()->GetProfileInt(strWindow, _T("Right"), -1)))
{
max_x = rtWindow.right - rtWindow.left;
max_y = rtWindow.bottom - rtWindow.top;
// Get a handle to the monitor
HMONITOR hMonitor = ::MonitorFromPoint(
CPoint(rtWindow.left, rtWindow.top), MONITOR_DEFAULTTONEAREST);
// Get the monitor info
MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
if (::GetMonitorInfo(hMonitor, &monInfo) == 0)
AfxMessageBox(_T("GetMonitorInfo failed"));
else
{
// Adjust for work area
rtWindow.left += monInfo.rcWork.left - monInfo.rcMonitor.left;
rtWindow.top += monInfo.rcWork.top - monInfo.rcMonitor.top;
// Ensure top left point is on screen
if (CRect(monInfo.rcWork).PtInRect(CPoint(rtWindow.left, rtWindow.top)) == FALSE)
{
rtWindow.left = monInfo.rcWork.left;
rtWindow.top = monInfo.rcWork.top;
}
rtWindow.right = rtWindow.left + max_x;
rtWindow.bottom = rtWindow.top + max_y;
// Restore window size
pWindow->MoveWindow(&rtWindow, FALSE);
}
if (bOverrideState)
{
// Let us override by restoring the window state
int iState = AfxGetApp()->GetProfileInt(strWindow, _T("ShowCmd"), SW_SHOWNORMAL);
pWindow->ShowWindow(iState);
}
}
}
有时我所做的只是记住 window 位置。好吧,一位用户向我报告了这个问题:
如您所见,window 已经裁剪了控件。我没有检查用户 PC 但由于某种原因 window(不可调整大小)已裁剪控件。
更新
我已经能够重现这个问题。我在我的 Windows 10 PC 上使用高清(不是超高清)。如果我将操作系统的文本缩放设置为150%,我会看到这个问题。
我的 MFC 项目是使用 DPI Per Monitor 设置编译的,所以应该没问题。它失败并使用对话框的原始大小,而不是对话框的 "scaled" 大小。
我做了更多测试,似乎只有这个 window 不正常。这是对话资源:
IDD_DIALOG_OUR_CHRISTIAN_LIFE_AND_MINISTRY_STUDENTS DIALOGEX 0, 0, 385, 298
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Apply Yourself to the Field Ministry"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Main hall",IDC_STATIC,7,7,257,93
LTEXT "Student:",IDC_STATIC_STUDENT_MH,29,16,29,8
LTEXT "Study #",IDC_STATIC_STUDY_MH,117,16,27,8
LTEXT "Assistant:",IDC_STATIC_ASSIST_MH,154,16,33,8,0,WS_EX_RIGHT
LTEXT "#1",IDC_STATIC,15,29,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_MH_STUDENT,29,26,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN2_MH_STUDENT_STUDY,117,26,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_MH_ASSIST,154,26,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM1_MH,"MfcButton",WS_TABSTOP,242,26,15,15
LTEXT "#2",IDC_STATIC,15,46,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_MH_STUDENT,29,43,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN3_MH_STUDENT_STUDY,117,43,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_MH_ASSIST,154,43,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM2_MH,"MfcButton",WS_TABSTOP,242,43,15,15
LTEXT "#3",IDC_STATIC,15,62,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_MH_STUDENT,29,60,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN4_MH_STUDENT_STUDY,117,60,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_MH_ASSIST,154,60,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM3_MH,"MfcButton",WS_TABSTOP,242,60,15,15
LTEXT "#4",IDC_STATIC,15,80,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_MH_STUDENT,29,78,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN5_MH_STUDENT_STUDY,117,78,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_MH_ASSIST,154,78,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM4_MH,"MfcButton",WS_TABSTOP,241,78,15,15
GROUPBOX "Auxiliary Classroom 1",IDC_STATIC,7,102,257,93
LTEXT "Student:",IDC_STATIC_STUDENT_C1,30,111,29,8
LTEXT "Study #",IDC_STATIC_STUDY_C1,117,111,27,8
LTEXT "Assistant:",IDC_STATIC_ASSIST_C1,154,111,33,8,0,WS_EX_RIGHT
LTEXT "#1",IDC_STATIC,15,124,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C1_STUDENT,29,121,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN2_C1_STUDENT_STUDY,117,121,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C1_ASSIST,154,121,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM1_C1,"MfcButton",WS_TABSTOP,242,121,15,15
LTEXT "#2",IDC_STATIC,15,142,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C1_STUDENT,29,139,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN3_C1_STUDENT_STUDY,117,139,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C1_ASSIST,154,139,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM2_C1,"MfcButton",WS_TABSTOP,242,139,15,15
LTEXT "#3",IDC_STATIC,15,158,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C1_STUDENT,29,157,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN4_C1_STUDENT_STUDY,117,157,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C1_ASSIST,154,157,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM3_C1,"MfcButton",WS_TABSTOP,242,157,15,15
LTEXT "#4",IDC_STATIC,15,176,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C1_STUDENT,29,175,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN5_C1_STUDENT_STUDY,117,175,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C1_ASSIST,154,175,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM4_C1,"MfcButton",WS_TABSTOP,241,175,15,15
GROUPBOX "Auxiliary Classroom 2",IDC_STATIC,7,198,257,93
LTEXT "Student:",IDC_STATIC_STUDENT_C2,30,208,29,8
LTEXT "Study #",IDC_STATIC_STUDY_C2,117,207,27,8
LTEXT "Assistant:",IDC_STATIC_ASSIST_C2,154,208,33,8,0,WS_EX_RIGHT
LTEXT "#1",IDC_STATIC,16,222,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C2_STUDENT,29,219,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN2_C2_STUDENT_STUDY,117,219,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C2_ASSIST,154,219,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM1_C2,"MfcButton",WS_TABSTOP,242,219,15,15
LTEXT "#2",IDC_STATIC,16,239,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C2_STUDENT,29,237,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN3_C2_STUDENT_STUDY,117,237,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C2_ASSIST,154,237,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM2_C2,"MfcButton",WS_TABSTOP,242,237,15,15
LTEXT "#3",IDC_STATIC,16,255,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C2_STUDENT,29,254,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN4_C2_STUDENT_STUDY,117,254,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C2_ASSIST,154,254,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM3_C2,"MfcButton",WS_TABSTOP,242,254,15,15
LTEXT "#4",IDC_STATIC,15,272,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C2_STUDENT,29,272,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN5_C2_STUDENT_STUDY,117,272,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C2_ASSIST,154,272,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM4_C2,"MfcButton",WS_TABSTOP,241,272,15,15
EDITTEXT IDC_EDIT_INFO,270,7,108,243,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL
DEFPUSHBUTTON "OK",IDOK,270,255,108,14
PUSHBUTTON "Cancel",IDCANCEL,270,274,108,14
END
我想知道是不是我在 CResizingDialog
中的代码有问题?但后来我读到了这个answer。这意味着由于我正在为 DPI 感知监视器进行编译,所以 MFC 项目应该开箱即用。那么,为什么我得到的 window 尺寸没有补偿缩放设置?
我可以验证嵌入式清单也有此 DPI 设置(为简洁起见,我删除了一些信息):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</windowsSettings>
</application>
</assembly>
更新
此问题与 RestoreWindowPosition
有关。假设我上次存储的位置是在我使用 100% 字体缩放时。现在我使用 150% 的字体缩放。 window 的注册表中保存的尺寸用于 100% 缩放。因此它被裁剪了。
同样,如果我删除恢复代码,使用 150% 的缩放文本并关闭 window,注册表中的大小现在为 150%。因此,如果我恢复为 100% 缩放,则尺寸是错误的。
我不确定如何进行。我保存 window 位置的代码在这里:
void CResizingDialog::SaveWindowPosition(CString strWindow, CWnd* pWindow)
{
WINDOWPLACEMENT wp;
if (pWindow == nullptr)
return;
pWindow->GetWindowPlacement(&wp);
// Commit to registry
AfxGetApp()->WriteProfileInt(strWindow, _T("Top"), wp.rcNormalPosition.top);
AfxGetApp()->WriteProfileInt(strWindow, _T("Left"), wp.rcNormalPosition.left);
AfxGetApp()->WriteProfileInt(strWindow, _T("Bottom"), wp.rcNormalPosition.bottom);
AfxGetApp()->WriteProfileInt(strWindow, _T("Right"), wp.rcNormalPosition.right);
AfxGetApp()->WriteProfileInt(strWindow, _T("ShowCmd"), wp.showCmd);
}
很明显,它保存的值取决于活动缩放。 #confused - 头痛。
更新
根据评论,我尝试进行一些更改以存储标准化的位置,然后缩放它们。但是不太对。
代码如下:
void CResizingDialog::RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState)
{
int max_x, max_y;
RECT rtWindow;
if (pWindow == nullptr)
return;
// Only restore if there is a previously saved position
if ((rtWindow.top = AfxGetApp()->GetProfileInt(strWindow, _T("TopDPI"), -1)) != -1 &&
(rtWindow.left = AfxGetApp()->GetProfileInt(strWindow, _T("LeftDPI"), -1)) != -1 &&
(rtWindow.bottom = AfxGetApp()->GetProfileInt(strWindow, _T("BottomDPI"), -1)) != -1 &&
(rtWindow.right = AfxGetApp()->GetProfileInt(strWindow, _T("RightDPI"), -1)))
{
CDC* screen = GetDC();
if (screen != nullptr)
{
double dpi = static_cast<double>(screen->GetDeviceCaps(LOGPIXELSX));
// 100% Scaled Text using 96 DPI
double dScaleFactor = dpi / 96.0;
rtWindow.top *= dScaleFactor;
rtWindow.left *= dScaleFactor;
rtWindow.bottom *= dScaleFactor;
rtWindow.right *= dScaleFactor;
ReleaseDC(screen);
}
max_x = rtWindow.right - rtWindow.left;
max_y = rtWindow.bottom - rtWindow.top;
// Get a handle to the monitor
HMONITOR hMonitor = ::MonitorFromPoint(
CPoint(rtWindow.left, rtWindow.top), MONITOR_DEFAULTTONEAREST);
// Get the monitor info
MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
if (::GetMonitorInfo(hMonitor, &monInfo) == 0)
AfxMessageBox(_T("GetMonitorInfo failed"));
else
{
// Adjust for work area
rtWindow.left += monInfo.rcWork.left - monInfo.rcMonitor.left;
rtWindow.top += monInfo.rcWork.top - monInfo.rcMonitor.top;
// Ensure top left point is on screen
if (CRect(monInfo.rcWork).PtInRect(CPoint(rtWindow.left, rtWindow.top)) == FALSE)
{
rtWindow.left = monInfo.rcWork.left;
rtWindow.top = monInfo.rcWork.top;
}
rtWindow.right = rtWindow.left + max_x;
rtWindow.bottom = rtWindow.top + max_y;
// Restore window size
pWindow->MoveWindow(&rtWindow, FALSE);
}
if (bOverrideState)
{
// Let us override by restoring the window state
int iState = AfxGetApp()->GetProfileInt(strWindow, _T("ShowCmd"), SW_SHOWNORMAL);
pWindow->ShowWindow(iState);
}
}
}
void CResizingDialog::SaveWindowPosition(CString strWindow, CWnd* pWindow)
{
WINDOWPLACEMENT wp;
if (pWindow == nullptr)
return;
pWindow->GetWindowPlacement(&wp);
CDC *screen = GetDC();
if (screen != nullptr)
{
double dpi = static_cast<double>(screen->GetDeviceCaps(LOGPIXELSX));
// 100% Scaled Text using 96 DPI
double dScaleFactor = dpi / 96.0;
AfxGetApp()->WriteProfileInt(strWindow, _T("TopDPI"), wp.rcNormalPosition.top / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("LeftDPI"), wp.rcNormalPosition.left / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("BottomDPI"), wp.rcNormalPosition.bottom / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("RightDPI"), wp.rcNormalPosition.right / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("ShowCmd"), wp.showCmd);
ReleaseDC(screen);
}
}
当我的 PC 的 DPI 为 120 时,这是一个对话框:
好消息是我现在可以看到所有控件了。坏消息是它实际上太宽了。我尝试注释掉针对工作区调整它的代码,并确保左上角在屏幕上,但这只减少了一点。
我不明白为什么它现在太宽了?它也比应有的高度略高。
我不知道这是否是最好的方法,但我已经接受了一些评论。这给了我 95% 的解决方案。
void CResizingDialog::RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState)
{
int max_x, max_y;
RECT rtWindow;
if (pWindow == nullptr)
return;
// Only restore if there is a previously saved position
if ((rtWindow.top = AfxGetApp()->GetProfileInt(strWindow, _T("Top"), -1)) != -1 &&
(rtWindow.left = AfxGetApp()->GetProfileInt(strWindow, _T("Left"), -1)) != -1 &&
(rtWindow.bottom = AfxGetApp()->GetProfileInt(strWindow, _T("Bottom"), -1)) != -1 &&
(rtWindow.right = AfxGetApp()->GetProfileInt(strWindow, _T("Right"), -1)))
{
max_x = rtWindow.right - rtWindow.left;
max_y = rtWindow.bottom - rtWindow.top;
// Get a handle to the monitor
HMONITOR hMonitor = ::MonitorFromPoint(
CPoint(rtWindow.left, rtWindow.top), MONITOR_DEFAULTTONEAREST);
// Get the monitor info
MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
if (::GetMonitorInfo(hMonitor, &monInfo) == 0)
AfxMessageBox(_T("GetMonitorInfo failed"));
else
{
// Adjust for work area
rtWindow.left += monInfo.rcWork.left - monInfo.rcMonitor.left;
rtWindow.top += monInfo.rcWork.top - monInfo.rcMonitor.top;
// Ensure top left point is on screen
if (CRect(monInfo.rcWork).PtInRect(CPoint(rtWindow.left, rtWindow.top)) == FALSE)
{
rtWindow.left = monInfo.rcWork.left;
rtWindow.top = monInfo.rcWork.top;
}
if (m_bOnlyStorePosition)
{
// We must override the dimensions of the dialog. This is because the user
// might have text scale in effect.
CRect rtOrg;
GetWindowRect(&rtOrg);
// But we want to show it in the previous place (albeit slightly off position)
pWindow->MoveWindow(rtWindow.left, rtWindow.top, rtOrg.Width(), rtOrg.Height());
}
else
{
rtWindow.right = rtWindow.left + max_x;
rtWindow.bottom = rtWindow.top + max_y;
// Restore window size
pWindow->MoveWindow(&rtWindow, FALSE);
}
}
if (bOverrideState)
{
// Let us override by restoring the window state
int iState = AfxGetApp()->GetProfileInt(strWindow, _T("ShowCmd"), SW_SHOWNORMAL);
pWindow->ShowWindow(iState);
}
}
}
主要问题是当我们恢复具有固定大小的 windows 时(因为可调整大小 windows 可以在用户错误的情况下调整大小)。
所以我添加了一些代码来恢复 X/Y 处的 window,但具有原始宽度和高度。然而,MFC 机制是这样做的,这里的值总是正确的,所以只使用它们是有意义的。
唯一的问题是 x/y 原点没有考虑到文本缩放的变化,但至少他们现在可以移动 window 就没问题了。
如果您能想到我对我的功能所做的代码调整有任何改进,请告诉我。我希望它对处于这种困境的其他人有用。
我有这个基础 class 用于调整对话框大小并记住它们的 window 状态。
BOOL CResizingDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Save Initial window size to m_rcInit
GetWindowRect(&m_rcInit);
//if (!m_bOnlyStorePosition && !m_bDoNotShowResizeIcon)
//InitialiseResizeIcon(m_bmpResize, m_lblResize, this);
RestoreWindowPosition(m_strWindowID, this, true);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CResizingDialog::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
// Set the minimum window size to initial size.
lpMMI->ptMinTrackSize.x = m_rcInit.Width();
lpMMI->ptMinTrackSize.y = m_rcInit.Height();
CDialogEx::OnGetMinMaxInfo(lpMMI);
}
void CResizingDialog::RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState)
{
int max_x, max_y;
RECT rtWindow;
if (pWindow == nullptr)
return;
// Only restore if there is a previously saved position
if ((rtWindow.top = AfxGetApp()->GetProfileInt(strWindow, _T("Top"), -1)) != -1 &&
(rtWindow.left = AfxGetApp()->GetProfileInt(strWindow, _T("Left"), -1)) != -1 &&
(rtWindow.bottom = AfxGetApp()->GetProfileInt(strWindow, _T("Bottom"), -1)) != -1 &&
(rtWindow.right = AfxGetApp()->GetProfileInt(strWindow, _T("Right"), -1)))
{
max_x = rtWindow.right - rtWindow.left;
max_y = rtWindow.bottom - rtWindow.top;
// Get a handle to the monitor
HMONITOR hMonitor = ::MonitorFromPoint(
CPoint(rtWindow.left, rtWindow.top), MONITOR_DEFAULTTONEAREST);
// Get the monitor info
MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
if (::GetMonitorInfo(hMonitor, &monInfo) == 0)
AfxMessageBox(_T("GetMonitorInfo failed"));
else
{
// Adjust for work area
rtWindow.left += monInfo.rcWork.left - monInfo.rcMonitor.left;
rtWindow.top += monInfo.rcWork.top - monInfo.rcMonitor.top;
// Ensure top left point is on screen
if (CRect(monInfo.rcWork).PtInRect(CPoint(rtWindow.left, rtWindow.top)) == FALSE)
{
rtWindow.left = monInfo.rcWork.left;
rtWindow.top = monInfo.rcWork.top;
}
rtWindow.right = rtWindow.left + max_x;
rtWindow.bottom = rtWindow.top + max_y;
// Restore window size
pWindow->MoveWindow(&rtWindow, FALSE);
}
if (bOverrideState)
{
// Let us override by restoring the window state
int iState = AfxGetApp()->GetProfileInt(strWindow, _T("ShowCmd"), SW_SHOWNORMAL);
pWindow->ShowWindow(iState);
}
}
}
有时我所做的只是记住 window 位置。好吧,一位用户向我报告了这个问题:
如您所见,window 已经裁剪了控件。我没有检查用户 PC 但由于某种原因 window(不可调整大小)已裁剪控件。
更新
我已经能够重现这个问题。我在我的 Windows 10 PC 上使用高清(不是超高清)。如果我将操作系统的文本缩放设置为150%,我会看到这个问题。
我的 MFC 项目是使用 DPI Per Monitor 设置编译的,所以应该没问题。它失败并使用对话框的原始大小,而不是对话框的 "scaled" 大小。
我做了更多测试,似乎只有这个 window 不正常。这是对话资源:
IDD_DIALOG_OUR_CHRISTIAN_LIFE_AND_MINISTRY_STUDENTS DIALOGEX 0, 0, 385, 298
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Apply Yourself to the Field Ministry"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Main hall",IDC_STATIC,7,7,257,93
LTEXT "Student:",IDC_STATIC_STUDENT_MH,29,16,29,8
LTEXT "Study #",IDC_STATIC_STUDY_MH,117,16,27,8
LTEXT "Assistant:",IDC_STATIC_ASSIST_MH,154,16,33,8,0,WS_EX_RIGHT
LTEXT "#1",IDC_STATIC,15,29,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_MH_STUDENT,29,26,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN2_MH_STUDENT_STUDY,117,26,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_MH_ASSIST,154,26,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM1_MH,"MfcButton",WS_TABSTOP,242,26,15,15
LTEXT "#2",IDC_STATIC,15,46,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_MH_STUDENT,29,43,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN3_MH_STUDENT_STUDY,117,43,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_MH_ASSIST,154,43,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM2_MH,"MfcButton",WS_TABSTOP,242,43,15,15
LTEXT "#3",IDC_STATIC,15,62,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_MH_STUDENT,29,60,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN4_MH_STUDENT_STUDY,117,60,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_MH_ASSIST,154,60,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM3_MH,"MfcButton",WS_TABSTOP,242,60,15,15
LTEXT "#4",IDC_STATIC,15,80,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_MH_STUDENT,29,78,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN5_MH_STUDENT_STUDY,117,78,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_MH_ASSIST,154,78,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM4_MH,"MfcButton",WS_TABSTOP,241,78,15,15
GROUPBOX "Auxiliary Classroom 1",IDC_STATIC,7,102,257,93
LTEXT "Student:",IDC_STATIC_STUDENT_C1,30,111,29,8
LTEXT "Study #",IDC_STATIC_STUDY_C1,117,111,27,8
LTEXT "Assistant:",IDC_STATIC_ASSIST_C1,154,111,33,8,0,WS_EX_RIGHT
LTEXT "#1",IDC_STATIC,15,124,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C1_STUDENT,29,121,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN2_C1_STUDENT_STUDY,117,121,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C1_ASSIST,154,121,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM1_C1,"MfcButton",WS_TABSTOP,242,121,15,15
LTEXT "#2",IDC_STATIC,15,142,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C1_STUDENT,29,139,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN3_C1_STUDENT_STUDY,117,139,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C1_ASSIST,154,139,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM2_C1,"MfcButton",WS_TABSTOP,242,139,15,15
LTEXT "#3",IDC_STATIC,15,158,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C1_STUDENT,29,157,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN4_C1_STUDENT_STUDY,117,157,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C1_ASSIST,154,157,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM3_C1,"MfcButton",WS_TABSTOP,242,157,15,15
LTEXT "#4",IDC_STATIC,15,176,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C1_STUDENT,29,175,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN5_C1_STUDENT_STUDY,117,175,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C1_ASSIST,154,175,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM4_C1,"MfcButton",WS_TABSTOP,241,175,15,15
GROUPBOX "Auxiliary Classroom 2",IDC_STATIC,7,198,257,93
LTEXT "Student:",IDC_STATIC_STUDENT_C2,30,208,29,8
LTEXT "Study #",IDC_STATIC_STUDY_C2,117,207,27,8
LTEXT "Assistant:",IDC_STATIC_ASSIST_C2,154,208,33,8,0,WS_EX_RIGHT
LTEXT "#1",IDC_STATIC,16,222,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C2_STUDENT,29,219,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN2_C2_STUDENT_STUDY,117,219,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C2_ASSIST,154,219,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM1_C2,"MfcButton",WS_TABSTOP,242,219,15,15
LTEXT "#2",IDC_STATIC,16,239,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C2_STUDENT,29,237,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN3_C2_STUDENT_STUDY,117,237,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C2_ASSIST,154,237,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM2_C2,"MfcButton",WS_TABSTOP,242,237,15,15
LTEXT "#3",IDC_STATIC,16,255,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C2_STUDENT,29,254,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN4_C2_STUDENT_STUDY,117,254,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C2_ASSIST,154,254,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM3_C2,"MfcButton",WS_TABSTOP,242,254,15,15
LTEXT "#4",IDC_STATIC,15,272,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C2_STUDENT,29,272,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN5_C2_STUDENT_STUDY,117,272,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C2_ASSIST,154,272,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM4_C2,"MfcButton",WS_TABSTOP,241,272,15,15
EDITTEXT IDC_EDIT_INFO,270,7,108,243,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL
DEFPUSHBUTTON "OK",IDOK,270,255,108,14
PUSHBUTTON "Cancel",IDCANCEL,270,274,108,14
END
我想知道是不是我在 CResizingDialog
中的代码有问题?但后来我读到了这个answer。这意味着由于我正在为 DPI 感知监视器进行编译,所以 MFC 项目应该开箱即用。那么,为什么我得到的 window 尺寸没有补偿缩放设置?
我可以验证嵌入式清单也有此 DPI 设置(为简洁起见,我删除了一些信息):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</windowsSettings>
</application>
</assembly>
更新
此问题与 RestoreWindowPosition
有关。假设我上次存储的位置是在我使用 100% 字体缩放时。现在我使用 150% 的字体缩放。 window 的注册表中保存的尺寸用于 100% 缩放。因此它被裁剪了。
同样,如果我删除恢复代码,使用 150% 的缩放文本并关闭 window,注册表中的大小现在为 150%。因此,如果我恢复为 100% 缩放,则尺寸是错误的。
我不确定如何进行。我保存 window 位置的代码在这里:
void CResizingDialog::SaveWindowPosition(CString strWindow, CWnd* pWindow)
{
WINDOWPLACEMENT wp;
if (pWindow == nullptr)
return;
pWindow->GetWindowPlacement(&wp);
// Commit to registry
AfxGetApp()->WriteProfileInt(strWindow, _T("Top"), wp.rcNormalPosition.top);
AfxGetApp()->WriteProfileInt(strWindow, _T("Left"), wp.rcNormalPosition.left);
AfxGetApp()->WriteProfileInt(strWindow, _T("Bottom"), wp.rcNormalPosition.bottom);
AfxGetApp()->WriteProfileInt(strWindow, _T("Right"), wp.rcNormalPosition.right);
AfxGetApp()->WriteProfileInt(strWindow, _T("ShowCmd"), wp.showCmd);
}
很明显,它保存的值取决于活动缩放。 #confused - 头痛。
更新
根据评论,我尝试进行一些更改以存储标准化的位置,然后缩放它们。但是不太对。
代码如下:
void CResizingDialog::RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState)
{
int max_x, max_y;
RECT rtWindow;
if (pWindow == nullptr)
return;
// Only restore if there is a previously saved position
if ((rtWindow.top = AfxGetApp()->GetProfileInt(strWindow, _T("TopDPI"), -1)) != -1 &&
(rtWindow.left = AfxGetApp()->GetProfileInt(strWindow, _T("LeftDPI"), -1)) != -1 &&
(rtWindow.bottom = AfxGetApp()->GetProfileInt(strWindow, _T("BottomDPI"), -1)) != -1 &&
(rtWindow.right = AfxGetApp()->GetProfileInt(strWindow, _T("RightDPI"), -1)))
{
CDC* screen = GetDC();
if (screen != nullptr)
{
double dpi = static_cast<double>(screen->GetDeviceCaps(LOGPIXELSX));
// 100% Scaled Text using 96 DPI
double dScaleFactor = dpi / 96.0;
rtWindow.top *= dScaleFactor;
rtWindow.left *= dScaleFactor;
rtWindow.bottom *= dScaleFactor;
rtWindow.right *= dScaleFactor;
ReleaseDC(screen);
}
max_x = rtWindow.right - rtWindow.left;
max_y = rtWindow.bottom - rtWindow.top;
// Get a handle to the monitor
HMONITOR hMonitor = ::MonitorFromPoint(
CPoint(rtWindow.left, rtWindow.top), MONITOR_DEFAULTTONEAREST);
// Get the monitor info
MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
if (::GetMonitorInfo(hMonitor, &monInfo) == 0)
AfxMessageBox(_T("GetMonitorInfo failed"));
else
{
// Adjust for work area
rtWindow.left += monInfo.rcWork.left - monInfo.rcMonitor.left;
rtWindow.top += monInfo.rcWork.top - monInfo.rcMonitor.top;
// Ensure top left point is on screen
if (CRect(monInfo.rcWork).PtInRect(CPoint(rtWindow.left, rtWindow.top)) == FALSE)
{
rtWindow.left = monInfo.rcWork.left;
rtWindow.top = monInfo.rcWork.top;
}
rtWindow.right = rtWindow.left + max_x;
rtWindow.bottom = rtWindow.top + max_y;
// Restore window size
pWindow->MoveWindow(&rtWindow, FALSE);
}
if (bOverrideState)
{
// Let us override by restoring the window state
int iState = AfxGetApp()->GetProfileInt(strWindow, _T("ShowCmd"), SW_SHOWNORMAL);
pWindow->ShowWindow(iState);
}
}
}
void CResizingDialog::SaveWindowPosition(CString strWindow, CWnd* pWindow)
{
WINDOWPLACEMENT wp;
if (pWindow == nullptr)
return;
pWindow->GetWindowPlacement(&wp);
CDC *screen = GetDC();
if (screen != nullptr)
{
double dpi = static_cast<double>(screen->GetDeviceCaps(LOGPIXELSX));
// 100% Scaled Text using 96 DPI
double dScaleFactor = dpi / 96.0;
AfxGetApp()->WriteProfileInt(strWindow, _T("TopDPI"), wp.rcNormalPosition.top / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("LeftDPI"), wp.rcNormalPosition.left / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("BottomDPI"), wp.rcNormalPosition.bottom / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("RightDPI"), wp.rcNormalPosition.right / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("ShowCmd"), wp.showCmd);
ReleaseDC(screen);
}
}
当我的 PC 的 DPI 为 120 时,这是一个对话框:
好消息是我现在可以看到所有控件了。坏消息是它实际上太宽了。我尝试注释掉针对工作区调整它的代码,并确保左上角在屏幕上,但这只减少了一点。
我不明白为什么它现在太宽了?它也比应有的高度略高。
我不知道这是否是最好的方法,但我已经接受了一些评论。这给了我 95% 的解决方案。
void CResizingDialog::RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState)
{
int max_x, max_y;
RECT rtWindow;
if (pWindow == nullptr)
return;
// Only restore if there is a previously saved position
if ((rtWindow.top = AfxGetApp()->GetProfileInt(strWindow, _T("Top"), -1)) != -1 &&
(rtWindow.left = AfxGetApp()->GetProfileInt(strWindow, _T("Left"), -1)) != -1 &&
(rtWindow.bottom = AfxGetApp()->GetProfileInt(strWindow, _T("Bottom"), -1)) != -1 &&
(rtWindow.right = AfxGetApp()->GetProfileInt(strWindow, _T("Right"), -1)))
{
max_x = rtWindow.right - rtWindow.left;
max_y = rtWindow.bottom - rtWindow.top;
// Get a handle to the monitor
HMONITOR hMonitor = ::MonitorFromPoint(
CPoint(rtWindow.left, rtWindow.top), MONITOR_DEFAULTTONEAREST);
// Get the monitor info
MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
if (::GetMonitorInfo(hMonitor, &monInfo) == 0)
AfxMessageBox(_T("GetMonitorInfo failed"));
else
{
// Adjust for work area
rtWindow.left += monInfo.rcWork.left - monInfo.rcMonitor.left;
rtWindow.top += monInfo.rcWork.top - monInfo.rcMonitor.top;
// Ensure top left point is on screen
if (CRect(monInfo.rcWork).PtInRect(CPoint(rtWindow.left, rtWindow.top)) == FALSE)
{
rtWindow.left = monInfo.rcWork.left;
rtWindow.top = monInfo.rcWork.top;
}
if (m_bOnlyStorePosition)
{
// We must override the dimensions of the dialog. This is because the user
// might have text scale in effect.
CRect rtOrg;
GetWindowRect(&rtOrg);
// But we want to show it in the previous place (albeit slightly off position)
pWindow->MoveWindow(rtWindow.left, rtWindow.top, rtOrg.Width(), rtOrg.Height());
}
else
{
rtWindow.right = rtWindow.left + max_x;
rtWindow.bottom = rtWindow.top + max_y;
// Restore window size
pWindow->MoveWindow(&rtWindow, FALSE);
}
}
if (bOverrideState)
{
// Let us override by restoring the window state
int iState = AfxGetApp()->GetProfileInt(strWindow, _T("ShowCmd"), SW_SHOWNORMAL);
pWindow->ShowWindow(iState);
}
}
}
主要问题是当我们恢复具有固定大小的 windows 时(因为可调整大小 windows 可以在用户错误的情况下调整大小)。
所以我添加了一些代码来恢复 X/Y 处的 window,但具有原始宽度和高度。然而,MFC 机制是这样做的,这里的值总是正确的,所以只使用它们是有意义的。
唯一的问题是 x/y 原点没有考虑到文本缩放的变化,但至少他们现在可以移动 window 就没问题了。
如果您能想到我对我的功能所做的代码调整有任何改进,请告诉我。我希望它对处于这种困境的其他人有用。