You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt自定义右键菜单位置异常:随机偏移至右下角固定

Qt自定义右键菜单位置异常问题

我给QLabelDragDrop(自定义标签类)添加了自定义右键菜单,其余功能正常,但每次右键点击时,菜单会随机出现在屏幕上,沿对角线移动至屏幕右下角后便固定在此位置。打印传入的QPoint对象,显示坐标并未出错。

相关代码

custom_menu.cpp

#include "custom_menu.h"
#include <iostream>

Menu::Menu(QWidget *parent) :
    QMenu(parent)
{
    QAction *action1 = addAction("Action1");
    connect(action1, &QAction::triggered, this, &Menu::onAction1Triggered);
}
void Menu::onAction1Triggered(){
    std::cout<<"Working";
}

void Menu::showMenu(const QPoint &pos)
{
    qDebug() << pos;
    exec(mapToGlobal(pos));
}

自定义标签类QLabelDragDrop

QLabelDragDrop::QLabelDragDrop(QWidget *parent) : QLabel(parent)
{
    setAcceptDrops(true);
    setMouseTracking(true);
}

void QLabelDragDrop::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        drag_start_position = event->pos();
    }
}
void QLabelDragDrop::mouseMoveEvent(QMouseEvent *event){
    {
        if (!(event->buttons() & Qt::LeftButton)) {
            return;
        }
        if ((event->pos() - drag_start_position).manhattanLength() < QApplication::startDragDistance()) {
            return;
        }
        QDrag *drag = new QDrag(this);
        QMimeData *mimeData = new QMimeData;
        mimeData->setImageData(this->pixmap().toImage());
        drag->setMimeData(mimeData);
        QPixmap pixmap(this->size());
        QPainter painter(&pixmap);
        painter.drawPixmap(this->rect(), this->grab());
        painter.end();
        drag->setPixmap(pixmap);
        //drag->setHotSpot(event->pos() - parentWidget()->pos() - this->pos());
        drag->setHotSpot(event->pos()); // - this->pos()
        drag->exec(Qt::MoveAction);
    }
}

自定义Frame类(标签的父控件)

custom_frame::custom_frame(QWidget *parent)
    : QFrame(parent)
{
    setAcceptDrops(true);
}

void custom_frame::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasImage()) {
        event->acceptProposedAction();
    }
}

void custom_frame::dropEvent(QDropEvent *event)
{
    if (event->mimeData()->hasImage()) {
        QLabel *label = qobject_cast<QLabel*>(event->source());
        if (label) {
            label->move(event->position().toPoint());
            event->setDropAction(Qt::MoveAction);
            event->accept();
            update();
        }

    }
}

void custom_frame::paintEvent(QPaintEvent* event) {
    QFrame::paintEvent(event);
    for (int i = 1; i<=label_count; i++){
        char c[] = "label_";
        QString num = QString::number(i);
        QString name = QString::fromUtf8(c, 6);
        QLabel* my_label = this->findChild<QLabel*>(name + num);
        QPainter painter(this);
        painter.setPen(QPen(Qt::black, 2));
        QPoint start = my_label->frameGeometry().center();
        QGroupBox* groupBox = this->findChild<QGroupBox*>("groupBox");
        QPoint end = groupBox->frameGeometry().center();
        painter.drawLine(start, end);
    }
}

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QObject::connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::Create_Device);
}

MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::Create_Device(){
    QLabelDragDrop *label = new QLabelDragDrop(ui->frame);
    label->setGeometry(QRect(200,20,80,40));
    ui->frame->label_count++;
    char c[] = "label_";
    QString num = QString::number(ui->frame->label_count);
    QString name = QString::fromUtf8(c, 6);
    QString obj_name = name+num;
    Menu *m_menu = new Menu;
    QPixmap pixmap("C:\\Users\\Farhan Ahmed\\Documents\\untitled\\router.png");
    QPixmap scaledPixmap = pixmap.scaled(QSize(70, 70), Qt::KeepAspectRatio, Qt::SmoothTransformation);    
    label->setObjectName(obj_name);
    //label->setText("New Label");
    label->setPixmap(scaledPixmap);
    label->setContextMenuPolicy(Qt::CustomContextMenu);
    label->setFixedSize(scaledPixmap.size());
    label->setToolTip(obj_name);
    label->setStatusTip(obj_name);
    bool success = connect(label, &QWidget::customContextMenuRequested, m_menu, &Menu::showMenu);
    Q_ASSERT(success);
    label->show();
    ui->frame->update();
}

问题分析

  • Menu父对象缺失:创建Menu时未指定父窗口(Menu *m_menu = new Menu;),导致Menu的父对象为nullptr,调用mapToGlobal时会以全局坐标系为基准,但传入的pos是QLabelDragDrop的局部坐标,转换逻辑错误。
  • 坐标转换对象错误:showMenu中用this->mapToGlobal(pos),而this是Menu对象,并非产生右键事件的QLabelDragDrop,所以无法正确将局部坐标转换为全局坐标。

修复方案

方案一:修正Menu父对象及坐标转换

  1. 在Create_Device中创建Menu时,将QLabelDragDrop作为父对象:
Menu *m_menu = new Menu(label);
  1. 修改Menu::showMenu方法,使用父窗口(QLabelDragDrop)的mapToGlobal转换坐标:
void Menu::showMenu(const QPoint &pos)
{
    qDebug() << pos;
    exec(parentWidget()->mapToGlobal(pos));
}

方案二:使用Lambda表达式处理坐标转换(无需修改Menu类)

在Create_Device中替换信号连接代码,直接在Lambda中完成正确的坐标转换:

bool success = connect(label, &QWidget::customContextMenuRequested, [label, m_menu](const QPoint& pos){
    m_menu->exec(label->mapToGlobal(pos));
});

两种方案都能保证右键菜单在点击位置正确弹出。

内容的提问来源于stack exchange,提问作者farhan jatt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 10:50:07