为什么QGraphicsProxyWidget放入QGraphicsView后无法正确调整大小? [英] Why QGraphicsProxyWidget does not resize properly after dropping into 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屋!