Qt - перетаскивание с каркасом графического представления - PullRequest
0 голосов
/ 28 апреля 2010

Я пытаюсь сделать простой перетаскиваемый элемент, используя графический фреймворк. Вот код для того, что я сделал до сих пор:

Класс виджетов:

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

};

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    DragScene *scene = new DragScene();
    DragView *view = new DragView();
    QHBoxLayout *layout = new QHBoxLayout();

    DragItem *item = new DragItem();
    view->setAcceptDrops(true);
    scene->addItem(item);
    view->setScene(scene);
    layout->addWidget(view);
    this->setLayout(layout);

}

Widget::~Widget()
{
}

Класс DragView:

class DragView : public QGraphicsView
{
public:
    DragView(QWidget *parent = 0);
};

DragView::DragView(QWidget *parent) : QGraphicsView(parent)
{
    setRenderHints(QPainter::Antialiasing);
}

Класс DragScene:

class DragScene : public QGraphicsScene
{
public:
    DragScene(QObject* parent = 0);

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

DragScene::DragScene(QObject* parent) : QGraphicsScene(parent)
{
}

void DragScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event){
}

void DragScene::dropEvent(QGraphicsSceneDragDropEvent *event){
    qDebug() << event->pos();
    event->acceptProposedAction();
    DragItem *item = new DragItem();
    this->addItem(item);
    // item->setPos(event->pos()); before badgerr's tip
    item->setPos(event->scenePos());
}

Класс DragItem:

class DragItem : public QGraphicsItem
{
public:
    DragItem(QGraphicsItem *parent = 0);
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);

protected:
    void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};

DragItem::DragItem(QGraphicsItem *parent) : QGraphicsItem(parent)
{
    setFlag(QGraphicsItem::ItemIsMovable);
}

QRectF DragItem::boundingRect() const{
    const QPointF *p0 = new QPointF(-10,-10);
    const QPointF *p1 = new QPointF(10,10);
    return QRectF(*p0,*p1);
}

void DragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
    if(painter == 0)
        painter = new QPainter();
    painter->drawEllipse(QPoint(0,0),10,10);
}

void DragItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event){

}

void DragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
}

void DragItem::mousePressEvent(QGraphicsSceneMouseEvent *event){
    QMimeData* mime = new QMimeData();
    QDrag* drag = new QDrag(event->widget());
    drag->setMimeData(mime);
    drag->exec();
}

void DragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
}

main.cpp создает экземпляр виджета и показывает его. Когда я пытаюсь перетащить круг, приложение просто создает еще один круг поверх исходного, независимо от того, где я отпущу перетаскивание. qDebug () в dropEvent () DragScene показывает QPointF (0,0) каждый раз, когда заканчивается перетаскивание. Я с трудом пытаюсь понять, что именно я должен делать, какие классы я должен подклассить, какие методы нужно переопределить, чтобы эта работа работала. Документация не очень подробна. Я хотел бы знать, как заставить это работать, и если есть какой-то другой, более полный ресурс, чтобы узнать о платформе графического представления, кроме официальной документации (которая, между прочим, отлично, но было бы здорово, если бы была более подробная трактат на эту тему).

EDIT:

Следуя совету барсука, я заменил item-> pos () в DragScene :: dropEvent () на item-> scenePos (), теперь событие drop создает новый круг на сайте перетаскивания, который более или менее соответствует в розыске. Но исходный круг все еще находится на месте, и пока идет перетаскивание, элемент не следует за курсором мыши.

В документации QGraphicsSceneDragDropEvent говорится, что pos () должна возвращать позицию курсора относительно представления, отправляющего событие, которое, если я не ошибаюсь, не должно быть (0,0) все время. Weird.

Я прочитал в сообщении на форуме, что вы можете использовать QDrag :: setPixMap (), чтобы показать что-то во время перетаскивания, и в примерах я видел изображения, которые устанавливаются как растровые изображения, но как я могу сделать растровое изображение таким же, как графический элемент, который я должен перетаскивать?

1 Ответ

1 голос
/ 29 апреля 2010

Есть пример с Qt Assistant, называемый «Пример перетаскивания робота», который, похоже, использует метод QDrag, я не знаю, смотрели ли вы уже это.

edit : просто быстрое наблюдение, вы, кажется, создаете новый DragItem в своем DropEvent вместо использования mimeData () самого события, и так как ваш элемент рисует себя в 0,0 , это может объяснить, почему у вас есть новый, появляющийся в этой позиции, независимо от того, куда вы уронили DragItem.


Когда я писал нечто похожее на графическое перетаскивание, я делал это немного иначе. Может быть, это поможет вам:

Вместо использования материала QDrag я использовал только функции mousePressEvent, mouseReleaseEvent и mouseMoveEvent из QGraphicsItem. Нажатие / отпускание мыши устанавливает флаг, указывающий состояние перетаскивания, и перемещается, следуя процессу

  • вызову prepareGeometryChange ();
  • обновить границы QGraphicsItem (моя функция boundingRect () возвращает эти границы. Все границы моего графического элемента находятся в пространстве QGraphicsScene)
  • обновление вызовов ();

Затем в моей функции paint () я рисую фигуру с помощью boundingRect ().

Извините, у меня нет примера кода, которым я могу поделиться, я его подбью, если у меня будет время.

...