Пробую создать простое приложение с 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);
}
@eyllanesc Да, я бы хотел центрировать по вертикали! Теперь это наверху.





Когда изображение масштабируется, это делается относительно верхнего левого угла, поэтому оно всегда будет искать вверх, если высота меньше префикса, или вправо, если ширина меньше.
Решение состоит в том, чтобы перекрасить масштабированный 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();), и приложение немного сломалось.
@LexSergeev Даже если вы укажете размер, форму, цвет и т. д., Эти характеристики не применяются сразу, но при необходимости в вашем случае область просмотра QGraphicsView обновляется, когда они отображаются. Если мой ответ поможет вам, не забудьте отметить его как правильный, это лучший способ поблагодарить. Если не знаете, как это сделать, проверьте тур
Конечно, ответ мне помогает, но я не понимаю, как это работает. Непонятно, например, почему важен порядок. Конечно, я знаю, как отметить ответ, спасибо за заметку и ссылку на экскурсию. Но на данный момент ответ неясен.
@LexSergeev Порядок важен, потому что необходимо, чтобы параметры просмотров были установлены. Как я сказал в своем предыдущем комментарии, Qt из соображений эффективности не применяет изменения немедленно, например, вы указываете, что изменяете размер, думаете ли вы, что можете обновить размер, когда представление еще не отображается, поэтому вы собирается изменить размер, если он все еще не имеет размера, Qt сохраняет желаемый размер и использует его при необходимости.
@LexSergeev [cont] в данном случае в методе showEvent (), поэтому после выполнения этой строки вы просто видите правильный размер, я вызываю show (), чтобы принудительно вызвать showEvent (), как только изменение будет обновлено, оно может быть нарисованным правильно.
Вы хотите, чтобы элемент, показывающий изображение, был центрирован по вертикали?