MFC/WinAPI的大问题 [英] Big problems with MFC/WinAPI

查看:110
本文介绍了MFC/WinAPI的大问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要使用带有两个选项卡的formview创建一个SDI表单,该视图将多个对话框封装为选项卡内容.但是表单必须具有彩色背景.

像这样的事情让我讨厌编程.

首先,我通过资源编辑器尝试了CTabControl,尝试了不同的操作,但是未记录的行为和没有答案的怪癖使我陷入了障碍.

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

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

并且可以通过CPropertySheet的AddPage方法将派生自CPropertyPage的对话框类直接添加为页面.

太好了!并非完全如此...有些控件没有起作用,也没有创建,遇到了奇怪的断言.原来对话框中缺少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依赖于这种行为."据我了解,他在Microsoft工作了20年的拉里·奥斯特曼(Larry Osterman)让我大声笑了.

无论如何,修正了现在已经按预期创建了dialog-controls(CPropertyPages)的情况,该部分看起来有些遥不可及,但是下一个带有颜色的部分再次死了!

通常,您将重写WM_CTLCOLOR,检查控件ID或hwnd并提供必要的画笔以设置所需的颜色.对于CPropertySheet并非如此,整个第一行都保持灰色!对于CTabCtrl,它以某种方式起作用,而对于CPropertySheet,则不起作用.

为什么?似乎CPropertySheet有点嵌入CTabControl之类的东西,因为如果我重写WM_ERASEBKGND,则只有内部会更改颜色.

现在,似乎CPropertySheet中有一个GetTabControl()方法,该方法返回CPropertySheet的实际CTabCtrl *.但是由于它是内部构造的,所以我找不到如何覆盖它的WM_CTLCOLOR消息处理.

似乎有一个子类化windowproc的方法,但是经过多次尝试,我找不到有关如何执行此操作的任何好方法. MSDN上的SubclassWindow文档说:调用此函数时,窗口必须尚未附加到MFC对象上."那是什么?

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

尝试将内部CTabCtrl的WindowLong设置为GCL_HBRBACKGROUND,

最糟糕的是,我找不到关于该主题的任何有用的文档或教程.

我最能找到的是如何所有者制表符控件,但这在很多方面都是严重错误,我想要一个标准控件行为减去背景色,我不希望支持不同的配色方案,Windows版本和IAccesible界面和所有这些东西,而且我所见过的ownerdraw示例都无法获得所有标准控件行为的10%.我不幻想会创造出更好的东西,我不会动用手头的资源.

我偶然发现了这个线程,我无法与作者保持一致:解决方案

您唯一的选择是所有者绘制选项卡控件.没那么难.好吧,这很令人沮丧,因为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();
}

I need to create a SDI form with a formview that has two tabs, which encapsulate multiple dialogs as the tab content. But the form has to have a colored background.

And things like these makes me hate programming.

First, I tried CTabControl, via resource editor, tried different things, but the undocumented behavior and the quirks with no answers led me into a roadblock.

After many hours of searching, I found that there is a control called property sheet, which is actually what I need.

Some more searching later, I found that property sheet can even be actually embedded onto CFormView like so: http://www.codeguru.com/Cpp/controls/propertysheet/article.php/c591

And that the dialog classes derived from CPropertyPage can be directly added as pages via AddPage method of CPropertySheet.

Great! Not quite so... Some of the controls didn't worked, and were not created, ran into weird asserts. Turns out the DS_CONTROL style was missing from the dialogs. Found it completely accidentaly on http://blogs.msdn.com/b/oldnewthing/archive/2007/01/08/1434501.aspx, no word about that on MSDN!!!! Property page must have: DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_TABSTOP, and can have: DS_SHELLFONT | DS_LOCALEDIT | WS_CLIPCHILDREN styles! Not any other, which are created by default with resource editor. Sweet, super hidden information for software developers!

The quote in comments on that page: "OMG. That's where that behavior came from...

It turns out that the PlaySound API relied on that behavior when playing sounds on 64bit machines." by Larry Osterman, who as I understand works for Microsoft for 20 years, got me laughing out loud.

Anyway, fixed that, the dialog-controls(CPropertyPages) are created as expected now, and that part looks something remotely promising, but the next part with color is dead end again!

Normally you override WM_CTLCOLOR, check for control ID or hwnd and supply the necessary brush to set the color you need. Not quite so with CPropertySheet, the whole top row stays gray! For CTabCtrl it somehow works, for CPropertySheet it doesn't.

Why? Seems that the CPropertySheet is kinda embedded inside CTabControl or something, because if I override WM_ERASEBKGND, only the internal part changes the color.

Now it seems that there is a GetTabControl() method in the CPropertySheet, that returns the actual CTabCtrl* of the CPropertySheet. But since it's constructed internally, I can't find how to override it's WM_CTLCOLOR message processing.

There seems to be a way to subclass the windowproc, but after multiple tries I can't find any good source on how to do it. SubclassWindow doc on MSDN says: "The window must not already be attached to an MFC object when this function is called."?! What's that?

I tried creating a custom CCustomTabCtrl class based on CTabCtrl via MFC wizard, created an instance of it, called SubclassWindow from one of the CCustomPropertySheet handlers to override the internal CTabCtrl, but nothing works, mystical crashes deep inside MFC.

Tried setting WindowLong with GCL_HBRBACKGROUND for the internal CTabCtrl, nothing changed.

And worst of all, I can't find any sort of useful documentation or tutorials on the topic.

Most I can find is how to ownerdraw the tab control, but this is seriously wrong on so many ways, I want a standard control behavior minus background color, I don't want to support different color schemes, windows versions, IAccesible interfaces and all this stuff, and none of the ownerdraw samples I've seen can get even 10% of all the standard control behavior right. I have no illusion that I will create something better, I wont with the resources at hand.

I stumbled upon this thread, and I can't agree with the author more: http://arstechnica.com/civis/viewtopic.php?f=20&t=169886&sid=aad002424e80121e514548d428cf09c6 owner draw controls are undocumented PITA, that are impossible to do right, and there is NULL information on MSDN to help.

So is there anything I have missed or haven't tried yet? How to change the top strip background color of the CPropertySheet? Anyone?

解决方案

Your only option is to ownerdraw the tab control. It's not that hard. Well, it is frustrating because MFC doesn't tell you how to make the necessary Win32 calls.

In your CPropertySheet-derived class, overwrite OnInitDialog() and add:

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

This puts your CPropertySheet-derived class in charge of drawing the tab control. Add a handler for WM_DRAWITEM (OnDrawItem) and change backgroundColor and textColor to match whatever colors you wanted. Code for OnDrawItem follows:

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();
}

这篇关于MFC/WinAPI的大问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