Solved 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 thenmapFromGlobal
. -
@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 thenmapFromGlobal
.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?
Theparent
should be a parent of the calling widget.
I think it should beQPoint 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();
-
@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 bysetCellWidget
?
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 triedQPoint 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 intoif (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()
- If
EffectTable::ContextMenu
is declared as a slot, use
connect(cb, &QComboBox::customContextMenuRequested, this, &EffectTable::ContextMenu);
- 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)); });
- If
-
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 usecb
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 lambdaQPoint 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 changecb
to the button's pointer? -
@Bonnie
After adding viewport everything works perfect!
I wish I could give you 100 thumbs up!!!