gpt4 book ai didi

c++ - 用鼠标移动 QGraphicsRectItem

转载 作者:太空狗 更新时间:2023-10-29 20:56:51 26 4
gpt4 key购买 nike

我试图在将 QGraphicsRectItem 添加到场景后移动它。它会移动,但与鼠标指针有一定的偏移量。我认为它只是将鼠标指针位置添加到其原始位置。我不知道如何解决这个问题。

这是我的代码:

class ucFilter : public QGraphicsItem {

std::shared_ptr<QGraphicsRectItem> m_rect;
std::shared_ptr<QGraphicsTextItem> m_text;
std::shared_ptr<QString> m_name;
std::shared_ptr<QPointF> m_pos;
QGraphicsItem* selectedItem;

bool m_mouseGrabbed;
public:
static const int default_x = 80, default_y=40;
ucFilter::ucFilter(QString &name, QPointF &pos){
m_name = shared_ptr<QString>(new QString(name));
m_pos = shared_ptr<QPointF>(new QPointF(pos));
m_rect = shared_ptr<QGraphicsRectItem>( new QGraphicsRectItem(pos.x()-default_x, pos.y()-default_y, 2*default_x, 2*default_y ));


m_text = shared_ptr<QGraphicsTextItem>( new QGraphicsTextItem(name));

m_text->setPos(pos.x() - m_text->boundingRect().width()/2, pos.y()- 30);
selectedItem = NULL;
m_mouseGrabbed = false;
}

QGraphicsRectItem* getRect() { return m_rect.get(); }
QGraphicsTextItem* getText() { return m_text.get(); }
QString* getName() { return m_name.get(); }
QPointF* getPos() { return m_pos.get(); }

void setPos(QPointF newPos) { m_pos->setX(newPos.x()); m_pos->setY(newPos.y()); }

QRectF ucFilter::boundingRect() const
{
return m_rect->boundingRect();
}

void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget);
//QBrush brush(

if (!m_mouseGrabbed){ grabMouse(); m_mouseGrabbed = true; }

}

void mousePressEvent(QGraphicsSceneMouseEvent *event){
selectedItem = this;
QGraphicsItem::mousePressEvent(event);
}

void mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
selectedItem = NULL;
QGraphicsItem::mouseReleaseEvent(event);
}

void mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if(NULL != selectedItem){
m_text->setPos(event->pos());
m_rect->setPos(event->pos());
}
QGraphicsItem::mouseMoveEvent(event);
}

};

在场景dropEvent中创建ucFilter对象:

void cGraphicsScene::dropEvent(QGraphicsSceneDragDropEvent * event){

QTreeView* source = static_cast<QTreeView*>(event->source());

string name = event->mimeData()->text().toUtf8().constData();
if(0 == name.length()){
event->acceptProposedAction();
return ; // nothing to do anymore
}
QPointF pos = event->scenePos ();

shared_ptr<ucFilter> newFilter = shared_ptr<ucFilter>(new ucFilter(event->mimeData()->text(),event->scenePos ()));
m_filters.push_back(newFilter);
this->addItem(newFilter->getRect());
this->addItem(newFilter->getText());

this->addItem(newFilter.get()); // also add the item to grab mouse events

event->acceptProposedAction();
}

问题出在哪里?这是我实际看到的屏幕截图:enter image description here

我想在鼠标所在的位置绘制矩形..

最佳答案

您有几个问题:

  1. 使用共享指针来保存所有内容是完全没有根据的。场景充当项目的容器 - 就像 QObject 是对象的容器一样。

  2. ucFilter 没有 child 。它包含指向其他项目的指针,但这是不必要的。基础项目本身可以是一个矩形,它可以将文本作为子项。这样您就不需要以特殊方式处理定位。

  3. ucFilter 可以移动。不要自己重新实现该功能。

  4. 当您通过引用传递事物时,将它们作为 const 引用传递,除非您打算将修改后的值传递出去。如果您希望更改函数体内的值,您可以改为按值传递。

  5. 当您拖动项目时,鼠标已经被捕获。

让我们从ucFilter 项开始。它真的很简单,可以做你需要的一切。请注意,m_text 由值保存,并成为矩形父项的子项。

