【问题标题】:How can I transform QTabWidget coordinates to its child's coordinates?如何将 QTabWidget 坐标转换为其子坐标?
【发布时间】:2026-02-15 01:00:02
【问题描述】:

我正在尝试在仅包含 QListWidgets 的 QTabWidget(列表)上生成右键菜单。我在下面得到一个菜单,单击标签栏高度的距离,这是预期的,因为上下文菜单已应用于 QTabWidget。

void onCustomContextMenuRequested(const QPoint& pos) {
    QListWidgetItem * item = ((QListWidget*)(lists->currentWidget()))->itemAt(pos);
    if (item) showContextMenu(item, QListWidget(lists->currentWidget()).viewport()->mapToGlobal(pos));
}
void showContextMenu(QListWidgetItem* item, const QPoint& globalPos) {
    QMenu menu;
    menu.addAction(item->text());
    menu.exec(globalPos);
}

我可以通过更改让菜单出现在鼠标上,同时仍然引用它下方约 100 像素的项目

QListWidget(lists->currentWidget()).viewport()->mapToGlobal(pos));

QListWidget(lists->currentWidget()).viewport()->mapToParent(mapToGlobal(pos)));

但我无法让菜单指向我正在单击的项目。我已经尝试在父坐标之间进行转换,但没有效果。

QPoint pos_temp = ((QListWidget*)(lists->currentWidget()))->viewport()->mapFromParent(pos);
if (item) showContextMenu(item, QListWidget(lists->currentWidget()).viewport()->mapToGlobal(pos_temp));

我也尝试过全局坐标,以及全局和父级的组合,但效果不佳。

那么我怎样才能获得右键菜单来引用我正在点击的项目呢?

【问题讨论】:

    标签: c++ qt qt5 c++14


    【解决方案1】:

    customContextMenuRequested 信号发送的位置是相对于建立连接的小部件而言的,在这种情况下,我假设它是主要小部件,因此当使用 QListWidgetitemAt() 时,它会抛出不足值,因为此方法等待相对于viewport() 的位置。在这些情况下,方法是将本地位置转换为全局位置,然后将该全局位置映射到最终小部件的本地位置。

    在下一部分中,我将展示一个示例。

    #include <QApplication>
    #include <QTabWidget>
    #include <QListWidget>
    #include <QVBoxLayout>
    #include <QMenu>
    
    class Widget: public QWidget{
        Q_OBJECT
        QTabWidget *lists;
    public:
        Widget(QWidget *parent=Q_NULLPTR):QWidget(parent){
            lists = new QTabWidget;
            setContextMenuPolicy(Qt::CustomContextMenu);
            connect(this, &Widget::customContextMenuRequested, this, &Widget::onCustomContextMenuRequested);
            auto layout = new QVBoxLayout(this);
            layout->addWidget(lists);
            for(int i=0; i<4; i++){
                auto list = new QListWidget;
                lists->addTab(list, QString("tab-%1").arg(i));
                for(int j=0; j<10; j++){
                    list->addItem(QString("item %1-%2").arg(i).arg(j));
                }
            }
    
        }
    private slots:
        void onCustomContextMenuRequested(const QPoint& pos){
            QPoint globalPos = mapToGlobal(pos);
            QListWidget *list = static_cast<QListWidget *>(lists->currentWidget());
            if(list){
                QPoint p = list->viewport()->mapFromGlobal(globalPos);
                QListWidgetItem *item = list->itemAt(p);
                if(item)
                    showContextMenu(item, globalPos);
            }
        }
    
        void showContextMenu(QListWidgetItem* item, const QPoint& globalPos) {
            QMenu menu;
            menu.addAction(item->text());
            menu.exec(globalPos);
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget w;
        w.show();
    
        return a.exec();
    }
    
    #include "main.moc"
    

    下面link是完整的例子。

    【讨论】:

    • 这在选项卡中唯一的小部件是列表时有效。如果我在列表上方添加一个按钮,则右键单击菜单会出现在鼠标上方按钮的距离附近,如果没有按钮,它将在该位置出现。菜单指的是它悬停的项目,而不是我单击的位置。此外,添加int tab_index = lists-&gt;tabBar()-&gt;tabAt(pos); if (tab_index!=-1) showListContextMenu(tab_index, globalPos); 在我添加按钮之前一直有效,然后当我右键单击选项卡时会产生一个类似的移位菜单,但菜单将指向我单击的位置。