问题描述
我有一个QListWidget
和QGraphicsView
都被子类化以覆盖其某些成员。
我准备了一个最小的可验证示例来显示我的问题。
我可以从QListWidget
拖放由QTableWidget
表示的特定字段,并将它们拖放到QGraphicsView
中,为此,我正在使用QGraphicsProxyWidget
如下所示。
重要的是要提到绿色的QGraphicsRectItem
用于在QTableWidget
周围移动并调整其尺寸。
问题:从QListWidget
拖动不是问题。但是进入QGraphicsView
是一个问题,因为您看到QGraphicsRectItem
就在QTableWidget
的上方。
为了完整起见,可以在here及以下找到最小的可验证示例:
但是,当我触摸QSizegrip
的右下角QGraphicsProxyWidget
时,QGraphicsRectItem
会根据QTableWidgetItem
的尺寸进行自我调整:
下面是最小的可验证示例:
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;
}
选项列表。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();
}
最后是问题所在:
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(),QBrush(Qt::darkGreen));
layout->setContentsMargins(0,0);
layout->addWidget(sizegrip,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);
}
}
}
我对this主题进行了广泛的研究,发现this other post很有用,因为它使我解决了QGraphicsView
内部的大小调整问题,但并没有解决我的问题QGraphicsView
内的小部件的问题。
我提到的帖子继续对所需的小部件进行子类化,并添加一个名为sizeChanged();
的附加信号,这就是我所做的。
我还在QSizegrip
声明的AND后面移动了以下语句:
connect(wgt,proxyControl](){
proxyControl->setRect(wgt->geometry().adjusted(-10,10));
});
但是它没有引起任何变化,我仍然有错误。
感谢您指出正确的方向来解决此问题。
解决方法
原因
您创建proxyControl
并以wgt->width()
作为宽度:
QGraphicsRectItem *proxyControl = addRect(initPos.x(),initPos.y(),wgt->width(),20,QPen(Qt::black),QBrush(Qt::darkGreen));
但是,那时wgt
没有最终的几何形状。
解决方案
设置proxyControl
之后,您完成了wgt
。
示例
这是我为您写的一个示例,以演示如何实现建议的解决方案。像这样更改您的dropEvent
:
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,QBrush(Qt::darkGreen));
auto *sizeGrip = new QSizeGrip(wgt);
auto *layout = new QHBoxLayout(wgt);
layout->setContentsMargins(0,0);
layout->addWidget(sizeGrip,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));
}
}
}
注意:使用QGraphicsSceneDragDropEvent::scenePos()
正确放置放置的物品。
结果
建议的更改会立即为您提供所需的结果: