как панорамировать изображения в QGraphicsView

в настоящее время я могу загрузить свое изображение в сцену grahpics, а затем снова в QGraphicsViewer.

Я могу реализовать функцию масштабирования, выделив колесо QEvent::, а затем вызвав функцию graphicsviews scale ().

однако я не могу понять, как заставить функциональность панорамирования работать. Я в основном хочу определить, когда мышь нажала на изображение, а затем переместите изображение влево, вправо, вверх или вниз вместе с мышь.

на данный момент у меня в основном есть класс MouseFilter, который обнаруживает события и делает разные вещи в зависимости от типа события. Я прикрепил этот прослушиватель к объекту QGraphicsView

3 ответов


QGraphicsView имеет встроенную поддержку панорамирования мыши. Установить правильно DragMode и он справится с остальными. Для этого вам нужно включить полосы прокрутки.


если кому-то интересно, как это сделать самостоятельно, это на самом деле довольно просто. Вот код из моего приложения:

class ImageView : public QGraphicsView
{
public:
    ImageView(QWidget *parent);
    ~ImageView();

private:
    virtual void mouseMoveEvent(QMouseEvent *event);
    virtual void mousePressEvent(QMouseEvent *event);
    virtual void mouseReleaseEvent(QMouseEvent *event);

    bool _pan;
    int _panStartX, _panStartY;
};

вам нужно сохранить начальную позицию перетаскивания, например, вот так (я использовал правую кнопку):

void ImageView::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::RightButton)
    {
        _pan = true;
        _panStartX = event->x();
        _panStartY = event->y();
        setCursor(Qt::ClosedHandCursor);
        event->accept();
        return;
    }
    event->ignore();
}

кроме того, вам нужно очистить флаг и восстановить курсор после того, как кнопка отпущена:

void ImageView::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::RightButton)
    {
        _pan = false;
        setCursor(Qt::ArrowCursor);
        event->accept();
        return;
    }
    event->ignore();
}

чтобы фактически управлять перетаскиванием, вам нужно переопределить событие перемещения мыши. Дать QGraphicsView наследует QAbstractScrollArea и его полосы прокрутки легко доступны. Вам также необходимо обновить положение панорамирования:

void ImageView::mouseMoveEvent(QMouseEvent *event)
{
    if (_pan)
    {
        horizontalScrollBar()->setValue(horizontalScrollBar()->value() - (event->x() - _panStartX));
        verticalScrollBar()->setValue(verticalScrollBar()->value() - (event->y() - _panStartY));
        _panStartX = event->x();
        _panStartY = event->y();
        event->accept();
        return;
    }
    event->ignore();

}

решение neuviemeporte требует подкласса QGraphicsView.

другая рабочая реализация перетаскивания может быть получена без подкласса представления с помощью eventFilter. Если вам не нужно настраивать другое поведение QGraphicsView, этот метод сэкономит вам некоторую работу.

предположим, что ваша логика GUI поддерживается подклассом QMainWindow, а QGraphicsView & QGraphicsScene объявлены как частные члены этого подкласса. Тебе придется реализовать функцию eventFilter следующим образом:

bool MyMainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (obj == scene && event->type() == Event::GraphicsSceneMouseMove)
    {
        QGraphicsSceneMouseEvent *m = static_cast<QGraphicsSceneMouseEvent*>(event);
        if (m->buttons() & Qt::MiddleButton)
        {
            QPointF delta = m->lastScreenPos() - m->screenPos();
            int newX = view->horizontalScrollBar()->value() + delta.x();
            int newY = view->verticalScrollBar()->value() + delta.y();
            view->horizontalScrollBar()->setValue(newX);
            view->verticalScrollBar()->setValue(newY);
            return true;
        }
    }

    return QMainWindow::eventFilter(obj, event);
}

чтобы отфильтровать события из QGraphicsScene, вам придется установить MyMainWindow в качестве фильтра событий сцены. Возможно, вы могли бы сделать это в той же функции, где вы настраиваете свой GUI.

void MyMainWindow::setupGUI()
{ 
    // along with other GUI stuff...

    scene->installEventFilter(this);
}

вы можете расширить эту идею, чтобы заменить курсор на перетаскивание "рука", как показано ранее.