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父对象及坐标转换
- 在
Create_Device中创建Menu时,将QLabelDragDrop作为父对象:
Menu *m_menu = new Menu(label);
- 修改
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
相关产品推荐
相关产品推荐

