Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt RightClick on QListWidget Opens Contextmenu and Delete Item

Tags:

I want to know how can I open a popup menu when I right click on the table items. In the popup menu some actions like add and delete should be given, which will create a new row or delete the selected row.

I am a new in the Qt world, so if anybody can give me the full details (with code if possible) then I will be really grateful towards him/her.

Thank you.

My goal: Only in the area of QListWidget and only if you click on an item, the menu with Delete will be opened.


Edit : Ok I solved the problem with the QListWidget and the menu. Now the following must be accomplished:

If you click on an item with the right mouse button, and then click Delete, then the item will be deleted.

My code:


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 : Ok I solved the whole problem :D. I uploaded my code, if somebody needs something like that it can help him/her.

like image 952
SDE Avatar asked Jul 13 '15 12:07

SDE


2 Answers

Firstly you need to create slot for opening context menu:

void showContextMenu(const QPoint&);

At constructor of your class, which used QListWidget, set context menu policy to custom and connect QListWidget::customContextMenuRequested(QPoint) signal and showContextMenu() slot like this:

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

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

Then need to realize context menu opening:

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);
}

After this we need to realize slots for adding and removing QListWidget elements:

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;
    }
}

As you can see we iterate all selected items (for set multiple selection mode use setSelectionMode() method) and delete it by ourself, because docs says that

Items removed from a list widget will not be managed by Qt, and will need to be deleted manually.

Adding some items is easier, my solution with static variable for different item caption looks like:

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

To simplify your code use Qt5 sytax for signals and slots. It eliminates the need to create intermediate slots.

I hope it helps to you.

like image 125
t3ft3l--i Avatar answered Sep 30 '22 15:09

t3ft3l--i


It's much simpler than the accepted answer. You don't need to deal with creating a context menu or cursor positions or any of that. Instead of Qt::CustomContextMenu, use Qt::ActionsContextMenu and just add your actions directly to the widget:

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
}

Everything above except addActions (I think) can also be done in Designer.

Alternatively, if you don't want to add actual slot functions for whatever reason, you can do everything in a lambda on connect, too:

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 });

}

The signal/slot option is more organized and flexible, but the lambda option is good for short highly specialized bits of code (or binding to functions that aren't slots).

This works for context menus on any widget. Also, the same QAction can be used on multiple widgets.

like image 39
Jason C Avatar answered Sep 30 '22 15:09

Jason C