MFC / WinAPI的大问题

时间:2010-10-20 12:19:48

标签: visual-studio winapi mfc

我需要创建一个带有formview的SDI表单,该表单有两个选项卡,它们将多个对话框封装为选项卡内容。但表格必须有彩色背景。

这些事情让我讨厌编程。

首先,我尝试了CTabControl,通过资源编辑器,尝试了不同的东西,但没有记录的行为和没有答案的怪癖让我陷入了障碍。

经过几个小时的搜索,我发现有一个名为属性表的控件,这实际上就是我所需要的。

稍后再搜索一下,我发现属性表甚至可以实际嵌入到CFormView中,如下所示:http://www.codeguru.com/Cpp/controls/propertysheet/article.php/c591

从CPropertyPage派生的对话框类可以通过CPropertySheet的AddPage方法直接添加为页面。

大!不是这样......有些控件没有用,而且没有被创建,遇到了奇怪的断言。结果是对话框中缺少DS_CONTROL样式。在http://blogs.msdn.com/b/oldnewthing/archive/2007/01/08/1434501.aspx完全意外地发现它,在MSDN上没有关于它的消息!属性页必须包含:DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_TABSTOP,可以有:DS_SHELLFONT | DS_LOCALEDIT | WS_CLIPCHILDREN样式!没有任何其他,默认情况下使用资源编辑器创建。为软件开发人员提供的超级隐藏信息!

该页面评论中的引用:“OMG。这就是这种行为的来源......

事实证明,当在64位计算机上播放声音时,PlaySound API依赖于这种行为。“拉里奥斯特曼,据我所知,他为微软工作了20年,让我大笑。

无论如何,修正了,对话框控件(CPropertyPages)现在按照预期创建了,那部分看起来很有希望,但下一部分有颜色的部分再次死路一条!

通常你重写WM_CTLCOLOR,检查控件ID或hwnd并提供必要的画笔来设置你需要的颜色。对于CPropertySheet来说并不是这样,整个顶行保持灰色!对于CTabCtrl,它在某种程度上是有效的,对于CPropertySheet它没有。

为什么呢?似乎CPropertySheet有点嵌入CTabControl或其他东西,因为如果我覆盖WM_ERASEBKGND,只有内部部分改变颜色。

现在看来CPropertySheet中有一个GetTabControl()方法,它返回CPropertySheet的实际CTabCtrl *。但由于它是在内部构建的,我无法找到如何覆盖它的WM_CTLCOLOR消息处理。

似乎有一种方法可以对windowproc进行子类化,但经过多次尝试后,我找不到任何关于如何做的好消息来源。 MSDN上的SubclassWindow doc说:“调用此函数时,窗口不得已经附加到MFC对象。”?!那是什么?

我尝试通过MFC向导创建一个基于CTabCtrl的自定义CCustomTabCtrl类,创建了一个实例,从一个CCustomPropertySheet处理程序调用SubclassWindow来覆盖内部CTabCtrl,但没有任何效果,神秘崩溃在MFC内部。

尝试使用GCL_HBRBACKGROUND为内部CTabCtrl设置WindowLong,没有任何改变。

最糟糕的是,我找不到任何有用的文档或教程。

我能找到的最多是如何拥有标签控件,但这在很多方面严重错误,我想要一个标准的控制行为减去背景颜色,我不想支持不同的配色方案,windows版本,IAccesible接口和所有这些东西,我见过的所有ownerdraw样本都没有得到所有标准控制行为的10%。我没有幻想我会创造更好的东西,我不会掌握手头的资源。

我偶然发现了这个帖子,我不能更多地同意作者:http://arstechnica.com/civis/viewtopic.php?f=20&t=169886&sid=aad002424e80121e514548d428cf09c6所有者绘制控件是未记录的PITA,这是不可能正确的,并且MSDN上有空信息可以提供帮助。 / p>

那么我有什么遗漏或者还没有尝试过吗?如何更改CPropertySheet的顶部条带背景颜色?任何人吗?

2 个答案:

答案 0 :(得分:5)

您唯一的选择是拥有标签控件。这并不难。嗯,这很令人沮丧,因为MFC没有告诉你如何进行必要的Win32调用。

在CPropertySheet派生类中,覆盖OnInitDialog()并添加:

GetTabControl()->ModifyStyle(0,TCS_OWNERDRAWFIXED);

这会使您的CPropertySheet派生类负责绘制选项卡控件。为WM_DRAWITEM(OnDrawItem)添加处理程序并更改backgroundColor和textColor以匹配您想要的任何颜色。 OnDrawItem的代码如下:

void CPropSht::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    if (ODT_TAB != lpDrawItemStruct->CtlType)
    {
        CPropertySheet::OnDrawItem(nIDCtl, lpDrawItemStruct);
        return;
    }

    // prepare to draw the tab control
    COLORREF backgroundColor = RGB(0,255,0);
    COLORREF textColor = RGB(0,0,255);
    CTabCtrl *c_Tab = GetTabControl();

    //  Get the current tab item text.
    TCHAR buffer[256] = {0};
    TC_ITEM tcItem;
    tcItem.pszText = buffer;
    tcItem.cchTextMax = 256;
    tcItem.mask = TCIF_TEXT;

    if (!c_Tab->GetItem(c_Tab->GetCurSel(), &tcItem )) return;

    // draw it
    CDC aDC;
    aDC.Attach(lpDrawItemStruct->hDC);
    int nSavedDC = aDC.SaveDC();

    CBrush newBrush;
    newBrush.CreateSolidBrush(backgroundColor);
    aDC.SelectObject(&newBrush);
    aDC.FillRect(&lpDrawItemStruct->rcItem, &newBrush);
    aDC.SetBkMode(TRANSPARENT); 
    aDC.SetTextColor(textColor);
    aDC.DrawText(tcItem.pszText, &lpDrawItemStruct->rcItem, DT_CENTER|DT_VCENTER|DT_SINGLELINE);

    aDC.RestoreDC(nSavedDC);

    aDC.Detach();
}

答案 1 :(得分:0)

感谢您提供此解决方案,但是......

上述解决方案适用于一个选项卡,但是当您有多个选项卡时,它似乎重命名了错误的选项卡。我需要将GetItem的if语句更改为:

if (!c_Tab->GetItem(lpDrawItemStruct->itemID, &tcItem )) return;

需要 lpDrawItemStruct-> itemID 才能正确命名标签