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

В настоящее время я могу загрузить свое изображение в графическую сцену, а затем снова в QGraphicsViewer.

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

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

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


person Derek    schedule 20.01.2011    source источник


Ответы (3)


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

person Stephen Chu    schedule 21.01.2011
comment
Как вы думаете, смогу ли я реализовать это у себя? Я хочу сделать это при нажатии правой кнопки мыши. Как я могу прокручивать вид из кода? - person neuviemeporte; 01.03.2011
comment
@neuviemeporte: я не знаю, как это сделать, щелкнув правой кнопкой мыши. Вы можете опубликовать его как отдельный вопрос, чтобы кто-то другой мог ответить на него. - person Stephen Chu; 01.03.2011
comment
Вам больше не нужно включать полосы прокрутки в Qt 5.0 - person vsz; 19.01.2017

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

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();

}
person neuviemeporte    schedule 01.03.2011
comment
да, именно то, что я искал .. даже годы спустя, спасибо! - person Amazonasmann; 13.12.2013
comment
Попробуйте использовать приведенный выше пример, но вместо того, чтобы манипулировать полосами прокрутки, используйте QGraphicsView::scrollContentsBy. Требуется смещение dx, dy, которое корректирует ваше содержимое (Scene). - person Mark; 20.02.2016
comment
Игнорировать — не использовать ::scrollContentsBy — согласно документам следует использовать только полосы прокрутки. Вызов этой функции для программной прокрутки является ошибкой, вместо этого используйте полосы прокрутки (например, путем прямого вызова QScrollBar::setValue()). - person Mark; 20.02.2016
comment
Может ли кто-нибудь сказать мне, будет ли это мешать щелчку правой кнопкой мыши вызывать контекстные меню? - person pbreach; 12.06.2016

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

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

Допустим, логика вашего графического интерфейса поддерживается подклассом 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 в качестве фильтра событий сцены. Возможно, вы могли бы сделать это в той же функции, где вы настраиваете свой графический интерфейс.

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

    scene->installEventFilter(this);
}

Вы можете расширить эту идею, заменив курсор перетаскиванием «руки», как показано ранее.

person Jonathan    schedule 01.03.2016
comment
Спасибо, отличный обходной путь - для тех, кто не хочет повторно реализовывать QGraphicsView :) - person Maxime Franchot; 24.01.2020