Qt右键单击QListWidget打开上下文菜单并删除项目

23

我想知道如何在右键单击表格项时打开一个弹出菜单。在弹出菜单中应该提供一些操作,比如添加和删除,这将创建一个新行或删除所选行。

我是Qt世界的新手,如果有人能给我详细的说明(如果可能的话还包括代码),那我会非常感激他/她。

谢谢。

我的目标:仅在QListWidget区域,并且只有在单击项时,才会打开具有删除选项的菜单。


编辑:好的,我解决了与QListWidget和菜单相关的问题。现在需要完成以下任务:

如果您使用鼠标右键单击项目,然后单击“删除”,则该项目将被删除。

我的代码:


void ProvideContextMenu(const QPoint &); // MainWindow.h
// In MainWindow.cpp

ui->listFiles->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->listFiles, SIGNAL(customContextMenuRequested(const QPoint &)), 
        this, SLOT(ProvideContextMenu(const QPoint &)));

void MainWindow::ProvideContextMenu(const QPoint &pos)
{
    QPoint item = ui->listFiles->mapToGlobal(pos);
    QMenu submenu;
    submenu.addAction("ADD");
    submenu.addAction("Delete");
    QAction* rightClickItem = submenu.exec(item);
    if (rightClickItem && rightClickItem->text().contains("Delete") )
    {
        ui->listFiles->takeItem(ui->listFiles->indexAt(pos).row());
    }
}

编辑2: 好的,我解决了整个问题 :D。 我上传了我的代码,如果有人需要类似的东西,它可以帮助他/她。



阅读我的答案,了解如何正确使用 takeItem() 方法。 - t3ft3l--i
很酷,真的有效。 - ejectamenta
3个回答

32

首先,您需要创建一个用于打开上下文菜单的插槽:

void showContextMenu(const QPoint&);

在您的类的构造函数中,使用了QListWidget,将上下文菜单策略设置为自定义,并像这样连接QListWidget::customContextMenuRequested(QPoint)信号和showContextMenu()插槽:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    setupUi(this);

    listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(listWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
}

然后需要实现上下文菜单的打开:

void MainWindow::showContextMenu(const QPoint &pos)
{
    // Handle global position
    QPoint globalPos = listWidget->mapToGlobal(pos);

    // Create menu and insert some actions
    QMenu myMenu;
    myMenu.addAction("Insert", this, SLOT(addItem()));
    myMenu.addAction("Erase",  this, SLOT(eraseItem()));

    // Show context menu at handling position
    myMenu.exec(globalPos);
}

接下来,我们需要为添加和删除 QListWidget 元素创建插槽:

void MainWindow::eraseItem()
{
    // If multiple selection is on, we need to erase all selected items
    for (int i = 0; i < listWidget->selectedItems().size(); ++i) {
        // Get curent item on selected row
        QListWidgetItem *item = listWidget->takeItem(listWidget->currentRow());
        // And remove it
        delete item;
    }
}

正如您所看到的,我们迭代所有选定的项目(要设置多个选择模式,请使用setSelectionMode()方法),并通过自己删除它,因为文档中说:

从列表小部件中移除的项将不受Qt管理,需要手动删除。

添加一些项目更容易,我的解决方案是使用静态变量来存储不同项目标题,如下所示:

void MainWindow::addItem()
 {
        static int i = 0;
        listWidget->addItem(QString::number(++i));
 }

为了简化你的代码,请使用Qt5语法来处理信号和槽。它消除了创建中间槽的需要。

希望这能对你有所帮助。


应该使用 QObject 上的 deleteLater() 调用,而不是 delete - Dcow
谢谢你的帮助,这太棒了 :D。 - SDE
@Dcow QListWidgetItem没有继承QObject - t3ft3l--i

3

这比被接受的答案要简单得多。您不需要处理创建上下文菜单或光标位置等任何内容。使用Qt :: ActionsContextMenu而不是Qt :: CustomContextMenu,并直接将操作添加到小部件中:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    ui->setupUi(this);

    // you can create the actions here, or in designer
    auto actInsert = new QAction("Insert", this);
    auto actDelete = new QAction("Delete", this);

    // you can set up slot connections here or in designer
    connect(actInsert, SIGNAL(triggered()), this, SLOT(addItem()));
    connect(actDelete, SIGNAL(triggered()), this, SLOT(eraseItem()));

    // and this will take care of everything else:
    listWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
    listWidget->addActions({ actInsert, actDelete });

}

void MainWindow::addItem () {
    ...; // add an item
}

void MainWindow::eraseItem () {
    ...; // erase an item
}

除了addActions(我认为)之外的所有内容,也可以在设计师中完成。

或者,如果出于任何原因您不想添加实际的槽函数,您也可以在连接时使用lambda表达式完成所有操作:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    ui->setupUi(this);

    // you can create the actions here, or in designer
    auto actInsert = new QAction("Insert", this);
    auto actDelete = new QAction("Delete", this);

    connect(actInsert, &QAction::triggered, [=]() {
       ...; // add an item
    });

    connect(actDelete, &QAction::triggered, [=]() {
       ...; // erase an item
    });

    // and this will take care of everything else:
    listWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
    listWidget->addActions({ actInsert, actDelete });

}

信号/槽选项更有组织和灵活性,但lambda选项适用于短小的高度专业化的代码块(或绑定到不是槽的函数)。
这适用于任何小部件上的上下文菜单。此外,同一QAction可以在多个小部件上使用。

1
我尝试了这个解决方案的第一种方法,但它并没有起作用。在创建上下文菜单时可能缺少某些内容。你需要添加一个信号来响应contextMenu请求。 - Jules
哦不,我在代码中打错了一个字。策略应该是ActionsContextMenu。然后它就能自己工作了。现在正在修复。抱歉!@Jules - Jason C

0

我是 StackOverFlow 的新手,在使用 Qt6.4.0 中尝试 @t3ft3l--i 的删除项目解决方案时,发现在从 listWidget 中删除项目时, selectedItem() -> size() 会减少, 这会导致您无法删除每个已选择的项目。 由于需要 50 个声望来发表评论, 因此我将在此处发布我的代码作为参考。(我不是母语为英语的人,因此可能有些地方没有解释得很清楚)

QList<QListWidgetItem*> removed_items = listWidget->selectedItems(); 
for (QListWidgetItem* item: removed_items) 
{ 
    listWidget->takeItem(listWidget->row(item)); 
    delete item; 
}

目前你的回答不够清晰,请[编辑]以添加更多细节,帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接