PropertyGrid(属性控件)是一种表格控件,用来组织和显示“属性”。“属性”是“名字”和“数值”的组合,“名字”一般是字符串,“数值”可以是各种类型,整数、浮点数、字符串、颜色等。
属性控件可以以层次化的结构组织和显示多个“属性”,如下图所示。
创建控件
wxPropertyGrid的构造函数同其他wxWidgets控件相同,
wxPropertyGrid::wxPropertyGrid (
wxWindow * parent, /// 父窗口
wxWindowID id = wxID_ANY, /// 窗口ID
const wxPoint & pos = wxDefaultPosition, /// 窗口位置
const wxSize & size = wxDefaultSize, /// 窗口尺寸
long style = wxPG_DEFAULT_STYLE, /// 控件风格
const wxString & name = wxPropertyGridNameStr /// 控件名称
)
可用的PropertyGrid控件风格与其含义如下:
标志 | 含义 |
---|---|
wxPG_AUTO_SORT | 自动排序 |
wxPG_HIDE_CATEGORIES | 隐藏层次(如果有层次的话) |
wxPG_ALPHABETIC_MODE | 既自动排序,又隐藏层次 |
wxPG_BOLD_MODIFIED | 粗体显示改动的数据 |
wxPG_SPLITTER_AUTO_CENTER | 列分割线自动居中 |
wxPG_TOOLTIPS | 显示完整提示(需设置wxUSE_TOOLTIPS才能起效) |
wxPG_STATIC_SPLITTER | 使用户不能调整列分割线 |
wxPG_STATIC_LAYOUT | 使用户不能调整布局 |
wxPG_TOOLBAR | 显示工具栏(wxPropertyGridManager 中有效) |
wxPG_DESCRIPTION | 显示描述区(wxPropertyGridManager 中有效) |
wxPG_NO_INTERNAL_BORDER | 不显示内部边线(wxPropertyGridManager中有效) |
此外,在创建控件后,还可以通过调用SetExtraStyle函数为PropertyGrid控件设置扩展风格。PropertyGrid可用的扩展风格如下表所示:
注:PropertyGrid的扩展风格均以wxPG_EX_xxx表示,必须通过SetExtraStyle()函数设置.
标志 | 含义 |
---|---|
wxPG_EX_INIT_NOCAT | 快速启用 wxPG_HIDE_CATEGORIES模式 |
wxPG_EX_NO_FLAT_TOOLBAR | wxPropertyGridManager 不使用平面风格工具栏 |
wxPG_EX_MODE_BUTTONS | 在工具栏显示“目录”、“排序”按钮 |
wxPG_EX_HELP_AS_TOOLTIPS | 将帮助文本按提示方式显示(不再在状态栏显示) |
wxPG_EX_NATIVE_DOUBLE_BUFFERING | 使用本地双缓冲 |
wxPG_EX_AUTO_UNSPECIFIED_VALUES | 允许用户将属性的数值设置为非规定值 |
wxPG_EX_HIDE_PAGE_BUTTONS | 在工具栏上隐藏页面选择按钮 |
wxPG_EX_MULTIPLE_SELECTION | 允许用户选择多个属性(按SHIFT键同时选择,或者鼠标左键拖动) |
wxPG_EX_NO_TOOLBAR_DIVIDER | 工具栏不显示分割线(Windows下有效) |
wxPG_EX_TOOLBAR_SEPARATOR | 工具栏下显示分割线 |
下面是创建PropertyGrid的示例代码。
wxPropertyGrid * ctrl = new wxPropertyGrid(this, ctrlID, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE);
ctrl->SetExtraStyle(wxPG_EX_HELP_AS_TOOLTIPS);
增加属性
用户可以通过Append、AppendIn、Insert等函数来添加属性。其中,最常用的是Append函数。
该函数将新属性添加至控件的结尾处,函数声明如下:
wxPGProperty* wxPropertyGridInterface::Append(
wxPGProperty * newProperty ///新属性。
)
wxWidgets已经提供了一些预定义类型的wxPGProperty,包括字符串、数字、字体、颜色等等。
下面例子创建了一些常见的属性。
代码如下:
// 字符串属性
pg->Append(new wxStringProperty("StringProperty", wxPG_LABEL, "test_name"));
// 整数属性
pg->Append(new wxIntProperty("IntProperty", wxPG_LABEL, 12345678));
// 浮点数属性
pg->Append( new wxFloatProperty("FloatProperty", wxPG_LABEL, 12345.678) );
// 逻辑属性
pg->Append( new wxBoolProperty("BoolProperty", wxPG_LABEL, false) );
// 长字符串属性(用一个单独的对话框编辑)
pg->Append( new wxLongStringProperty("LongStringProperty", wxPG_LABEL, "This is much longer string than the " "first one. Edit it by clicking the button."));
// 目录属性
pg->Append( new wxDirProperty("DirProperty", wxPG_LABEL, ::wxGetUserHome()) );
// 字符列表属性
pg->Append( new wxArrayStringProperty("Label of ArrayStringProperty", "NameOfArrayStringProp"));
// 文件属性.
pg->Append( new wxFileProperty("FileProperty", wxPG_LABEL, wxEmptyString) );
// 设置文件属性的参数.
pg->SetPropertyAttribute("FileProperty", wxPG_FILE_WILDCARD, "All files (*.*)|*.*" );
有两种类型的属性需要特别说明一下:
EnumProperty(枚举属性)
枚举属性可以通过下拉菜单选择若干选项之一。
作为选项的数据可以利用wxArrayString类型、字符串数组类型或者wxPGChoices类型。
示例如下:
/// 方法1,通过wxArrayString
wxArrayString items;
items.Add(wxT("item_value_1"));
items.Add(wxT("item_value_2"));
items.Add(wxT("item_value_3"));
pg->Append(new wxEnumProperty(wxT("item_name"), wxPG_LABEL, items));
/// 方法2,通过字符串数组
const wxChar* items[] = {
wxT("item_value_1"), wxT("item_value_2"), wxT("item_value_3"), NULL
};
pg->Append(new wxEnumProperty("item_name", wxPG_LABEL, items));
/// 方法3,通过wxPGChoices
wxPGChoices chs;
chs.Add("item_value_1");
chs.Add("item_value_2");
chs.Add("item_value_3");
pg->Append(new wxEnumProperty("item_name", wxPG_LABEL, chs));
此外,EnumProperty还支持“标签”和“数值”分离。即除指定可选的标签外,为每个标签另外指定整数数据,通过数据来设定当前选择的标签。
示例如下:
///通过wxPGChoices,也可通过其他两种办法设置.
wxPGChoices chs;
chs.Add("item_value_1", 11);
chs.Add("item_value_2", 22);
chs.Add("item_value_3", 33);
wxPGProperty * prop = pg->Append(new wxEnumProperty("item_name", wxPG_LABEL, chs));
prop->SetValue(11);
wxString value = prop->GetValueAsString(); // value = "item_value_1"
FlagProperty(标志属性)
标志属性与枚举属性类似,同样包含多个选项,可以实现多个选项的组合。运行效果如下图所示。
示例如下:
///通过wxPGChoices,也可通过其他两种办法设置.
wxPGChoices chs;
chs.Add("flag_1");
chs.Add("flag_2");
chs.Add("flag_3");
wxPGProperty * prop = pg->Append(new wxFlagsProperty("item_name", wxPG_LABEL, chs));
删除属性
删除属性的常用方法包括:
- DeleteProperty():删除指定属性及其子属性。
- Clear():删除所有属性。
示例代码如下:
wxPGProperty * prop1 = pg->Append(new wxStringProperty("Property1", wxPG_LABEL));
wxPGProperty * prop2 = pg->Append(new wxStringProperty("Property2", wxPG_LABEL));
wxPGProperty * prop3 = pg->Append(new wxStringProperty("Property3", wxPG_LABEL));
/// 删除属性1
pg->DeleteProperty("Property1");
/// 删除属性2
pg->DeleteProperty(prop2);
/// 删除所有属性.
pg->Clear();
获取指定属性
通过PropertyGrid的成员函数GetProperty或GetPropertyByName可以获取指定的属性。
GetProperty或GetPropertyByName可以通过属性名称来获取指定的属性。
示例代码如下:
pg->Append(new wxStringProperty("StringProperty", wxPG_LABEL, "test_name"));
/// 获取前面添加的名为"StringProperty"的属性.
wxPGProperty * prop = pg->GetProperty("StringProperty");
……
获取属性的内容
通常,用户可以通过两种方法获取属性的数值:
- 调用wxPGProperty的GetValue成员函数。
- 调用wxPropertyGrid的GetPropertyValue成员函数。
上述函数均返回wxVariant类型的结果,需要将wxVariant转换为用户所需的类型,如整数、浮点数、字符串等。
……
wxPGProperty * prop1 = pg->Append(new wxStringProperty("name", wxPG_LABEL, "test value"));
wxString valStr;
wxAny value1 = prop1->GetValue();
valStr = value1.As<wxString>();
wxAny value2 = pg->GetPropertyValue("name");
valStr = value1.As<wxString>();
wxAny value3 = pg->GetPropertyValue(prop1);
valStr = value1.As<wxString>();
……
PropertyGrid还提供了一些获取属性数值的函数,省去用户进行类型转换。如:
- GetPropertyValueAsArrayInt
- GetPropertyValueAsArrayString
- GetPropertyValueAsBool
- GetPropertyValueAsDateTime
- GetPropertyValueAsDouble
- GetPropertyValueAsInt
- ……
修改属性的数值
通常,用户可以通过两类方法设置属性的数值:
(1)SetValue方法
- 调用wxPGProperty的SetValue成员函数。
- 调用wxPropertyGrid的SetPropertyValue成员函数。
上述函数均进行了重载,以接受多种类型的输入参数。示例代码如下:
……
wxPGProperty * prop1 = pg->Append(new wxStringProperty("name", wxPG_LABEL));
prop1->SetValue("value set 1");
wxString valStr = prop1->GetValueAsString();
pg->SetPropertyValue("name", "value set 2");
valStr = pg->GetPropertyValueAsString("name");
……
(2)ChangeValue方法
还可以使用wxPropertyGrid的ChangePropertyValue成员函数改变指定属性的数值。
注意:ChangePropertyValue函数用法和SetPropertyValue函数相同,但效果不同。ChangePropertyValue会(a)执行输入验证过程,(b)发送属性改变事件,而SetPropertyValue则不会。
属性的层次化
可以将属性组织成类似“文件夹”的方式(树状层次结构)。下面是一个层次化属性的运行效果:
上述效果可以通过2种途径实现:
(1)通过wxPGPropertyGrid的AppendIn成员函数或Insert成员函数增加层次化的属性
wxPropertyGrid的AppendIn()和Insert()函数可以为指定属性添加子属性,形成树状结构的属性层次。该方法使用相对复杂,但更为灵活。
AppendIn函数将新的属性添加至父属性的结尾。
`
wxPGProperty* wxPropertyGridInterface::AppendIn(
wxPGPropArg parent, ///父属性.
wxPGProperty * newProperty ///新属性。
)
Insert函数将新的属性添加至父属性的指定位置。
wxPGProperty* wxPropertyGridInterface::Insert(
wxPGPropArg parent, ///父属性.
int index, ///添加位置. 0表示开始位置,-1表示结尾位置,。
wxPGProperty * newProperty ///新属性。
)
为实现前面的效果,代码如下:
/// 1.添加一个“Group 1”属性
wxPGProperty * group1 = pg->Append(new wxPropertyCategory("Group 1"));
/// 为“Group 1”属性添加子属性
pg->AppendIn(group1, new wxStringProperty("Name1_1"));
pg->AppendIn(group1, new wxStringProperty("Name1_2"));
pg->AppendIn(group1, new wxStringProperty("Name1_3"));
/// 2.添加一个“Group 2”属性
wxPGProperty * group2 = pg->Append(new wxPropertyCategory("Group 2"));
/// 为“Group 2”属性添加子属性
pg->AppendIn(group2, new wxStringProperty("Name2_1"));
pg->AppendIn(group2, new wxStringProperty("Name2_2"));
pg->AppendIn(group2, new wxStringProperty("Name2_3"));
(2)通过wxPropertyCatagory来实现。
通过增加wxPropertyCategory类型的属性,可以为属性进行分类,实现简单的属性层次化。
在PropertyGrid中增加wxPropertyCatagory属性,该属性将自动成为当前目录属性,后续添加的属性将作为该属性的子属性,直至添加另一个wxPropertyCatagory属性。
代码如下:
/// 1.添加一个“Group 1”目录
pg->Append(new wxPropertyCategory("Group 1"));
/// 后续的属性都将添加至“Group 1”目录
pg->Append(new wxStringProperty("Name1_1"));
pg->Append(new wxStringProperty("Name1_2"));
pg->Append(new wxStringProperty("Name1_3"));
/// 2.添加一个“Group 2”目录
pg->Append(new wxPropertyCategory("Group 2"));
/// 后续的属性都将添加至“Group 1”目录
pg->Append(new wxStringProperty("Name2_1"));
pg->Append(new wxStringProperty("Name2_2"));
pg->Append(new wxStringProperty("Name2_3"));
遍历属性
PropertyGrid控件提供了类似STL迭代器(iterator)的属性遍历方法。
PropertyGrid控件提供的迭代器有两类:
- wxPropertyGridIterator
- wxPropertyGridConstIterator(const类型迭代器)
PropertyGrid迭代器的主要成员函数如下:
- Next():向后迭代,等价于operator ++();
- Prev():向前迭代,等价于operator –();
- AtEnd():判断是否迭代结束。
ProperyGrid通过GetIterator函数来获取迭代器.
该函数的声明如下:
wxPropertyGridIterator wxPropertyGridInterface::GetIterator(
int flags = wxPG_ITERATE_DEFAULT,
wxPGProperty * firstProp = NULL
)
wxPropertyGridIterator wxPropertyGridInterface::GetIterator(
int flags,
int startPos
)
其中, flags标志了获取的迭代器的位置和类型。
其通常使用方法如下:
for (wxPropertyGridIterator it = ctrl->GetIterator(); ! it.AtEnd(); it++)
{
wxPGProperty * prop = * it;
…
}
通过设置GetIterator的参数,可以获得不同类型的迭代器。
/// 针对可见的属性,获取结尾位置的迭代器.
wxPropertyGridIterator it1 = ctrl->GetIterator(wxPG_ITERATE_VISIBLE, wxBOTTOM);
…
/// 针对所有属性,获取结尾位置的迭代器.
wxPropertyGridIterator it2 = ctrl->GetIterator(wxPG_ITERATE_ALL, wxBOTTOM);
…
常用消息
PropertyGrid控件消息处理函数类型是:
void XXX(wxPropertyGridEvent & event)
PropertyGrid控件的常见消息及其含义如下:
消息 | 含义 |
---|---|
EVT_PG_SELECTED (id, func) | 属性被选中 |
EVT_PG_CHANGED(id, func) | 属性已经发生改变 |
EVT_PG_CHANGING(id, func) | 属性打算发生改变。可以利用wxPropertyGridEvent::GetValue()先观察修改后的值,(可否决,即利用 wxPropertyGridEvent::Veto()防止发生改变) |
EVT_PG_RIGHT_CLICK(id, func) | 属性被鼠标右击 |
EVT_PG_DOUBLE_CLICK(id, func) | 属性被鼠标双击 |
EVT_PG_ITEM_COLLAPSED(id, func) | 属性收起子属性 |
EVT_PG_ITEM_EXPANDED(id, func) | 属性展开子属性 |
EVT_PG_COL_BEGIN_DRAG(id, func) | 用户开始改变列尺寸(可否决) |
EVT_PG_COL_DRAGGING, (id, func) | 用户正在改变列尺寸 |
EVT_PG_COL_END_DRAG(id, func) | 用户完成改变列尺寸 |
EVT_PG_LABEL_EDIT_BEGIN(id, func) | 用户开始编辑属性标签(可否决) |
EVT_PG_LABEL_EDIT_ENDING(id, func) | 用户结束编辑属性标签(可否决) |
EVT_PG_HIGHLIGHTED(id, func) | 鼠标经过属性。 |