ActiveX控件的MFC设计之旅-第6步 .

来源:互联网 发布:国家税务局网络 编辑:程序博客网 时间:2024/05/29 15:36
 
痛苦,已经写完了,Firefox报了错,只得重来。

关于属性页,这里先翻译msdn上一段关于属性页的介绍。
用户通过属性页来操作控件的属性,用户可以设置一个或多个属性页,每个属性页上可以显示控件的某些属性。这些属性既可以来自一个控件,也可以来自多个控件,也就是说一个属性页上可以显示多个控件的属性。
每个ActiveX控件属性页都是一个进程内对象,拥有它自己的CLSID,每个属性页均实现了IPropertyPage接口。IPropertyPage::SetObjects是用来将控件对象的接口指针(IUnknown)传递给属性页的。
MFC的COlePropertyPage也实现了IPropertyPage接口,它将控件对象指针的保存在一个IDispatch接口指针的数组中。该数组可以通过COlePropertyPage::GetObjectArray()访问,这样就可以通过IDispatch接口来访问控件的属性了,令人头疼的是通过IDispatch来访问控件属性,实在有够麻烦,MFC提供了COleDispatchDriver来帮助访问,可惜,也仅仅是能稍微简化一些操作而已。其实,MFC为了自己方便,在COlePropertyPage还提供了一组函数来帮助访问控件的属性,只不过这组函数没公布在msdn中罢了,下面是这组函数的声明:
    // DDP_ property get/set helper routines
    BOOL SetPropText(LPCTSTR pszPropName, BYTE &Value);
    BOOL GetPropText(LPCTSTR pszPropName, BYTE* pValue);
    BOOL SetPropText(LPCTSTR pszPropName, short &Value);
    BOOL GetPropText(LPCTSTR pszPropName, short* pValue);
    BOOL SetPropText(LPCTSTR pszPropName, int &Value);
    BOOL GetPropText(LPCTSTR pszPropName, int* pValue);
    BOOL SetPropText(LPCTSTR pszPropName, UINT &Value);
    BOOL GetPropText(LPCTSTR pszPropName, UINT* pValue);
    BOOL SetPropText(LPCTSTR pszPropName, long &Value);
    BOOL GetPropText(LPCTSTR pszPropName, long* pValue);
    BOOL SetPropText(LPCTSTR pszPropName, DWORD &Value);
    BOOL GetPropText(LPCTSTR pszPropName, DWORD* pValue);
    BOOL SetPropText(LPCTSTR pszPropName, CString &Value);
    BOOL GetPropText(LPCTSTR pszPropName, CString* pValue);
    BOOL SetPropText(LPCTSTR pszPropName, float &Value);
    BOOL GetPropText(LPCTSTR pszPropName, float* pValue);
    BOOL SetPropText(LPCTSTR pszPropName, double &Value);
    BOOL GetPropText(LPCTSTR pszPropName, double* pValue);
    BOOL SetPropCheck(LPCTSTR pszPropName, int Value);
    BOOL GetPropCheck(LPCTSTR pszPropName, int* pValue);
    BOOL SetPropRadio(LPCTSTR pszPropName, int Value);
    BOOL GetPropRadio(LPCTSTR pszPropName, int* pValue);
    BOOL SetPropIndex(LPCTSTR pszPropName, int Value);
    BOOL GetPropIndex(LPCTSTR pszPropName, int* pValue);

在一般情况下,我们并不用直接访问控件的属性,一切都由框架帮助做了(框架利用了DoDateExchange,DoDataExchange又用了上面的SetPropText/GetPropText函数组)。
但是,有时候,我们希望能在控件中直接访问控件的属性和方法。对于普通属性,使用上面的GetPropText和SetPropText足以满足需要,但是对于带参数的属性和方法,就只好老老实实的用COleDispatchDriver来InvokeHelper了。

下面是在属性页中访问控件属性和方法的例子toop.

1.控件中设置了一个字符串数组CStringArray m_saItems,提供了方法long Add(LPCTSTR strItem)和get/set method属性BSTR Item(long lItem)来访问数组中的某项字符串,另外还有一个只读属性long Count(在添加属性的向导中,设置为get/set methods类型的属性,并去掉SetCount即是设置为只读属性了)
2.控件另外设置了一member variable属性OLE_COLOR Color
3.属性和方法的实现如下:

void CToppCtrl::OnColorChanged()
{
    // TODO: Add notification handler code
    SetModifiedFlag();
}

long CToppCtrl::Add(LPCTSTR strItem)
{
    // TODO: Add your dispatch handler code here
    return m_saItems.Add(strItem);
    return 0;
}

BSTR CToppCtrl::GetItem(long nItem)
{
    CString strResult;
    // TODO: Add your property handler here
    if(nItem >= 0 && nItem < m_saItems.GetSize()){
        strResult = m_saItems[nItem];
    }
    return strResult.AllocSysString();
}

void CToppCtrl::SetItem(long nItem, LPCTSTR lpszNewValue)
{
    // TODO: Add your property handler here
    if(nItem >= 0 && nItem < m_saItems.GetSize()){
        m_saItems[nItem] = lpszNewValue;
    }
    SetModifiedFlag();
}

