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





5.00/5 (1投票)
关于如何实现列宽和位置持久化的示例。
引言
Microsoft 的CListCtrl
支持使用报表样式显示网格中的数据,但要使其记住其列状态(列顺序、宽度等),需要进行某些更改。
此实现支持以下功能:
- 可以备份和恢复列宽和列顺序。
- 可以处理从初始配置中添加/删除列的情况。
- 可以处理多个视图的列配置。
- 可以将列配置重置为初始配置。
- 可以在多个列状态配置文件之间切换。如果您需要额外的特殊列配置(例如,打印时),这很有用。
- 易于更改为另一个持久层。
背景
许多高级网格控件扩展了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** - 初始发布。