Chinaunix首页 | 论坛 | 博客
  • 博客访问: 194896
  • 博文数量: 90
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 0
  • 用 户 组: 普通用户
  • 注册时间: 2017-08-23 16:48
文章分类

全部博文(90)

文章存档

2015年(1)

2011年(21)

2010年(59)

2009年(9)

我的朋友

分类: C/C++

2010-07-14 09:51:41

到目前为止,我们的例子中都没有一点Grid的影子,这趟改造一下程序,稍微能象点样,顺便加上一个也蛮流行的话题,传递数组问题,或者说是SAFEARRAY吧

我们先来看看SAFEARRAY和它的操作函数,从msdn上翻译了那么一段下来
SAFEARRAY的定义如下
struct SAFEARRAY {
    WORD cDims;
    WORD fFeatures;
    DWORD cbElements;
    DWORD cLocks;
    void * pvData;
    SAFEARRAYBOUND rgsabound[1];
};
基本上它的操作函数也就是对这个结构的操作了
SAFEARRAY * SafeArrayCreate(VARTYPE vt, UINT cDims, SAFEARRAYBOUND * aDims);
HRESULT SafeArrayDestroy(SAFEARRAY * psa);
这组函数不用多说了,建立一个SAFEARRAY,不过这个函数有个缺陷,它只能处理类型是VARIANT类型子集中的元素。
HRESULT SafeArrayAllocDescriptor(UINT cDims, SAFEARRAY ** ppsaOut);
HRESULT SafeArrayAllocData(SAFEARRAY * psa);
HRESULT SafeArrayDestroyData(SAFEARRAY * psa);
HRESULT SafeArrayDestroyDescriptor(SAFEARRAY * psa);
这组函数就提供了更多,更灵活的元素类型,但是用起来就稍微复杂一些了,何况一般在COM中也用不了这种复杂的数据类型。
HRESULT SafeArrayLock(SAFEARRAY * psa);
HRESULT SafeArrayUnlock(SAFEARRAY * psa);
这组函数只是对结构中cLocks值+1和-1,为什么要用这组函数,目前为止好象也不是非常理解,可能是为了防止在操作数据时删除数组吧,另外在已经 SafeArrayLock后,还可以再在其它地方SafeArrayLock来对数组进行操作,只要记得用完后SafeArrayUnlcok一下就可 以了。
HRESULT SafeArrayGetElement(SAFEARRAY * psa, long * aiIndex, void * pvElem);
HRESULT SafeArrayPutElement(SAFEARRAY * psa, long * aiIndex, void * pvElem);
这组函数是得到数组中的某一个值,aiIndex就是下标索引了,这组函数在每次调用的时候都自动调用SafeArrayLock和 SafeArrayUnlock,所以在需要遍历数组中的元素时,最好先用SafeArrayLock,再直接操作数据,最后用 SafeArrayUnlock。该组函数的用法举例如下:
long ai[2];
int iVal;
xMin = aDims[0].lLbound;
xMax = xMin + (int)aDims[0].cElements - 1;
yMin = aDims[1].lLbound;
yMax = yMin + (int)aDims[1].cElements - 1;
for (x = xMin; x <= xMax; x++) {
    ai[0] = x;
    for (y = yMin; y <= yMax; y++) {
        ai[1] = y;
        if (hres = SafeArrayGetElement(psaiInOut, ai, &iVal)) throw hres;
        // Equivalent to: aiInOut(x, y) = aiInOut(x, y) + 1.
        iVal++;
        if (hres = SafeArrayPutElement(psaiInOut, ai, &iVal)) throw hres;
    }
}
HRESULT SafeArrayPtrOfIndex(SAFEARRAY * psa, long * aiIndex, void ** ppv);
这个函数主要用在多维数组中,一维数组可以用,不过没什么意思吧,这个函数其实和SafeArrayGetElement类似,不过是一个有Lock,一个没Lock,所以用这个函数前,最好先SafeArrayLock一下,用完了,再SafeArrayUnlock。
HRESULT SafeArrayAccessData (SAFEARRAY * psa, void ** ppvData);
HRESULT SafeArrayUnaccessData(SAFEARRAY * psa);
这组函数只是简单的Lock和Unlock,加上返回SAFEARRAY结构的pvData成员而已,并不包含维数信息,所以,想不出什么理由来使用它,当然要使用那也是你的事。(这是文摘中的话,个人觉得在用一维数组时,这组函数非常有用)
UINT SafeArrayGetDim(SAFEARRAY * psa);
UINT SafeArrayGetElemsize(SAFEARRAY * psa);
这两个函数,第一个返回数组的维数,第二个返回数组中每个元素的大小,比如long就是4了。
其它的函数也不多说了,累,查查资料了
在MFC中,SAFEARRAY用COleSafeArray来封装了,稍微简化一些操作,不过基本用法应该一样的。
现在,我们开始了:
1.改造一下目前的代码,我们先用一个确定大小的Grid,就定为10*10吧
在CLiteGrid中加上成员变量
CCell m_cells[10][10];
在CLiteGrid的构造函数中初始化这100个CCell
CLiteGridCtrl::CLiteGridCtrl()
{
    InitializeIIDs(&IID_DLiteGrid, &IID_DLiteGridEvents);
    // TODO: Initialize your control's instance data here.
   m_scrollBars = 0;
    int x = 0;
    int y = 0;
    for(int i=0; i<10; i++, x+=50){
        y = 0;
        for(int j=0; j<10; j++, y+=20){
            m_cells[i][j].m_rect = CRect(x, y, x+50, y+20);
        }
    }
}
修改LPDISPATCH CLiteGridCtrl::GetCell(short nCol, short nRow)
LPDISPATCH CLiteGridCtrl::GetCell(short nCol, short nRow)
{
    // TODO: Add your property handler here
/*    CCell* pcell = new CCell;
    return pcell->GetIDispatch(FALSE);*/
    if(nCol >=0 && nCol < 10 && nRow >= 0 && nRow < 10){
        return m_cells[nCol][nRow].GetIDispatch(TRUE);
    }
    else{
        return NULL;
    }
}
添加OnDraw绘图代码
void CLiteGridCtrl::OnDraw(
            CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
    // TODO: Replace the following code with your own drawing code.
    pdc->FillRect(&rcBounds, &CBrush(RGB(10, 200, 100)));
    for(int i=0; i<10; i++){
        for(int j=0; j<10; j++){
            m_cells[i][j].Draw(pdc);
        }
    }
}
显然还缺省CCell的Draw代码,所以再添加CCell::Draw(CDC* pdc)函数
void CCell::Draw(CDC *pdc)
{
    pdc->Rectangle(&m_rect);
    int noldmode = pdc->SetBkMode(TRANSPARENT);
    pdc->DrawText(m_text, &m_rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    pdc->SetBkMode(noldmode);
}
2.应该差不多了吧,大致就是画10*10个框框,然后在框框中写字,现在编译一下,不出意外的话,是通过了的。
3.转到VB下,就可以看到这个框框了,不过好象没字,当然了,m_text是空的啊
4.当然可以通过ICell的Text属性给m_text赋值,但我们讲了那么多SafeArray,总要用上吧,所以为CLiteGridCtrl再加 上一个Texts属性,用这个属性给所有的Cell赋上Text,Texts属性用Get/Set methods,类型为VARIANT
5.实现Texts属性
VARIANT CLiteGridCtrl::GetTexts()
{
    COleSafeArray sa;
    DWORD dweles[2] = {10, 10};
    sa.Create(VT_BSTR, 2, dweles);
    long lindex[2] = {0};
    BSTR* pele = NULL;
    sa.Lock();
    for(int i=0; i<10; i++){
        lindex[0] = i;
        for(int j=0; j<10; j++){
            lindex[1] = j;
            sa.PtrOfIndex(lindex, (void**)&pele);
            *pele = T2BSTR(m_cells[i][j].m_text);
        }
    }
    sa.Unlock();
    return sa.Detach();
}
void CLiteGridCtrl::SetTexts(const VARIANT FAR& newValue)
{
    // TODO: Add your property handler here
    USES_CONVERSION;
    COleSafeArray sa(newValue);
    ASSERT(sa.GetDim() == 2);
    long llb1 = 0;
    long lub1 = 0;
    long llb2 = 0;
    long lub2 = 0;
    long l1 = 0;
    long l2 = 0;
    sa.GetLBound(1, &llb1);
    sa.GetUBound(1, &lub1);
    l1 = lub1-llb1+1;
    ASSERT(l1 == 10);
    sa.GetLBound(2, &llb2);
    sa.GetUBound(2, &lub2);
    l2 = lub2-llb2+1;
    ASSERT(l2 == 10);
    long lindex[2] = {0};
    BSTR* pele = NULL;
    sa.Lock();
    for(int i=llb1; i<=lub1; i++){
        lindex[0] = i;
        for(int j=llb2; j<=lub2; j++){
            lindex[1] = j;
            sa.PtrOfIndex(lindex, (void**)&pele);
            m_cells[i-llb1][j-llb2].m_text = OLE2T(*pele);
        }
    }
    sa.Unlock();
    InvalidateControl();
    SetModifiedFlag();
}
要注意的是因为用到了字符串转换宏OLE2T, T2BSTR,所以需要#include "afxpriv.h",个人还是挺喜欢这组宏的,用起来特省事,就是老要加USES_CONVERSION,别扭的紧。

6.在VB的Form_Load中添加如下代码
Private Sub Form_Load()
Dim str(0 To 9, 0 To 9) As String
Dim stro() As String
Dim i As Integer
Dim j As Integer
For i = 0 To 9
    For j = 0 To 9
        str(i, j) = i & " : " & j
    Next
Next
LiteGrid1.Texts = str
stro = LiteGrid1.Texts
End Sub
运行后可以发现10*10个网格,每个网格上都有纵横坐标字样
这篇好象稍微长了些,主要是SAFEARRAY的用法解释的多了些,应该不会烦到哪去吧。那就到这里了。
 
本文来自CSDN博客,转载请标明出处:
阅读(1354) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~