1

我正在使用 Visual Studio 2010 创建本机/win32/MFC C++ 应用程序。我有一个对话框,我希望用户能够在其中输入日期。为此,我使用了 CDateTimeCtrl,它只是 Win32 常用控件的包装。

这很好,因为用户可以单击箭头并下拉一个月视图,让他们以交互方式选择日期。

我遇到的问题是您无法控制月视图中使用的字体大小。它忽略了 WM_SETFONT,尽管控制文档提到了会告诉它使用自定义字体的调用(请参阅 CDateTimeCtrl::SetMonthCalFont()),但这些都被忽略了。

我最终通过 MS 技术支持事件发现它在 v5 的通用控件中工作,但在 v6 中,他们将其更改为忽略这一点,只使用 Windows 中设置的当前视觉样式信息。根据 MS 没有办法使用自定义字体,v6 中的控件将仅使用当前的 Windows 视觉样式。唯一的方法是强制使用 v5 控件,从而将应用程序中的所有 UI 都放回 v5 控件,或者乱用自定义激活上下文(听起来很乱)。

所以,我正在寻找替代控制。谁能推荐一个提供类似功能的本机/C++/MFC 控件,但它可以让我自定义整体字体大小?我在对话框和所有其他控件中使用了比正常字体更大的字体,除了这个日历控件之外,它看起来很棒。到目前为止,我最初的搜索还没有产生任何看起来像解决方案的东西。

4

2 回答 2

2

看看SetWindowTheme函数。在它的帮助下,您可以仅为应用程序中的某些控件禁用 XP 主题,而保留其他控件。

根据 MSDN:

当 pszSubAppName 和 pszSubIdList 为 NULL 时,主题管理器会删除先前应用的关联。您可以通过指定一个不匹配任何部分条目的空字符串 (L" ") 来防止将视觉样式应用于指定的窗口。

于 2013-02-25T21:35:02.813 回答
1

上面cha的回复是正确的解决方案。为了使控件服从 SetMonthCalFont 调用,您必须禁用视觉主题。虽然有一些技巧。

1)您不能只在 CDateTimeCtrl 对象上调用 SetWindowTheme,因为该调用仅适用于该即时窗口而不是子窗口。月份下拉菜单是一个子窗口,因此不受影响。因此,您必须处理控件的 DTN_DROPDOWN 通知,并在其中获取子月份控件并从中删除视觉主题。

2)在发送DTN_DROPDOWN通知之前确定月份子控件的大小/位置。因此,即使您执行上面的#1,它的大小也不会正确。所以,你必须更新大小。

3) 显然,意图确实是传递一个空字符串而不是一个带有 1 个空格的字符串,尽管 MSDN 文档似乎表明了这一点。

4) 下面的代码没有考虑日历下拉控件靠近屏幕边缘的情况。如果发生这种情况,可能需要修改代码以解决它并移动其位置以使其仍然可见。

上面的信息由 Microsoft 支持中的 Dave Anderson 提供,下面的代码解决了问题并让控件使用自定义字体正确显示。

因此,我在对话框 InitInstance() 中的 CDateTimeCtrl 对象上调用 SetMonthCalFont(),然后还使用以下代码处理 DTN_DROPDOWN 通知。

请注意,Dave 提供了一个警告,“这种方法依赖于日期和时间选择器控件的实现细节,这些细节将来可能会发生变化,并可能导致下面的代码中断”。

void DSomeDialog::OnDtnDropdownMyDateTimeCtrl(NMHDR *pNMHDR, LRESULT *pResult)
{
HWND hWndDateTime = (HWND)pNMHDR->hwndFrom;
HWND hWndMonthCal = DateTime_GetMonthCal(hWndDateTime);
HWND hWndDropDown = ::GetParent(hWndMonthCal);
DWORD dwWidth;
WINDOWINFO wi;

if (hWndMonthCal && hWndDropDown)
{
    RECT rcIdeal;

    //
    //  Remove the window theme from the month calendar 
    //  control
    SetWindowTheme(hWndMonthCal, L"", L"");

    //
    //  Get the ideal size of the month calendar control
    ZeroMemory(&rcIdeal, sizeof(rcIdeal));
    MonthCal_GetMinReqRect(hWndMonthCal, &rcIdeal);
    dwWidth = MonthCal_GetMaxTodayWidth(hWndMonthCal);
    if (dwWidth > (DWORD)rcIdeal.right)
    {
        rcIdeal.right = dwWidth;
    }

    //
    //  Add some padding
    InflateRect(&rcIdeal, 3, 3);

    //
    //  Determine the new size of the drop down window such
    //  that the client area of the window is large enough 
    //  to display the month calendar control
    ZeroMemory(&wi, sizeof(wi));
    wi.cbSize = sizeof(WINDOWINFO);
    ::GetWindowInfo(hWndDropDown, &wi);
    AdjustWindowRectEx(&rcIdeal, wi.dwStyle, FALSE, wi.dwExStyle);

    //
    //  Update the size of the drop down window
    ::SetWindowPos(hWndDropDown,
        NULL, 
        0, 
        0, 
        rcIdeal.right - rcIdeal.left, 
        rcIdeal.bottom - rcIdeal.top, 
        SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
}

*pResult = 0;
}
于 2013-03-06T22:26:20.683 回答