Есть ли QLabel :: setScaledContents эквивалентная функция для QGraphicsScene в Qt? - PullRequest
1 голос
/ 05 июня 2019

Я использую QGraphicsView и QGraphicsScene, чтобы отобразить загруженное изображение, а затем показать на нем некоторый рисунок.Я загружаю и изображение выглядит так:

void MeasuresWidget::on_openAction_triggered()
{
    QString fileName = QFileDialog::getOpenFileName(this,tr("Open File"), QDir::currentPath());
    if (!fileName.isEmpty())
    {
        QImage image(fileName);
        if (image.isNull())
        {
            QMessageBox::information(this, tr("Measures Application"), tr("Cannot load %1.").arg(fileName));
            return;
        }
        scene->clear();
        scene->addPixmap(QPixmap::fromImage(image).scaledToWidth(w, Qt::SmoothTransformation));
    }
}

Проблема, с которой я сталкиваюсь, заключается в том, что если я загружаю изображение, которое меньше, чем то, которое было загружено ранее, кажется, что есть пустое пространство, т.е.сцена сохраняет размер предыдущего изображения (больше) и больше текущего.Я пытался сохранить исходный размер сцены в отдельной переменной и использовать setSceneRect() в каждом действии загрузки:

//in constructor
    originalRect = ui->graphicsView->rect();
//in upload action
    scene->setSceneRect(originalRect);

, но в результате размер сцены всегда остается неизменным и, если он больше, чем фактическое изображение,режет это.Я использовал QLabel для отображения изображения раньше, и я использовал функцию QLabel::setScaledContents(), и она работала нормально для меня.Итак, мой вопрос: могу ли я добиться того же поведения с QGraphicsScene?

Обновление 1: Приложение ведет себя так, как я хочу, если я создаю новую сцену при каждом действии загрузки.Код теперь выглядит так:

void MeasuresWidget::on_openAction_triggered()
{
    scene = new QGraphicsScene(this);
    ui->graphicsView->setScene(scene);
    QString fileName = QFileDialog::getOpenFileName(this,tr("Open File"), QDir::currentPath());
    if (!fileName.isEmpty())
    {
        QImage image(fileName);
        if (image.isNull())
        {
            QMessageBox::information(this, tr("Image Viewer"), tr("Cannot load %1.").arg(fileName));
            return;
        }
        scene->clear();
        scene->addPixmap(QPixmap::fromImage(image).scaledToWidth(w, Qt::SmoothTransformation));
    }

}

Это нормально?Могу ли я достичь желаемого поведения без необходимости создавать новую сцену при каждом загрузке?

1 Ответ

1 голос
/ 05 июня 2019

Вы просто должны изменить размер сцены, когда вставляете свое растровое изображение в зависимости от его размера.

Если вы определяете новый класс, унаследованный от QGraphicsScene, вы можете легко с ним справиться:

class GraphicsScene: public QGraphicsScene
{
public:
    GraphicsScene(QRect const& rect, QObject* parent=nullptr): QGraphicsScene(rect, parent),
        background(nullptr)
    {}

    QGraphicsPixmapItem *addPixmap(const QPixmap &pixmap)
    {
        // We already have a background. Remove it
        if (background)
        {
            removeItem(background);
            delete background;
        }
        background = QGraphicsScene::addPixmap(pixmap);
        // Move the pixmap
        background->setPos(0, 0);
        // Change the scene rect based on the size of the pixmap
        setSceneRect(background->boundingRect());
        return background;
    }
private:
    QGraphicsPixmapItem* background;
};
    GraphicsScene* scene = new GraphicsScene(QRect());
    QGraphicsView* view = new QGraphicsView();
    view->setScene(scene);
    view->show();

    QPixmap pix1(QSize(2000, 2000));
    pix1.fill(Qt::red);


    QPixmap pix2(QSize(100, 300));
    pix2.fill(Qt::green);

    // The scene will be 2000x2000
    QTimer::singleShot(1000, [=]() { scene->addPixmap(pix1); });
    // The scene will be 100x300
    QTimer::singleShot(10000, [=]() { scene->addPixmap(pix2); });
...