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

可以保存和恢复列布局的 CListCtrl

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2009 年 3 月 1 日

CPOL

2分钟阅读

viewsIcon

38600

downloadIcon

975

关于如何实现列宽和位置持久化的示例。

引言

Microsoft 的CListCtrl支持使用报表样式显示网格中的数据,但要使其记住其列状态(列顺序、宽度等),需要进行某些更改。

此实现支持以下功能:

  • 可以备份和恢复列宽和列顺序。
  • 可以处理从初始配置中添加/删除列的情况。
  • 可以处理多个视图的列配置。
  • 可以将列配置重置为初始配置。
  • 可以在多个列状态配置文件之间切换。如果您需要额外的特殊列配置(例如,打印时),这很有用。
  • 易于更改为另一个持久层。

clistctrl_persist_state/screenshot.png

背景

许多高级网格控件扩展了CListCtrl,使其能够持久保存列状态。但是,由于这些网格控件可能非常复杂,因此很难看出它们是如何实现的。

同时,加载和保存列状态以及选择的持久层(注册表、INI 文件、XML 文件)之间很少有分离。

本文是系列文章的一部分,最后一篇文章CGridListCtrlEx结合了所有文章的细节。

选择持久层

通常有三个不同的层可以选择:

  • 注册表数据库 - 支持深层层次结构和二进制数据类型。
  • INI 文件 - 支持一级层次结构和字符串数据类型。
  • XML 文件 - 支持深层层次结构和字符串数据类型。

Microsoft 通过CWinApp对象及其方法GetProfileString()WriteProfileString()简化了在注册表数据库或INI文件中存储设置的操作。

许多人都在努力创建保存/存储设置的最佳实现。

使用代码

唯一列标识符

CListCtrl中的每一列都必须具有唯一的标识符,否则列状态的备份和恢复将无法正常工作。此外,在删除过时的列时,其他列的唯一标识符应保持不变。

在调用CListCtrl::InsertColumn()时,我们可以指定列标识符(col_id)。

m_ListCtrl.InsertColumn(col_pos, _T("Column Title"), LVCFMT_LEFT, 100, col_id); 

在添加/删除列时,其他列的列标识符保持不变非常重要。

设置持久层

PersistViewConfigWinApp实现接口PersistViewConfig,并使通过CWinApp在INI文件或注册表中存储设置成为可能。

void CListCtrl_Column_Persist::LoadConfiguration(PersistViewConfigProfiles* pViewConfig)
{
    m_pViewConfig = pViewConfig;
    // Save the current configuration as default configuration
    if (!m_pViewConfig->HasDefaultConfig())
    {
        PullConfiguration(m_pViewConfig->GetDefaultConfig());
    }
    // Load the saved configuration
    PushConfiguration(*m_pViewConfig);
}

保存列状态

使用LVS_EX_HEADERDRAGDROP样式时,必须从CHeaderCtrl检索列顺序。我们根据列顺序(以及列宽)存储唯一的列标识符。

void CListCtrl_Column_Persist::PullConfiguration(PersistViewConfig& config)
{
    config.RemoveCurrentConfig(); // Reset the existing config
    int nColCount = GetHeaderCtrl()->GetItemCount();
    int* pOrderArray = new int[nColCount];
    GetColumnOrderArray(pOrderArray, nColCount);
    int nVisibleCols = 0;
    for(int i = 0 ; i < nColCount; ++i)
    {
        int nCol = pOrderArray[i];
        int nColData = GetColumnData(nCol);

        // In this example columns are visible when their width is larger than zero
        if (IsColumnVisible(nCol))
        {
            CString colSetting;
            colSetting.Format(_T("ColumnData_%d"), nVisibleCols);
            config.SetIntSetting(colSetting, nColData);
            colSetting.Format(_T("ColumnWidth_%d"), nVisibleCols);
            config.SetIntSetting(colSetting, GetColumnWidth(nCol));
            nVisibleCols++;
        }
    }
 
    config.SetIntSetting(_T("ColumnCount"), nVisibleCols);
    delete [] pOrderArray;
}

应用列状态

保存列状态的反向操作,但额外需要注意的是必须处理列不再存在或出现新列的情况。

void CListCtrl_Column_Persist::PushConfiguration(const PersistViewConfig& config)
{
    int nVisibleCols = config.GetIntSetting(_T("ColumnCount"));
    int nColCount = GetHeaderCtrl()->GetItemCount();
    int* pOrderArray = new int[nColCount];
    GetColumnOrderArray(pOrderArray, nColCount);
    SetRedraw(FALSE);
    // All invisible columns must be place in the begining of the order-array
    int nColOrder = nColCount;
    for(int i = nVisibleCols-1; i >= 0; --i)
    {
        CString colSetting;
        colSetting.Format(_T("ColumnData_%d"), i);
        int nColData = config.GetIntSetting(colSetting);
        for(int nCol = 0; nCol < nColCount; ++nCol)
        {
           if (nColData==GetColumnData(nCol))
           {
               // Column still exists
               colSetting.Format(_T("ColumnWidth_%d"), i);
               int width = config.GetIntSetting(colSetting);
               SetColumnWidth(nCol, width);
               pOrderArray[--nColOrder] = nCol;
               break;
           }
        }
    }
    // Did we find any visible columns in the saved configuration ?
    if (nColOrder < nColCount)
    {
        // All remaining columns are added to the beginning with size zero
        for(int nCol = nColCount-1; nCol >= 0; --nCol)
        {
            bool visible = false;
            for(int i = nColOrder; i < nColCount; ++i)
            {
                if (pOrderArray[i]==nCol)
                {
                    visible = true;
                    break;
                }
            }
            if (!visible)
            {
                pOrderArray[--nColOrder] = nCol;
                SetColumnWidth(nCol, 0);
            }
        }

        // Only update the column configuration if there are visible columns
        ASSERT(nColOrder==0); // All entries in the order-array must be set
        SetColumnOrderArray(nColCount, pOrderArray);
    }
    
    delete [] pOrderArray;
    SetRedraw(TRUE);
    Invalidate();
    UpdateWindow();
}

重置列配置

将当前配置重置为初始状态,然后加载当前配置。

void CListCtrl_Column_Persist::ResetConfiguration()
{
    if (m_pViewConfig->HasDefaultConfig())
    {
        m_pViewConfig->ResetConfigDefault();
        PushConfiguration(*m_pViewConfig);
    }
}

更改配置配置文件

在更改为新的配置配置文件之前,我们保存当前列状态。

void CListCtrl_Column_Persist::ChangeProfile(const CString& profile)
{
    PullConfiguration(*m_pViewConfig);
    m_pViewConfig->SetActiveProfile(profile);
    PushConfiguration(*m_pViewConfig);
}

关注点

目前还没有。

历史

  • **2008-03-30** - 初始发布。
© . All rights reserved.