如何在鼠标正下方的 QGraphicsView 上正确放置小部件?

Posted

技术标签:

【中文标题】如何在鼠标正下方的 QGraphicsView 上正确放置小部件?【英文标题】:How to properly drop a widget on a QGraphicsView right under the mouse? 【发布时间】:2020-10-18 18:42:16 【问题描述】:

Following my previous post 我一直在尝试使用QGraphicsView 解决定位问题。

QListWidget 拖动一个小部件并放入QGraphicsView 后,它会到处跳转。

问题在另一个用户的帮助下,我一直在尝试解决以下问题: 只要将小部件拖入QGraphicsView 并放下。它只是在随机位置,必须注意检索它。这种行为对用户不友好,有时需要花费一些时间才能找到小部件。

代码下方:

scene.h

#ifndef SCENE_H
#define SCENE_H

#include <QGraphicsScene>

class Scene : public QGraphicsScene

public:
    Scene(QObject *parent = nullptr);

protected:
  void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
  void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
  void dropEvent(QGraphicsSceneDragDropEvent *event);
;

#endif // SCENE_H

scene.cpp

void Scene::dropEvent(QGraphicsSceneDragDropEvent *event)

    QByteArray encoded =
            event->mimeData()->data("application/x-qabstractitemmodeldatalist");
    QDataStream stream(&encoded, QIODevice::ReadOnly);

    QStringList rosTables;
    QString newString;

    while (!stream.atEnd()) 
        int row, col;
        QMap<int, QVariant> roleDataMap;
        stream >> row >> col >> roleDataMap;
        rosTables << roleDataMap[Qt::DisplayRole].toString();
    

    for (const QString &tableType : rosTables) 
        if (tableType == "Images") 
            QPoint initPos(0, 0);
            auto *wgt = new CustomTableWidget;
            auto *proxyControl = addRect(0, 0, 0, 0, QPen(Qt::black),
                                         QBrush(Qt::darkGreen));
            auto *sizeGrip = new QSizeGrip(wgt);
            auto *layout = new QHBoxLayout(wgt);

            layout->setContentsMargins(0, 0, 0, 0);
            layout->addWidget(sizeGrip, 0, Qt::AlignRight | Qt::AlignBottom);

            connect(wgt, &CustomTableWidget::sizeChanged, [wgt, proxyControl]()
                proxyControl->setRect(wgt->geometry().adjusted(-10, -10, 10, 10));
            );

            wgt->setColumnCount(2);
            wgt->setRowCount(2);

            for (int ridx = 0; ridx < wgt->rowCount(); ridx++) 
                for (int cidx = 0; cidx < wgt->columnCount(); cidx++) 
                    auto *item = new QTableWidgetItem();

                    item->setText(QString("%1").arg(ridx));
                    wgt->setItem(ridx,cidx,item);
                
            

            auto *const proxy = addWidget(wgt);


            proxy->setPos(initPos.x(), initPos.y()
                          + proxyControl->rect().height());
            proxy->setParentItem(proxyControl);

            proxyControl->setPos(initPos.x(), initPos.y());
            proxyControl->setFlag(QGraphicsItem::ItemIsMovable, true);
            proxyControl->setFlag(QGraphicsItem::ItemIsSelectable, true);
            proxyControl->setRect(wgt->geometry().adjusted(-10, -10, 10, 10));
        
    

到目前为止解决问题的方法:

现在QGraphicsScene 已被子类化以重新编写鼠标事件,特别是在这种情况下,注意dropEvent(QGraphicsSceneDragDropEvent *event) 因为它是负责“查看小部件”的函数

进行了多次试验和错误,并尝试在同一功能中添加以下部分:

for (const QString &tableType : rosTables) 
    if (tableType == "Images") 
        QPoint initPos(event->scenePos()); // <-- Tried this but no change 
        auto *wgt = new CustomTableWidget;
        auto *proxyControl = addRect(0, 0, 0, 0, QPen(Qt::black),
                                     QBrush(Qt::darkGreen));
        auto *sizeGrip = new QSizeGrip(wgt);
        auto *layout = new QHBoxLayout(wgt);

尝试的另一件事是提供QPointevent-&gt;scenePos().toPoint() 被认为适合目标,但不幸的是,这也没有解决问题:

for (const QString &tableType : rosTables) 
    if (tableType == "Images") 
        QPoint initPos(event->scenePos().toPoint()); // <-- Tried this too but no change
        auto *wgt = new CustomTableWidget;
        auto *proxyControl = addRect(0, 0, 0, 0, QPen(Qt::black),
                                     QBrush(Qt::darkGreen));
        auto *sizeGrip = new QSizeGrip(wgt);
        auto *layout = new QHBoxLayout(wgt);
 

如果有人知道问题可能是什么,请提供有关如何解决问题的指导。

【问题讨论】:

【参考方案1】:

    proxy-&gt;setPos(initPos.x(), initPos.y() + proxyControl-&gt;rect().height()); 更改为proxy-&gt;setPos(10, 10);

    设置场景矩形:

     Scene::Scene(QObject *parent) :
         QGraphicsScene(parent)
     
         setBackgroundBrush(Qt::lightGray);
         setSceneRect(0, 0, 1000, 1000);
     
    

    设置视图对齐方式,例如在MainWindow.cpp

     ui->graphicsView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    

【讨论】:

以上是关于如何在鼠标正下方的 QGraphicsView 上正确放置小部件?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 QMainWindow 鼠标点击位置传递给 QGraphicsView

如何通过鼠标单击在 QGraphicsView 中选择位置并添加项目?

如何识别 QGraphicsView 鼠标移动事件?

如何在Qgraphicsview上使用QPainter绘图

怎么在QGraphicsView上实现鼠标移动事件

如何在 QGraphicsView 中启用平移和缩放