Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to Create a Custom Context Menu For QTableView



  • Can anyone please post a simple example for creating a custom context menu for a QTableView ? I'm new to Qt. I searched in Google. But couldn't find any examples out there.



  • Try the following:

    main.cpp

    #include <QtGui/QApplication>
    #include "widget.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget w;
        w.show();
        
        return a.exec&#40;&#41;;
    }
    

    widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QtGui/QWidget>
    
    class QTableView;
    
    class Widget : public QWidget
    {
        Q_OBJECT
        
    public:
        Widget(QWidget *parent = 0);
        ~Widget();
    
    public slots:
        void customMenuRequested(QPoint pos);
    
    private:
        QTableView *table;
    };
    
    #endif // WIDGET_H
    

    widget.cpp

    #include <QtGui>
    #include "widget.h"
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
    {
        QVBoxLayout *l=new QVBoxLayout(this);
        table=new QTableView(this);
        table->setContextMenuPolicy(Qt::CustomContextMenu);
        connect(table, SIGNAL(customContextMenuRequested(QPoint)), 
                SLOT(customMenuRequested(QPoint)));
        l->addWidget(table);
    }
    
    Widget::~Widget(){}
    
    void Widget::customMenuRequested(QPoint pos){
        QModelIndex index=table->indexAt(pos);
    
        QMenu *menu=new QMenu(this);
        menu->addAction(new QAction("Action 1", this));
        menu->addAction(new QAction("Action 2", this));
        menu->addAction(new QAction("Action 3", this));
        menu->popup(table->viewport()->mapToGlobal(pos));
    }
    

    Basically, we tell our QTableView that we want to use a custom context menu by calling the setContextMenuPolicy() method with the arguments Qt::CustomContextMenu. We then create a slot customMenuRequested() and connect it to the customContextMenuRequested() signal. This signal has a QPoint as its argument which is the position at which the request was made relative to the table. This position is useful because we can use it to discover which table cell was clicked on (if any) using the indexAt() method and also to position our menu correctly relative to the mouse.

    Hope this helps ;o)

    [edit: updated coding tags SGaist]



  • Thank you Jazzycamel for your post. That was really hepful.

    But as per your code, The customcontextmenu pops up for the Table View cells. But I want to create a customContextMenu for the TableView Header. (not for the QTableView Cells). Please Help...



  • Look into QHeaderView and repeat the steps to build a custom context menu for that. Then use your own QHeaderView for your QTableView. (i.e. QTableView::setHorizontalHeader() or something along these lines).



  • What have you tried so far? Did you tried using QHeaderView ?



  • Use the same JazzyCamel's example. In Widget.cpp

    Instead of,

    table->setContextMenuPolicy(Qt::CustomContextMenu);
    
    connect(table, SIGNAL(customContextMenuRequested(QPoint)),
    SLOT(customMenuRequested(QPoint)));
    

    Change it to

    table->horizontalHeader-> setContextMenuPolicy(Qt::CustomContextMenu);
    
    connect(table->horizontalHeader(), SIGNAL(customContextMenuRequested(QPoint)),
    SLOT(customMenuRequested(QPoint)));
    

    Hope you get it..

    [edit: updated coding tags SGaist]



  • Rochi got there just as I was finishing the following and is exactly right, as both QTableView and QHeaderView inherit QAbstractItemView the method is the same:

    widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QtGui/QWidget>
    
    class QStandardItemModel;
    class QTableView;
    
    class Widget : public QWidget
    {
        Q_OBJECT
        
    public:
        Widget(QWidget *parent = 0);
        ~Widget();
    
    public slots:
        void customMenuRequested(QPoint pos);
        void customHeaderMenuRequested(QPoint pos);
    
    private:
        QStandardItemModel *model;
        QTableView *table;
    };
    
    #endif // WIDGET_H
    

    widget.cpp

    #include <QtGui>
    #include "widget.h"
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
    {
        model=new QStandardItemModel(10,10,this);
    
        QVBoxLayout *l=new QVBoxLayout(this);
        table=new QTableView(this);
        table->setModel(model);
        table->setContextMenuPolicy(Qt::CustomContextMenu);
        connect(table, SIGNAL(customContextMenuRequested(QPoint)),
                SLOT(customMenuRequested(QPoint)));
    
        table->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
        connect(table->horizontalHeader(),
                SIGNAL(customContextMenuRequested(QPoint)),
                SLOT(customHeaderMenuRequested(QPoint)));
        l->addWidget(table);
    }
    
    Widget::~Widget()
    {    
    }
    
    void Widget::customMenuRequested(QPoint pos){
        QModelIndex index=table->indexAt(pos);
    
        QMenu *menu=new QMenu(this);
        menu->addAction(new QAction("Action 1", this));
        menu->addAction(new QAction("Action 2", this));
        menu->addAction(new QAction("Action 3", this));
        menu->popup(table->viewport()->mapToGlobal(pos));
    }
    
    void Widget::customHeaderMenuRequested(QPoint pos){
        int column=table->horizontalHeader()->logicalIndexAt(pos);
    
        QMenu *menu=new QMenu(this);
        menu->addAction(new QAction("Header Action 1", this));
        menu->addAction(new QAction("Header Action 2", this));
        menu->addAction(new QAction("Header Action 3", this));
        menu->popup(table->horizontalHeader()->viewport()->mapToGlobal(pos));
    }
    

    Hope this answers your question ;o)

    [edit: updated coding tags SGaist]



  • Jus a side note, creating a nemu on the heap every time the user right clicks is going to eat up a lot of memory in the long term. It's much more efficient to create it once and call popup on it when needed


Log in to reply