【问题标题】:Qt RightClick on QListWidget Opens Contextmenu and Delete ItemQt RightClick on QListWidget 打开上下文菜单并删除项目
【发布时间】:2021-07-01 22:34:10
【问题描述】:

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

我是 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());
    }
}

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

【问题讨论】:

  • 阅读我的答案以正确使用takeItem() 方法
  • 酷,真的好用

标签: c++ qt


【解决方案1】:

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

void showContextMenu(const QPoint&);

在您的类的构造函数中,它使用QListWidgetset context menu policy 来自定义和连接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() 方法)并自行删除它,因为docs 这么说

从列表小部件中删除的项目将不会由 Qt 管理,并且将 需要手动删除。

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

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

为了简化您的代码,请使用Qt5 sytax 来表示信号和插槽。它消除了创建中间槽的需要。

希望对你有帮助。

【讨论】:

  • 而不是delete 应该使用deleteLater() 调用QObject
  • 感谢您的帮助,这很棒:D。
  • @Dcow QListWidgetItem 不继承 QObject
【解决方案2】:

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

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(我认为)之外的所有内容都可以在Designer中完成。

或者,如果您出于某种原因不想添加实际的槽函数,您也可以在连接时在 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 可以用于多个小部件。

【讨论】:

  • 我尝试了此解决方案的第一种方法,但它不起作用。在上下文菜单的创建中应该缺少一些东西。您需要添加一个信号来响应 contextMenu 请求。
  • 哦,不,我在代码中打错了字。它应该是策略的 ActionsContextMenu。然后它会自己工作。现在修复。对不起! @朱尔斯
猜你喜欢
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多