为什么QGraphicsProxyWidget放入QGraphicsView后无法正确调整大小? [英] Why QGraphicsProxyWidget does not resize properly after dropping into QGraphicsView?

查看:283
本文介绍了为什么QGraphicsProxyWidget放入QGraphicsView后无法正确调整大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 QListWidget 和一个 QGraphicsView 都被子类化以覆盖其某些成员.我准备了一个最小的可验证示例来显示我的问题.

QListWidget 中,我可以拖放由 QTableWidget 表示的特定字段,并将它们拖放到 QGraphicsView 中,以便执行此操作我正在使用如下所示的 QGraphicsProxyWidget 方法.

重要的是要提到,绿色的 QGraphicsRectItem 用于在 QTableWidget 周围移动以及调整其尺寸.

问题:从 QListWidget 拖动不是问题.但是放入 QGraphicsView 是一个问题,因为如您所见, QGraphicsRectItem 就在 QTableWidget 的顶部.

可以在主题,并遇到了

I have a QListWidget and a QGraphicsView both subclassed to overwrite some of their members. I prepared a minimal verifiable example showing the problem I have.

From the QListWidget I can drag and drop specific field represented by a QTableWidget and drop them into a QGraphicsView and in order to do that I am using a QGraphicsProxyWidget approach as shown below.

It is important to mention that the green QGraphicsRectItem it is used to move around the QTableWidget as well as adjusting its dimension.

The problem: dragging from the QListWidget is not a problem. But dropping into QGraphicsView is a problem because as you see the QGraphicsRectItem is right on top of the QTableWidget.

The minimal verifiable example can be found here and below for completeness:

However as soon as I touch the QSizeGrip bottom right of the QGraphicsProxyWidget the QGraphicsRectItem adjust itself with the dimension of the QTableWidgetItem:

Below the minimal verifiable example:

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsView>

#include "scene.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    Scene *mScene;

};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    mScene = new Scene;
    ui->graphicsView->setRenderHint(QPainter::Antialiasing);
    ui->graphicsView->setScene(mScene);
    ui->graphicsView->show();
}

MainWindow::~MainWindow()
{
    delete ui;
}

optionlist.h

#ifndef OPTIONLIST_H
#define OPTIONLIST_H


#include <QListWidget>

class OptionList : public QListWidget {
public:
  OptionList(QWidget *parent = nullptr);

protected:
  void startDrag(Qt::DropActions supportedActions);
};

#endif // OPTIONLIST_H

optionlist.cpp

#include "optionlist.h"

#include <QDrag>

OptionList::OptionList(QWidget *parent) : QListWidget(parent) {

  setDragEnabled(true);
  setDropIndicatorShown(true);
  setSelectionMode(QAbstractItemView::SingleSelection);
  setDefaultDropAction(Qt::CopyAction);
  setViewMode(QListView::ListMode);

  for (const QString &workspaceTree : {"Images", "Path", "Connection"}) {
    QListWidgetItem *img = new QListWidgetItem;
    img->setText(workspaceTree);
    img->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable |
                   Qt::ItemIsDragEnabled);
    addItem(img);
  }
}

void OptionList::startDrag(Qt::DropActions supportedActions) {
  if (supportedActions & Qt::CopyAction) {
    QList<QListWidgetItem *> m_items = selectedItems();
    if (m_items.isEmpty())
      return;
    QMimeData *data = mimeData(m_items);
    QDrag *drag = new QDrag(this);
    QPixmap pixmap("/home/Icon_icon.png");
    drag->setPixmap(pixmap);
    drag->setMimeData(data);
    drag->setHotSpot(pixmap.rect().center());
    drag->exec(Qt::CopyAction);
  } else
    QListWidget::startDrag(supportedActions);
}

customtablewidget.h

#ifndef CUSTOMTABLEWIDGET_H
#define CUSTOMTABLEWIDGET_H

#include <QTableWidget>
#include <QResizeEvent>

class CustomTableWidget : public QTableWidget
{
    Q_OBJECT

public:
    CustomTableWidget(QWidget *parent = Q_NULLPTR) : QTableWidget(parent){}
    void resizeEvent(QResizeEvent *event);

signals:
    void sizeChanged();

};

