我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
目录
如果界面上需要显示不同的列表(主要是列头不同),有几种思路实现:
- 动态创建ListView,处理显示位置比较麻烦,还涉及到窗口缩放时的处理
- 静态创建多个,按需要显示隐藏,多个重叠控件的初始位置可以在初始化时设置一次
- 单个静态控件,难点是记录正确的列头宽度,本文就谈论这个问题
技术基础
保存列头
listView.Columns数组就是列头,保存下来即可
删除列头
listView.Columns.RemoveAt(3);
删除指定位置的列。
恢复列头
删除之后再添加即可。
奇怪的BUG:不能在多处添加或插入项
这个很头疼,其实是ColumnHeader对象不能复用,要先克隆,所以保存列头是的代码是这样的:
old_headers.Add(listView.Columns[3].Clone() as ColumnHeader);
不好意思,我的程序仍然会有随机的BUG发生…… 原因是虽然保存的时候用了Clone但是添加的时候没有,导致添加后保存的数据也被修改了(其实是指向同一个对象),于是再次打开窗口的时候会遇到列已经被绑定到列表框的问题。所以高级语言的对象(其实是引用)比C++的指针高级?
控件的Tag
所有控件包括控件的数据条目都有tag属性,可以用来绑定数据,tag是Object类型的,可以绑定任何数据结构。
强烈建议专门定义tag结构而不要直接使用string或者现成的对象,因为需要在tag里增加信息的情形是很多的。
本示例代码涉及到一个树和一个列表,相关信息记录在树节点的tag和列表的tag里。
处理逻辑
其实逻辑还是稍微有点复杂的:
- 如果ListView没有列,直接创建需要的列
- 如果ListView已经有列,符合需要,什么也不做
- 如果ListView已经有列,不符合需要,保存现有列头,然后检查是否存在已经保存的列头,有则恢复,没有则直接创建
示例代码
本示例代码的列表显示只有两种,同种类型的列头显示宽度会被记录,不会因为切换显示而改变。
//这两个是旧列头,隧道协议所需的列只有一个,其余则有很多
static List<ColumnHeader> columnHeaders_std = new List<ColumnHeader>();
static List<ColumnHeader> columnHeaders_tunnel = new List<ColumnHeader>();
//这个函数根据树节点来显示
static public bool ShowChannels(TreeNode deviceNode, ListView listView)
{
NodeTag? tag= deviceNode.Tag as NodeTag;//这个tag是要显示的新信息
if (null == tag) return false;
if(tag.nodeType!= NodeTag.NodeType.NODETYPE_DEVICE)return false;
listView.Items.Clear();
if (0 == listView.Columns.Count)
{//两种情形共有的三个列
listView.Columns.Add("序号");
listView.Columns.Add("Code");
listView.Columns.Add("Name");
}
//保存可变部分
string? old_code = (listView.Tag as NodeTag)?.protocolCode;//当前ListView的tag是旧信息
if (null != old_code)
{
List<ColumnHeader> old_headers;
if (ProtocolCode.isTunnel(old_code))
{
old_headers = columnHeaders_tunnel;
}
else
{
old_headers = columnHeaders_std;
}
old_headers.Clear();
while (listView.Columns.Count > 3)
{
old_headers.Add(listView.Columns[3].Clone() as ColumnHeader);//注意这里没有Clone会有随机BUG并且列头宽度会错误
listView.Columns.RemoveAt(3);
}
}
//恢复可变部分,如果还没有保存过,直接创建
if (ProtocolCode.isTunnel(tag.protocolCode))
{
if (columnHeaders_tunnel.Count > 0) listView.Columns.AddRange(columnHeaders_tunnel.ToArray());这里不对,也要Clone
else
{
listView.Columns.Add("paramCommand");
}
}
else
{
if (columnHeaders_std.Count > 0) listView.Columns.AddRange(columnHeaders_std.ToArray());这里不对,也要Clone
else
{
listView.Columns.Add("Type");
listView.Columns.Add("Addr");
listView.Columns.Add("function");
listView.Columns.Add("transfer");
listView.Columns.Add("Length");
listView.Columns.Add("process");
listView.Columns.Add("report");
}
}
......(这里显示列表数据)
listView.Tag = tag;//更新listview的tag
return true;
}
(这里是结束)