// https://github.com/KubaO/stackoverflown/tree/master/questions/graphics-item-drop-32574576
#include <QtWidgets>

class ucFilter : public QGraphicsRectItem {
QGraphicsTextItem m_text;
public:
ucFilter(const QString &name, const QPointF &pos, QGraphicsItem * parent = 0) :
QGraphicsRectItem(parent),
m_text(this)
{
static const QRect defaultRect(0, 0, 160, 80);
setPos(pos);
setRect(QRect(-defaultRect.topLeft()/2, defaultRect.size()));
setFlags(QGraphicsItem::ItemIsMovable);
setName(name);
}
void setName(const QString & text) {
m_text.setPlainText(text);
m_text.setPos(-m_text.boundingRect().width()/2, -30);
}
QString name() const {
return m_text.toPlainText();
}
};

因为我们是从一个方便的小部件(QListWidget)中删除的,所以我们需要从 application/x-qabstractitemmodeldatalist mime 类型中解码文本:

const char * kMimeType = "application/x-qabstractitemmodeldatalist";

QVariant decode(const QMimeData* data, Qt::ItemDataRole role = Qt::DisplayRole) {
auto buf = data->data(kMimeType);
QDataStream stream(&buf, QIODevice::ReadOnly);
while (!stream.atEnd()) {
int row, col;
QMap<int, QVariant> map;
stream >> row >> col >> map;
if (map.contains(role)) return map[role];
}
return QVariant();
}

场景在拖动进入时立即创建一个项目,并在拖动过程中移动该项目。

项目的所有权保留在场景中:我们不需要删除任何项目,除非我们想明确地将它们从场景中删除。 m_dragItem 用于引用当前拖动的项目,只需将其移动并在完成放置后将其添加到 m_filters。如果拖动离开场景(或被中止),项目就会从场景中简单地删除。

class cGraphicsScene : public QGraphicsScene {
QList<ucFilter*> m_filters;
ucFilter* m_dragItem;
public:
cGraphicsScene(QObject * parent = 0) : QGraphicsScene(parent), m_dragItem(nullptr) {}
void dragEnterEvent(QGraphicsSceneDragDropEvent * event) Q_DECL_OVERRIDE {
if (!event->mimeData()->hasFormat(kMimeType)) return;
auto name = decode(event->mimeData()).toString();
if (name.isEmpty()) return;
QScopedPointer<ucFilter> filter(new ucFilter(name, event->scenePos()));
addItem(m_dragItem = filter.take());
event->acceptProposedAction();
}
void dragMoveEvent(QGraphicsSceneDragDropEvent * event) Q_DECL_OVERRIDE {
if (!m_dragItem) return;
m_dragItem->setPos(event->scenePos());
event->acceptProposedAction();
}
void dropEvent(QGraphicsSceneDragDropEvent * event) Q_DECL_OVERRIDE {
if (!m_dragItem) return;
m_dragItem->setPos(event->scenePos());
m_filters << m_dragItem;
event->acceptProposedAction();
}
void dragLeaveEvent(QGraphicsSceneDragDropEvent * event) Q_DECL_OVERRIDE {
delete m_dragItem;
m_dragItem = nullptr;
event->acceptProposedAction();
}
};

测试工具非常简单:我们的场景、一个显示它的 View ,以及一个包含两个项目的列表,您可以将它们拖到场景中。

int main(int argc, char ** argv) {
QApplication app{argc, argv};
QWidget w;
cGraphicsScene scene;
QGraphicsView view(&scene);
QListWidget list;
QHBoxLayout l(&w);
l.addWidget(&view);
l.addWidget(&list);

list.setFixedWidth(120);
list.addItem("Item1");
list.addItem("Item2");
list.setDragDropMode(QAbstractItemView::DragOnly);
view.setAcceptDrops(true);

w.resize(500, 300);
w.show();
return app.exec();
}

您可以将项目从右侧的列表拖到左侧的场景中。您还可以移动场景中的项目,以重新定位它们。

关于c++ - 用鼠标移动 QGraphicsRectItem,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32574576/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com