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

How to get the position of widgets in QTablewidget



  • Hello I have a QTableWidget, and I set some widgets in it.

    When I right-click that widget, I want to know which row it is in.

    I used the following code, but during my debugging, row is always 0. What's the matter?

    QComboBox* cb = new QComboBox(this);
    connect(cb, &QComboBox::customContextMenuRequested, [=](QPoint pos){ContextMenu(pos);});
    
    void EffectTable::ContextMenu(QPoint &pos)
    {
        QModelIndex index = ui->table->indexAt(pos);
        qint32 row = index.row();
    }
    


  • @MasterBlade You need to map pos from comboBox to the tableWidget (maybe it's better to map to the viewport) using

    QPoint QWidget::mapTo(const QWidget *parent, const QPoint &pos) const
    

    or mapToGlobal and then mapFromGlobal.



  • @Bonnie said in How to get the position of widgets in QTablewidget:

    @MasterBlade You need to map pos from comboBox to the tableWidget (maybe it's better to map to the viewport) using

    QPoint QWidget::mapTo(const QWidget *parent, const QPoint &pos) const
    

    or mapToGlobal and then mapFromGlobal.

    Thank you for the reply.

    I tried this

    QWidget* w = qobject_cast<QWidget*>(sender());
        QPoint p = mapTo(w, pos);
        QModelIndex index = ui->table->indexAt(p);
        qint32 row = index.row();
    

    But row is still 0. I replaced mapTo() with mapFrom(), same result.



  • @MasterBlade No, the mapTo should be called by the comboBox.
    Did you see the doc?
    The parent should be a parent of the calling widget.
    I think it should be

        QPoint p = w->mapTo(ui->table->viewport(), pos);
    

    If you are confused with that, you can try

    QPoint global = w->mapToGlobal(pos);
    QPoint p = ui->table->viewport()->mapFromGlobal(global);
    


  • @Bonnie The program crashed at QModelIndex index = ui->table->indexAt(p);

    QWidget* w = qobject_cast<QWidget*>(sender());
        QPoint p = w->mapTo(ui->table->viewport(), pos);
        QModelIndex index = ui->table->indexAt(p);
        qint32 row = index.row();
    

    Annotation 2020-05-09 235907.png



  • @MasterBlade Wow, I thought the viewport should be a parent of the cell widget. It's not?
    Then you should try the "global" ones.

    [EDITED]
    Is the sender widget set by setCellWidget?
    If it is, can you try that if you don't use viewport, will it crash? If not crash, what's the result?

    QPoint p = w->mapTo(ui->table, pos);
    


  • @Bonnie
    I used ui->table->setCellWidget(j, 2, cb); to setup the widget.

    After changing to QPoint p = w->mapTo(ui->table, pos);
    it still crashed with exactly the same error message.

    [EDIT]
    I tried

    QPoint global = w->mapToGlobal(pos);
    QPoint p = ui->table->mapFromGlobal(global);
    

    It didn't crash. But I'm having issues with QtCreator. It's not showing watchlist.
    But I'm sure row is a negative value because the program went into

    if (row < 0){
    //
    }
    


  • @MasterBlade Wait! I found that in your code the ContextMenu is not called as a slot.
    So the sender() should not be the comboBox...



  • @Bonnie It's a lambda function and should work.

    Actually I also connected the table with this function.

    connect(ui->table, &QTableWidget::customContextMenuRequested, [=](QPoint pos){ContextMenu(pos);});
    

    This is working alright. I can get the correct row number.



  • @MasterBlade But that's not the correct way to use sender()

    1. If EffectTable::ContextMenu is declared as a slot, use
    connect(cb, &QComboBox::customContextMenuRequested, this, &EffectTable::ContextMenu);
    
    1. If not , try this and don't do any mapping in EffectTable::ContextMenu, leave it same as in the top post
        connect(cb, &QComboBox::customContextMenuRequested, [=](QPoint pos){
            QWidget* w = qobject_cast<QWidget*>(sender());
            ContextMenu(w->mapTo(ui->table->viewport(), pos));
        });
    


  • @Bonnie

    You are correct. I output sender with

    QObject* obj = sender();
    qDebug() << obj;
    

    and got

    QObject(0x0)
    

    sender is not working in this case.



  • @Bonnie There is a compile error with ContextMenu(w->mapTo(ui->table->viewport(), pos));

    C:\Users\<...>\effecttable.cpp:132: error: non-const lvalue reference to type 'QPoint' cannot bind to a temporary of type 'QPoint'

    I changed it to

    QPoint p = w->mapTo(ui->table->viewport(), pos);
    ContextMenu(p);
    

    and it's running.

    But it again crashed with the same error message.



  • @Bonnie said in How to get the position of widgets in QTablewidget:

    connect(cb, &QComboBox::customContextMenuRequested, this, &EffectTable::ContextMenu);

    connect(cb, &QComboBox::customContextMenuRequested, this, &EffectTable::ContextMenu);

    has a link error.
    C:\Qt\5.15.0\msvc2019_64\include\QtCore\qobject.h:255: error: C2338: Signal and slot arguments are not compatible.



  • @Bonnie It's late at night in China and I need to take some sleep.
    Thank you so much for the help.
    I will answer your further responses tomorrow.



  • @MasterBlade I've tried myself. sender() is still 0x0.
    Seems not a good idea to use it in the lambda. We should use cb instead.
    Still in the lambda:

    QPoint p = cb->mapTo(ui->table, pos);
    ContextMenu(p);
    

    And no mapping in ContextMenu.
    I've tried, this works. ;)



  • @Bonnie Oh god this is working!
    Thank you so much!



  • @Bonnie Well there are still some minor problems.

    I have QComboBox and QPushbutton on the same row.

    Let's say the first row. Right-clicking the QPushbutton gives row# 0, but QComboBox gives 1.

    Also for the last row both give -1.

    They are linked the the same ContextMenu() function.



  • @MasterBlade I've tried again, to get the correct row, we need to map to the viewport, as I expected.
    So in the lambda

    QPoint p = cb->mapTo(ui->table->viewport(), pos);
    ContextMenu(p);
    

    I also tried to add a QPushButton, it works fine, too.
    How did you connect the button?
    Did you change cb to the button's pointer?



  • @Bonnie
    After adding viewport everything works perfect!
    I wish I could give you 100 thumbs up!!!


Log in to reply