65.9K
CodeProject 正在变化。 阅读更多。
Home

一个静态分割器,具有隐藏/显示多个列/行的能力

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (12投票s)

2002年8月7日

2分钟阅读

viewsIcon

133053

downloadIcon

2888

一个静态分割器,具有隐藏/显示多个列/行的能力

引言

当我在开发一个应用程序时,我意识到它需要一个静态分割器,能够同时隐藏/显示多个行或列。 令人惊讶的是,我找不到这样的组件。 最接近的解决方案是 Oleg Galkin 在这里 提出的。 他的分割器可以隐藏/显示分割器的一行(列),但只能一个。 本文提出了一个静态分割器,具有隐藏/显示多个列/行的能力。

算法扩展的问题

MFC CSplitterWnd 通过 ID 访问其窗格,ID 定义了窗格在分割器中的位置。 假设要隐藏第 n 列。 在 Oleg Galkin 的算法中,第 n 列获得了最后一列的 ID。 第 n 列之后的列向左移动 1,即 n+1 控件的 ID 被分配给控件 n,n+2 的 ID 被分配给 n+1,依此类推。 尝试将这种方法扩展到隐藏多列导致算法过于复杂。 每次隐藏列时,之前隐藏的操作中隐藏的列的 ID 都会再次更改。 因此,如果您隐藏三列,则某些控件的 ID 将更改三次。 追踪所有这些变化是一个不简单的问题。

新方法

CExtSplitter 类使用绝对地址和相对地址来操作分割器窗格。 绝对列地址是初始列号,相对地址是分割器中的当前列号。 HideColumnShowColumn public 函数使用绝对地址。 相对地址在内部使用。 CExtSplitter 类将指向所有控件的指针保存在内部数组中。 该数组在创建分割器时初始化一次,并且在分割器的存在期间不会更改。 此数组的行和列用于按绝对 ID 访问分割器窗格。 如果分割器使用 m 行和 n 列初始化,那么隐藏第 k 列(0 < k < n),意味着隐藏最初是第 k 列的列。 请注意,在多次隐藏操作之后,第 k 列可以出现在分割器中小于 k 的任何位置。

实现细节

CExtSplitter 类具有一个显示和隐藏列的列表。 列表成员的值是一个绝对列地址,位置是相对列地址。

class CExtSplitter : public CSplitterWnd
{
public:
    typedef std::list < int > LIST_INT;

    CExtSplitter();   

    virtual ~CExtSplitter();

    BOOL CreateStatic(CWnd* pParentWnd,
        int nRows, int nCols,
        DWORD dwStyle = WS_CHILD | WS_VISIBLE,
        UINT nID = AFX_IDW_PANE_FIRST);

    virtual BOOL CreateView( int row, int col, 
        CRuntimeClass* pViewClass, SIZE sizeInit,
        CCreateContext* pContext );

    void    HideColumn(int colHide);
    void    ShowColumn(int colShow);
    void    HideRow(int colRow);
    void    ShowRow(int row);

public: 
    LIST_INT m_shown_cols;      //shown  column list
    LIST_INT m_hid_cols;        //hidden column list
    LIST_INT m_shown_rows;      //shown  rows list
    LIST_INT m_hid_rows;        //hidden rows list

protected:
    //array of pointers to splitter panes
    C2DArray m_pane_ptr_array;  
};

函数 HideColumn 将列从显示列的列表移动到隐藏列的列表,并重新枚举分割器窗格。 重新枚举规则的 C++ 代码如下所示

void CExtSplitter::RenumeratePanes()
{
    int i,j,id;

    for(i=0; i < m_nMaxRows; i++)
    {
        for(j=0; j < m_nMaxCols; j++)
        {
            CPoint pos  = RelToAbsPosition(i,j);
            CWnd* pPane = 
                (CWnd*) m_pane_ptr_array(pos.x, pos.y);
            ASSERT(pPane != NULL);

            id=AFX_IDW_PANE_FIRST + i * 16 + j;

            int r=pPane->SetDlgCtrlID(id);
            ASSERT(r);

            if(IsPaneVisible(pos.x,pos.y))
                pPane->ShowWindow(SW_SHOW);
            else
                pPane->ShowWindow(SW_HIDE);

        }
    }
}

其中 RelToAbsPosition 函数将相对窗格位置转换为绝对窗格位置。

演示项目

在演示项目中,您可以通过“视图”子菜单调用隐藏和显示函数。 CExtSplitter 类依赖于 C2DArray,它包含在项目中。

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.