wxListCtrl和wxListBox
wxListCtrl和wxListBox都是用于显示列表数据的控件,但它们之间有一些区别。
wxListCtrl通常用于显示复杂的表格数据,可以通过设置列来显示多个属性,还支持对列表项进行排序、编辑和选择。
wxListBox通常用于显示简单的单列文本数据,只能显示一个属性,不支持对列表项进行排序和编辑,但支持选择。
因此,如果你需要显示复杂的表格数据并对其进行排序、编辑和选择,应该使用wxListCtrl。如果你只需要显示简单的单列文本数据并支持选择,则可以使用wxListBox。
wxListCtrl 或 wxDataViewCtrl
wxListCtrl 和 wxDataViewCtrl 都是 wxWidgets 框架中的列表控件,它们的主要区别在于它们的数据模型和显示方式不同。
wxListCtrl 是一个基于 Win32 ListView 控件的封装,它使用简单的行列格式来显示数据,每个项目通常只有一列数据。它可以使用 wxLC_REPORT 样式来显示多列数据,但这些列通常只是简单的文本或图标。它的数据模型是基于一个二维数组,每个项目对应一个数组元素,这个数组称为“列表视图”。
相比之下,wxDataViewCtrl 更加灵活,它支持多列数据的显示和自定义单元格渲染方式。它的数据模型是基于 MVC(Model-View-Controller)模式,即将数据模型、视图和控制器分离,使得开发人员可以更加方便地管理和显示复杂的数据结构。在 wxDataViewCtrl 中,每个项目都可以包含多列数据,并且每个单元格可以使用自定义的渲染器来显示不同的内容。
总之,wxListCtrl 适用于简单的列表显示,而 wxDataViewCtrl 适用于更加复杂的数据结构和自定义渲染方式的显示。
Style
此类支持以下样式:
事件
wxEVT_LIST_ITEM_SELECTED事件
wxEVT_LIST_ITEM_SELECTED 是 wxWidgets 框架中的一个事件,它表示用户在列表控件(如 wxListCtrl 或 wxDataViewCtrl)中选择了一个或多个项目。当用户选择一个或多个项目时,该事件会被触发,并将相关信息(如选择的项目的索引)传递给事件处理程序。开发人员可以通过绑定 wxEVT_LIST_ITEM_SELECTED 事件处理程序来响应用户选择项目的操作,以便在用户选择项目时执行一些操作,例如更新相关的控件或执行一些计算。
Bind( wxEVT_LIST_ITEM_SELECTED, &PANE_LISTVIEW::OnItemSelected, this );
wxEVT_LIST_ITEM_FOCUSED事件
wxEVT_LIST_ITEM_FOCUSED 是 wxWidgets 框架中的一个事件,它表示用户在列表控件(如 wxListCtrl 或 wxDataViewCtrl)中焦点变化了,即用户将焦点从一个项目移动到另一个项目。当用户移动焦点时,该事件会被触发,并将相关信息(如获得焦点的项目的索引)传递给事件处理程序。开发人员可以通过绑定 wxEVT_LIST_ITEM_FOCUSED 事件处理程序来响应用户焦点变化的操作,以便在用户移动焦点时执行一些操作,例如更新相关的控件或执行一些计算。
Bind( wxEVT_LIST_ITEM_FOCUSED, &PANE_LISTVIEW::OnItemSelected, this );
wxEVT_LIST_ITEM_DESELECTED事件
wxEVT_LIST_ITEM_DESELECTED 是 wxWidgets 框架中的一个事件,它表示用户在列表控件(如 wxListCtrl 或 wxDataViewCtrl)中取消选择了一个或多个项目。当用户取消选择一个或多个项目时,该事件会被触发,并将相关信息(如取消选择的项目的索引)传递给事件处理程序。开发人员可以通过绑定 wxEVT_LIST_ITEM_DESELECTED 事件处理程序来响应用户取消选择项目的操作,以便在用户取消选择项目时执行一些操作,例如更新相关的控件或执行一些计算。
Bind( wxEVT_LIST_ITEM_DESELECTED, &PANE_LISTVIEW::OnItemDeselected, this );
void SEARCH_PANE_LISTVIEW::OnItemSelected( wxListEvent& aEvent )
{
CallAfter(
[&]()
{
std::vector<long> list;
GetSelectRowsList( list );
m_handler->SelectItems( list );
} );
aEvent.Skip();
}
void SEARCH_PANE_LISTVIEW::OnItemDeselected( wxListEvent& aEvent )
{
CallAfter(
[&]()
{
std::vector<long> list;
GetSelectRowsList( list );
m_handler->SelectItems( list );
} );
aEvent.Skip();
}
这段代码使用了一个函数对象 CallAfter ,该函数接受一个 lambda 表达式作为参数,该 lambda 表达式捕获了当前作用域中的所有变量并在后台线程中执行。 lambda 表达式中的代码首先创建一个 std::vector 类型的变量 list,然后调用 GetSelectRowsList 函数将选定行的列表存储到该变量中。最后,它调用 m_handler->SelectItems 函数,将选定行的列表作为参数传递给该函数。这段代码的目的是在后台线程中选择选定行的项目。
CallAfter()函数
CallAfter 是 wxWidgets 框架中的一个函数,而不是 C++ 本身的关键字。它的作用是将指定的函数或 lambda 表达式加入到消息队列中,以便在稍后的时间点在主线程中执行。这个函数通常用于在后台线程中执行某些操作后,更新用户界面。由于用户界面只能在主线程中更新,因此 CallAfter 函数允许我们在主线程中异步执行需要更新界面的操作。
在计算机编程中,异步执行指的是程序中的某个操作不会立即返回结果,而是在后台继续执行,同时程序可以继续执行其他操作。当操作完成后,程序会通知相关的回调函数或事件处理程序。
与之相反,同步执行是指程序中的某个操作会一直阻塞当前线程,直到该操作完成并返回结果,才会继续执行后面的代码。
在使用 CallAfter 函数时,异步执行的意思是将指定的函数或 lambda 表达式加入到消息队列中,以便在稍后的时间点在主线程中执行,而不会阻塞当前线程。
void _LISTVIEW::GetSelectRowsList( std::vector<long>& aSelectedList )
{
long idx = GetFirstSelected();
if( idx < 0 ) // Nothing selected
return;
aSelectedList.emplace_back( idx );
idx = GetNextSelected( idx );
while( idx >= 0 )
{
aSelectedList.emplace_back( idx );
idx = GetNextSelected( idx );
}
}
wxWidgets中的GetFirstSelected()函数什么意思
GetFirstSelected() 是 wxWidgets 框架中 wxListCtrl 类的一个成员函数,它用于获取列表控件中第一个被选中的项目的索引。如果列表控件中没有选中任何项目,则返回值为 -1。
使用 GetFirstSelected() 函数可以方便地获取列表控件中选中的项目,并且可以与其他成员函数(如 GetNextSelected())一起使用,遍历所有选中的项目。例如,可以使用以下代码来遍历列表控件中所有选中的项目:
c
Copy
int index = listCtrl->GetFirstSelected();
while (index != -1)
{
// 处理选中的项目
// …
index = listCtrl->GetNextSelected(index);
}
该代码首先获取第一个选中的项目的索引,然后在循环中处理该项目,并调用 GetNextSelected() 函数来获取下一个选中的项目的索引。当 GetNextSelected() 函数返回 -1 时,表示已经遍历完所有选中的项目。
wxEVT_LIST_ITEM_RIGHT_CLICK 事件
要在 wxListCtrl 控件中右键单击某个项目时触发事件,可以使用以下步骤:
绑定 wxEVT_LIST_ITEM_RIGHT_CLICK 事件处理程序到 wxListCtrl 控件上。例如:
listCtrl->Bind(wxEVT_LIST_ITEM_RIGHT_CLICK, &MyFrame::OnListItemRightClick, this);
在 wxEVT_LIST_ITEM_RIGHT_CLICK 事件处理程序中,获取右键单击的项目的索引。例如:
void MyFrame::OnListItemRightClick(wxListEvent& event)
{
int index = event.GetIndex();
// ...
}
根据项目的索引执行相应的操作。例如,可以显示上下文菜单或弹出窗口。
完整的代码示例如下:
void MyFrame::OnListItemRightClick(wxListEvent& event)
{
int index = event.GetIndex();
if (index != wxNOT_FOUND)
{
// 显示上下文菜单或弹出窗口
wxMenu menu;
menu.Append(wxID_COPY, "Copy");
menu.Append(wxID_CUT, "Cut");
menu.Append(wxID_PASTE, "Paste");
PopupMenu(&menu);
}
}
MyFrame::MyFrame()
{
// 创建 wxListCtrl 控件
listCtrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
// 绑定右键单击事件处理程序
listCtrl->Bind(wxEVT_LIST_ITEM_RIGHT_CLICK, &MyFrame::OnListItemRightClick, this);
}
使用案例
wxListCtrl中放21个item,每一行放两个item,每个item显示图标和名字,点击某个图标,该图标呈现响应状态并响应对应的事件
以下是使用wxListCtrl实现放置21个item,每一行放两个item,每个item显示图标和名字,点击某个图标,该图标呈现响应状态并响应对应的事件的代码:
cpp
Copy
// 定义图标的状态
enum IconState {
Normal,
Selected,
Focused
};
// 定义每个项目的数据结构
struct ItemData {
wxString name;
wxBitmap normalIcon;
wxBitmap selectedIcon;
IconState state; // 图标状态
};
// 创建列表控件
wxListCtrl* ComponentList = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);
ComponentList->InsertColumn(0, wxT("Name"));
ComponentList->InsertColumn(1, wxT("Name"));
// 创建项目数据
std::vector<ItemData> itemData = {
{ wxT("Item 1"), wxBitmap(wxT("icon1.png"), wxBITMAP_TYPE_PNG), wxBitmap(wxT("icon1_selected.png"), wxBITMAP_TYPE_PNG), Normal },
{ wxT("Item 2"), wxBitmap(wxT("icon2.png"), wxBITMAP_TYPE_PNG), wxBitmap(wxT("icon2_selected.png"), wxBITMAP_TYPE_PNG), Normal },
// ...
};
// 插入项目
for (int i = 0; i < itemData.size(); i += 2) {
int row = ComponentList->GetItemCount();
ComponentList->InsertItem(row, itemData[i].name, 0);
if ((i + 1) < itemData.size()) {
ComponentList->InsertItem(row, itemData[i + 1].name, 1);
}
}
// 设置图标
for (int i = 0; i < itemData.size(); i++) {
wxListItem item;
item.SetMask(wxLIST_MASK_IMAGE);
item.SetColumn(i % 2);
item.SetId(i / 2);
item.SetImage(itemData[i].normalIcon);
ComponentList->SetItem(item);
}
// 绑定事件处理函数
ComponentList->Bind(wxEVT_LIST_ITEM_SELECTED, [=](wxListEvent& event) {
int index = event.GetIndex();
int column = event.GetColumn();
if (column >= 0 && index >= 0) {
// 获取项目数据
ItemData& data = itemData[index * 2 + column];
// 更新图标状态
data.state = Selected;
wxListItem item;
item.SetMask(wxLIST_MASK_IMAGE);
item.SetColumn(column);
item.SetId(index);
item.SetImage(data.selectedIcon);
ComponentList->SetItem(item);
// 处理事件
wxLogMessage(wxT("Selected: %s"), data.name);
}
});
ComponentList->Bind(wxEVT_LIST_ITEM_DESELECTED, [=](wxListEvent& event) {
int index = event.GetIndex();
int column = event.GetColumn();
if (column >= 0 && index >= 0) {
// 获取项目数据
ItemData& data = itemData[index * 2 + column];
// 更新图标状态
data.state = Normal;
wxListItem item;
item.SetMask(wxLIST_MASK_IMAGE);
item.SetColumn(column);
item.SetId(index);
item.SetImage(data.normalIcon);
ComponentList->SetItem(item);
// 处理事件
wxLogMessage(wxT("Deselected: %s"), data.name);
}
});
// 创建组合框架并添加控件
wxStaticBoxSizer* CompGroupLayout = new wxStaticBoxSizer(wxVERTICAL, this, wxT("Components"));
CompGroupLayout->Add(ComponentList, 1, wxEXPAND | wxALL, 5);
SetSizerAndFit(CompGroupLayout);
在这个例子中,我们定义了一个IconState枚举用于表示图标的状态,以及一个ItemData结构体用于存储每个项目的数据。然后我们创建了一个列表控件,并插入了两列。接着,我们创建了一个包含21个项目数据的数组,并使用循环插入了这些项目到列表中。同时,我们也使用循环设置了每个项目的图标。接下来,我们绑定了wxEVT_LIST_ITEM_SELECTED和wxEVT_LIST_ITEM_DESELECTED事件,并在事件处理函数中更新了所选项目的图标状态,并输出对应的事件信息。
值得注意的是,在本例中我们使用了wxLC_SINGLE_SEL样式来设置列表控件的选择模式为单选模式。这意味着用户只能选择一个项目。如果你希望用户可以选择多个项目,请使用wxLC_MULTIPLE_SEL样式。