setContextMenuPolicy(Qt::CustomContextMenu)。customContextMenuRequested(const QPoint&) 信號。indexAt(pos) 獲取點擊項模型索引。QMenu、添加 QAction、連接觸發槽。exec(mapToGlobal(pos)) 彈出選單。
// MyListView.h
class MyListView : public QListView {
Q_OBJECT
public:
explicit MyListView(QWidget* parent = nullptr);
protected:
void contextMenuEvent(QContextMenuEvent* event) override; // 或用信號槽
};
// MyListView.cpp
MyListView::MyListView(QWidget* parent) : QListView(parent) {
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &QListView::customContextMenuRequested, this, &MyListView::showContextMenu);
setModel(new QStringListModel({"Item 1", "Item 2", "Item 3"}, this));
}
void MyListView::showContextMenu(const QPoint& pos) {
QModelIndex idx = indexAt(pos);
if (!idx.isValid()) return; // 點擊空白處不顯示
QMenu menu(this);
QAction* actDelete = menu.addAction("刪除");
QAction* actEdit = menu.addAction("編輯");
connect(actDelete, &QAction::triggered, [this, idx](){
QStringListModel* m = qobject_cast(model());
QStringList list = m->stringList();
list.removeAt(idx.row());
m->setStringList(list);
});
connect(actEdit, &QAction::triggered, [this, idx](){
bool ok;
QString text = QInputDialog::getText(this, "編輯", "新內容:", QLineEdit::Normal, idx.data().toString(), &ok);
if (ok && !text.isEmpty()) {
QStringListModel* m = qobject_cast(model());
QStringList list = m->stringList();
list[idx.row()] = text;
m->setStringList(list);
}
});
menu.exec(viewport()->mapToGlobal(pos));
}
class MyModel : public QAbstractListModel {
QVector items;
public:
enum Roles { NameRole = Qt::UserRole + 1, IconRole };
QVariant data(const QModelIndex& index, int role) const override {
if (!index.isValid()) return {};
const auto& item = items[index.row()];
if (role == NameRole) return item.name;
if (role == IconRole) return item.icon;
return {};
}
QHash roleNames() const override {
return {{NameRole, "name"}, {IconRole, "icon"}};
}
// insertRows, removeRows, setData 等增刪改實作...
};
QML/Delegate 中即可用 model.name、model.icon 綁定。
examples/widgets/itemviews/listview