在 Qt 中遍歷容器並刪除元素是經典陷阱:迭代器失效、索引錯亂。對於 QListWidget 批量刪除選中項目,正確做法是反覆取第一個選中項目直到無選中,而非正向遍歷。
// ❌ 錯誤 1:正向遍歷索引刪除
for (int i = 0; i < listWidget->count(); ++i) {
if (listWidget->item(i)->isSelected())
delete listWidget->takeItem(i); // 索引錯亂,漏刪/越界
}
// ❌ 錯誤 2:使用迭代器
for (auto it = listWidget->selectedItems().begin(); it != selectedItems().end(); ++it) {
delete *it; // selectedItems() 返回臨時副本,迭代器無效
}
// 正確:批量移動選中項到另一個 QListWidget
while (ui->lwg_Source->selectedItems().size() > 0) {
QListWidgetItem* sel = ui->lwg_Source->selectedItems().at(0);
if (sel) {
int row = ui->lwg_Source->row(sel);
sel = ui->lwg_Source->takeItem(row); // 從源列表取出,所有權轉移
ui->lwg_Dest->addItem(sel); // 加入目標列表,無需 delete/new
}
}
selectedItems() 每次調用返回當前選中項的新列表 (值語義副本)at(0) 第一個,避開索引變化問題takeItem(row) 從列表移除並返回項指針,不釋放記憶體QListWidgetItem* 可直接 addItem 到另一列表,所有權轉移
// 通用批量刪除:從同一列表移除選中項
void removeSelectedItems(QListWidget* list) {
while (list->selectedItems().size() > 0) {
QListWidgetItem* item = list->takeItem(list->row(list->selectedItems().at(0)));
delete item; // 真正刪除需手動 delete
}
}
// 批量移動:源列表選中項 → 目標列表
void moveSelectedItems(QListWidget* src, QListWidget* dst) {
while (src->selectedItems().size() > 0) {
QListWidgetItem* item = src->takeItem(src->row(src->selectedItems().at(0)));
dst->addItem(item);
}
}
// 批量複製:源列表選中項 → 目標列表 (深拷貝)
void copySelectedItems(QListWidget* src, QListWidget* dst) {
for (QListWidgetItem* item : src->selectedItems()) {
dst->addItem(new QListWidgetItem(*item)); // 複製構造
}
}
| 方法 | 行為 | 記憶體 | 適用場景 |
|---|---|---|---|
| takeItem(row) | 移除並返回項指針 | 調用者擁有,需 delete 或 addItem | 移動/刪除 |
| removeItemWidget(item) | 移除項上的自定義控件 | 不影響項本身 | 自定義委託清理 |
| clear() | 移除所有項並 delete | 內部自動 delete | 清空列表 |
| selectedItems() | 返回選中項指針列表 (副本) | 不轉移所有權 | 只讀遍歷/批量操作判斷 |
// 設置選擇模式 (在構造函數或 UI 設計器中)
ui->lwg_Source->setSelectionMode(QAbstractItemView::ExtendedSelection); // Ctrl/Shift 多選
// 或
ui->lwg_Source->setSelectionMode(QAbstractItemView::MultiSelection); // 點擊即多選
Qt 容器批量刪除鐵律:
while (container.size() > 0) { takeFirst() } 模式QListWidget::takeItem() 返回項所有權,配合 addItem() 實現零拷貝移動delete此模式同樣適用於 QList、QVector 等順序容器的批量清理操作。