long CToppCtrl::GetCount()
{
    // TODO: Add your property handler here
    return m_saItems.GetSize();
    return 0;
}

控件编完后,就是属性页这个重头戏了:
1.界面,对于控件中字符串数组,添加了一编辑框和一按钮("添加项目")来调用控件的Add方法;添加了一列表框来调用控件的Item属性填充列表框。
2.界面,对于控件的Color属性,添加了一按钮("设置颜色")和一静态文本框(Caption为"看看我的颜色吧",ID为IDC_STATIC_COLOR)来设置颜色和获得颜色属性,文本框的文本背景颜色即为获得的颜色。
3.添加成员函数BOOL AddItem(LPCTSTR lpszItem)用来调用控件的Add方法添加字符串,添加CString GetItem(long lItem)函数来获得字符串数组中的lItem项对应的字符串,添加long GetCount()来获得数组中字符串的数目;添加COLORREF GetColor()函数来获得控件的Color属性,添加SetColor()函数来设置控件的Color属性,这些函数的实现如下:

BOOL CToppPropPage::AddItem(LPCTSTR lpszItem)
{
    USES_CONVERSION;
    COleDispatchDriver PropDispDriver;
    BOOL bResult = FALSE;
    ULONG nObjects = 0;
    LPDISPATCH* ppDisp = GetObjectArray(&nObjects);
    for (ULONG i = 0; i < nObjects; i++)
    {
        DISPID dwDispID;
        LPCOLESTR lpOleStr = T2COLE("Add");
        if (SUCCEEDED(ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID)))
        {
            PropDispDriver.AttachDispatch(ppDisp[i], FALSE);
            BYTE rgbParams[] = VTS_BSTR;
            long lret = 0;
            PropDispDriver.InvokeHelper(dwDispID, DISPATCH_METHOD, VT_I4, &lret, rgbParams, lpszItem);
            PropDispDriver.DetachDispatch();
            bResult = TRUE;
        }
    }
    return bResult;
}

CString CToppPropPage::GetItem(long lItem)
{
    CString str = _T("");
    USES_CONVERSION;
    COleDispatchDriver PropDispDriver;
    ULONG nObjects = 0;
    LPDISPATCH* ppDisp = GetObjectArray(&nObjects);
    for (ULONG i = 0; i < nObjects; i++)
    {
        DISPID dwDispID;
        LPCOLESTR lpOleStr = T2COLE("Item");
        if (SUCCEEDED(ppDisp[i]->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpOleStr, 1, 0, &dwDispID)))
        {
            PropDispDriver.AttachDispatch(ppDisp[i], FALSE);
            BYTE rgbParams[] = VTS_I4;
            PropDispDriver.InvokeHelper(dwDispID, DISPATCH_PROPERTYGET, VT_BSTR, &str, rgbParams, lItem);
            PropDispDriver.DetachDispatch();
        }
    }
    return str;
}

COLORREF CToppPropPage::GetColor()
{
    long l = 0;
    GetPropText("Color", &l);
    COLORREF cr = RGB(0, 0, 0);
    ::OleTranslateColor((OLE_COLOR)l, NULL, &cr);
    return cr;
}

void CToppPropPage::SetColor(COLORREF cr)
{
    SetPropText("Color", cr);
}

long CToppPropPage::GetCount()
{
    long lcount = 0;
    GetPropText("Count", &lcount);
    return lcount;
}

4.添加按钮("添加项目")响应函数

void CToppPropPage::OnButtonAdditem()
{
    // TODO: Add your control notification handler code here
    UpdateData();
    AddItem(m_strItem);            //m_strItem为编辑框关联的CString对象

    //填充列表框
    long lcount = 0;
    GetPropText("Count", &lcount);
    m_list.ResetContent();         //m_list为列表框关联的CListBox对象
    for(int i=0; i<lcount; i++){
        m_list.AddString(GetItem(i));
    }
}

5.添加按钮("设置颜色")响应函数来设置控件的Color属性
void CToppPropPage::OnButtonSetcolor()
{
    // TODO: Add your control notification handler code here
    CColorDialog dlg;
    if(dlg.DoModal() == IDOK){
        long lcolor = dlg.GetColor();
        SetPropText("Color", lcolor);
        GetDlgItem(IDC_STATIC_COLOR)->Invalidate();
    }
}

6.添加WM_CTLCOLOR消息响应函数,在函数里获得控件的Color属性,并用该Color设置静态文本框的文本背景颜色
HBRUSH CToppPropPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = COlePropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);
   
    // TODO: Change any attributes of the DC here
    if(nCtlColor == CTLCOLOR_STATIC){
        COLORREF cr = GetColor();
        pDC->SetBkColor(cr);
    }
    // TODO: Return a different brush if the default is not desired
    return hbr;
}

7.OK了,编译,可以在ActiveX Control Container中测试了

下面是控件和属性页效果图,因为后添加,加上了其它的许多效果,请参考本系列后续文章
原创粉丝点击