如何正确调整QGraphicsView的大小?

4
我将尝试使用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的测试结果如下: Test result for the <code>pic2.png</code>


您是否希望显示图像的项目在垂直方向上居中? - eyllanesc
@eyllanesc 是的,我想要垂直居中!现在它在顶部。 - Lex Sergeev
1个回答

4

当图像被缩放时,它是相对于左上角进行的,所以如果高度小于前缀,则它将始终向上看,如果宽度小于前缀,则向右看。

解决方法是在最终的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
即使您指定了大小、形状、颜色等特征,这些特征也不会立即应用,而是在必要时应用。在您的情况下,当它们被显示时,QGraphicsView 的视口将被更新。如果我的答案对您有帮助,请不要忘记将其标记为正确答案,这是最好的感谢方式。如果您不知道如何操作,请查看[tour]。 - eyllanesc
当然,这个答案对我有帮助,但我不明白它是如何工作的。例如,为什么顺序很重要并不清楚。当然,我知道如何标记答案,感谢您的提示和参考。但目前这个答案还是相当晦涩的。 - Lex Sergeev
@LexSergeev 顺序很重要,因为需要建立视图参数。如我在之前的评论中所说,Qt出于效率考虑不会立即应用更改。例如,您指示更改大小,您认为在视图尚未显示时可以更新大小吗?因此,如果它仍没有大小,您将更改大小,Qt保存所需的大小并在必要时使用它。 - eyllanesc
@LexSergeev [cont] 在这种情况下,在showEvent()方法中,执行该行代码后,您只能看到正确的大小,我调用show()来强制调用showEvent(),只有在更新更改时才能正确绘制。 - eyllanesc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接