Как правильно изменить размер QGraphicsView?

Пробую создать простое приложение с QGraphicsView. Приложение может загружать графические файлы с разным соотношением сторон в представлении. Я хотел бы реализовать следующую функцию: при изменении размера окна приложения содержимое представления также должно быть изменено и центрировано. Я плохо знаю эту часть Qt, поэтому могу изменить размер содержимого, но не могу его центрировать. Как я могу это исправить?

Фрагмент MainWindow.h:

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    void resizeEvent(QResizeEvent *event) override;

public slots:
    void onButtonClicked();

private:
    bool m_flag = false;
    QGraphicsPixmapItem *m_item = nullptr;
    QGraphicsView *m_view = nullptr;
    QPixmap m_pixmap;
};

MainWindow.cpp:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    auto central = new QWidget(this);
    setCentralWidget(central);

    // layouts
    auto mainLayout = new QVBoxLayout;
    mainLayout->setAlignment(Qt::AlignTop);
    central->setLayout(mainLayout);

    // top layout
    auto topLayout = new QHBoxLayout;
    topLayout->setAlignment(Qt::AlignLeft);
    mainLayout->addLayout(topLayout);
    auto btn = new QPushButton(this);
    btn->setText("Test");
    connect(btn, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
    topLayout->addWidget(btn);

    m_view = new QGraphicsView;
    mainLayout->addWidget(m_view);
    auto scene = new QGraphicsScene;
    m_view->setScene(scene);
    m_view->setMinimumSize(800, 600);
    m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    QString name = ":/pic1.jpg";
    m_pixmap = QPixmap{ name }.scaled(800, 600, Qt::KeepAspectRatio);
    m_item = scene->addPixmap(m_pixmap);
    m_view->viewport()->resize(m_pixmap.size());
}

void MainWindow::onButtonClicked()
{
    m_flag = !m_flag;
    QString name = m_flag ? ":/pic2.png" : ":/pic1.jpg";
    m_pixmap = QPixmap{ name }.scaled(m_view->size(), Qt::KeepAspectRatio);
    m_item->setPixmap(m_pixmap);
    m_view->fitInView(m_item, Qt::KeepAspectRatio);
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);
    m_view->fitInView(m_item, Qt::KeepAspectRatio);
}

Результат теста для pic2.png: Как правильно изменить размер QGraphicsView?

Вы хотите, чтобы элемент, показывающий изображение, был центрирован по вертикали?

eyllanesc 06.05.2018 16:51

@eyllanesc Да, я бы хотел центрировать по вертикали! Теперь это наверху.

Lex Sergeev 06.05.2018 16:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
2 601
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Решение состоит в том, чтобы перекрасить масштабированный QPixmap в середине окончательного QPixmap.

const QSize pixmap_size{800, 600};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    auto central = new QWidget(this);
    setCentralWidget(central);

    // layouts
    auto mainLayout = new QVBoxLayout;
    mainLayout->setAlignment(Qt::AlignTop);
    central->setLayout(mainLayout);

    // top layout
    auto topLayout = new QHBoxLayout;
    topLayout->setAlignment(Qt::AlignLeft);
    mainLayout->addLayout(topLayout);
    auto btn = new QPushButton(this);
    btn->setText("Test");
    connect(btn, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
    topLayout->addWidget(btn);

    m_view = new QGraphicsView;
    mainLayout->addWidget(m_view);
    auto scene = new QGraphicsScene;
    m_view->setScene(scene);
    m_view->setMinimumSize(pixmap_size);
    m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    m_pixmap = QPixmap(pixmap_size);
    m_pixmap.fill(Qt::transparent);
    m_item = new QGraphicsPixmapItem;
    m_view->scene()->addItem(m_item);
    show();
    onButtonClicked();
}

QPixmap MainWindow::createPixmap(const QString & filename, const QSize & size) const{

    QPixmap tmp = QPixmap{ filename }.scaled(size, Qt::KeepAspectRatio);
    QPixmap pixmap(size);
    pixmap.fill(Qt::transparent);
    QPainter p(&pixmap);
    QPoint point(QRect({}, size).center()-tmp.rect().center());
    p.drawPixmap(point, tmp);
    p.end();
    return pixmap;
}

void MainWindow::onButtonClicked()
{
    QString name = m_flag ? ":/pic2.png" : ":/pic1.jpg";
    m_item->setPixmap(createPixmap(name, pixmap_size));
    m_flag = !m_flag;
    m_view->fitInView(m_item, Qt::KeepAspectRatio);
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);
    m_view->fitInView(m_item, Qt::KeepAspectRatio);
}

Спасибо большое! Вроде работает! Я немного поигрался с кодом и у меня есть вопрос. Не могли бы вы объяснить, почему важна строка show(); в конструкторе? Я попытался закомментировать это или поменять местами на следующую строку (onButtonClicked();), и приложение немного сломалось.

Lex Sergeev 06.05.2018 19:48

@LexSergeev Даже если вы укажете размер, форму, цвет и т. д., Эти характеристики не применяются сразу, но при необходимости в вашем случае область просмотра QGraphicsView обновляется, когда они отображаются. Если мой ответ поможет вам, не забудьте отметить его как правильный, это лучший способ поблагодарить. Если не знаете, как это сделать, проверьте тур

eyllanesc 06.05.2018 19:53

Конечно, ответ мне помогает, но я не понимаю, как это работает. Непонятно, например, почему важен порядок. Конечно, я знаю, как отметить ответ, спасибо за заметку и ссылку на экскурсию. Но на данный момент ответ неясен.

Lex Sergeev 06.05.2018 20:11

@LexSergeev Порядок важен, потому что необходимо, чтобы параметры просмотров были установлены. Как я сказал в своем предыдущем комментарии, Qt из соображений эффективности не применяет изменения немедленно, например, вы указываете, что изменяете размер, думаете ли вы, что можете обновить размер, когда представление еще не отображается, поэтому вы собирается изменить размер, если он все еще не имеет размера, Qt сохраняет желаемый размер и использует его при необходимости.

eyllanesc 06.05.2018 20:33

@LexSergeev [cont] в данном случае в методе showEvent (), поэтому после выполнения этой строки вы просто видите правильный размер, я вызываю show (), чтобы принудительно вызвать showEvent (), как только изменение будет обновлено, оно может быть нарисованным правильно.

eyllanesc 06.05.2018 20:34

Другие вопросы по теме