#endif // CUSTOMTABLEWIDGET_H

customtablewidget.cpp

#include "customtablewidget.h"

void CustomTableWidget::resizeEvent(QResizeEvent *event)
{
    QTableWidget::resizeEvent(event);

    emit sizeChanged();
}

And finally where the problem is:

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

#include "scene.h"
#include "customtablewidget.h"

#include <QGraphicsSceneDragDropEvent>
#include <QMimeData>
#include <QTableWidget>
#include <QGraphicsProxyWidget>
#include <QVBoxLayout>
#include <QMetaEnum>
#include <QEvent>
#include <QSizeGrip>

Scene::Scene(QObject *parent)
{
    setBackgroundBrush(Qt::lightGray);

}

void Scene::dragEnterEvent(QGraphicsSceneDragDropEvent *event) {
  if (event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
    event->setAccepted(true);
}

void Scene::dragMoveEvent(QGraphicsSceneDragDropEvent *event) {
  if (event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
    event->setAccepted(true);
}

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);
            CustomTableWidget *wgt = new CustomTableWidget;
            QGraphicsRectItem *proxyControl = addRect(initPos.x(), initPos.y(), wgt->width(), 20, QPen(Qt::black), QBrush(Qt::darkGreen)); // widget->width() works properly here because of the resize(layout->sizeHint()) that we have used inside it
            QSizeGrip * sizeGrip = new QSizeGrip(wgt);
            QHBoxLayout *layout = new QHBoxLayout(wgt);
            //QGraphicsRectItem *proxyControl = addRect(initPos.x(), initPos.y(), wgt->width(), 20, QPen(Qt::black), QBrush(Qt::darkGreen));

            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));
            });

            proxyControl->setPos(initPos.x(), initPos.y());
            proxyControl->setFlag(QGraphicsItem::ItemIsMovable, true);
            proxyControl->setFlag(QGraphicsItem::ItemIsSelectable, true);

            wgt->setColumnCount(2);
            wgt->setRowCount(2);
            for (int ridx = 0 ; ridx < wgt->rowCount() ; ridx++ )
            {
                for (int cidx = 0 ; cidx < wgt->columnCount() ; cidx++)
                {
                    QTableWidgetItem* item = new QTableWidgetItem();
                    item->setText(QString("%1").arg(ridx));
                    wgt->setItem(ridx,cidx,item);
                }
            }
            QGraphicsProxyWidget * const proxy = addWidget(wgt);
            // In my case the rectangular graphics item is supposed to be above my widget so the position of the widget is shifted along the Y axis based on the height of the rectangle of that graphics item
            proxy->setPos(initPos.x(), initPos.y()+proxyControl->rect().height());
            proxy->setParentItem(proxyControl);
        }
    }
}

I did extensive research about this topic and came across this other post which was very useful because made me solve the resizing issue inside the QGraphicsView but it didn't make me solve the drop problem of the widget inside the QGraphicsView.

The post I mentioned proceed to subclass the widget desired and add an additional signals called sizeChanged(); and that is what I did.

I additionally moved the following statement after AND before the QSizeGrip declaration:

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

But it didn't cause any change and I still have the bug.

Thanks for pointing in the right direction for solving this problem.

解决方案

Cause

You create proxyControl giving wgt->width() as a width:

QGraphicsRectItem *proxyControl = addRect(initPos.x(), initPos.y(), wgt->width(), 20, QPen(Qt::black), QBrush(Qt::darkGreen));

However, at that time wgt does not have its final geometry.

Solution

Setup proxyControl after you are done with wgt.

Example

Here is an example I have written for you to demonstrate how the proposed solution could be implemented. Change your dropEvent like this:

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));
        }
    }
}

Note: Use QGraphicsSceneDragDropEvent::scenePos() to properly position the dropped item.

Result

The proposed change gives you the desired result right away:

这篇关于为什么QGraphicsProxyWidget放入QGraphicsView后无法正确调整大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