Thalia
Thalia

Reputation: 14605

Move QGraphicsView top left to a certain point in QGraphicsScene manually

I have a QGraphicsView subclass, holding a QGraphicsScene subclass, inside a QWidget.

The QGraphicsScene has an actual drawing rectangle with top let corner at (0,0) (so the scene really has a QRectF(-x,-y,w,h) of values irrelevant to the problem).

On startup, actually in the showEvent of the widget, I set the size of the scene to fit the custom sized rectangle. That also centers it.

What I would like, is to match the (0,0) point of the scene to the top left of the view, on start.

Unlike other questions with the same title, I actually need to move the view, not the items inside the scene.

Image 1: actual start, image 2: desired

actual desired

I am trying:

void MyWidget::showEvent(QShowEvent *event)
{
    static bool startUp = true;
    if(startUp)
    {
        QSizeF sz = m_scene->getActualSize();
        ui->graphicsView->fitInView(QRectF(0, 0, sz.width(), sz.height()), Qt::KeepAspectRatio);

        QPointF zero = ui->graphicsView->mapFromScene(QPointF(0,0));
        ui->graphicsView->translate(-zero.x(), -zero.y()); // or positive

        startUp = false;
    }
    QWidget::showEvent(event);
}

note: I use the fitInView to get the desired zoom - and it also brings the desired rectangle in focus - but centered in the view.

I also tried

void GraphicsView::alignToZero()
{
    QPointF zero = this->mapFromScene(QPointF(0,0));
    this->scrollContentsBy(-zero.x(), -zero.y());
}

void MyWidget::showEvent(QShowEvent *event)
{
    static bool startUp = true;
    if(startUp)
    {
        QSizeF sz = m_scene->getActualSize();
        ui->graphicsView->fitInView(QRectF(0, 0, sz.width(), sz.height()), Qt::KeepAspectRatio);

        ui->graphicsView->alignToZero();

        startUp = false;
    }
    QWidget::showEvent(event);
}

Still no result.

Also tried

void MyWidget::showEvent(QShowEvent *event)
{
    static bool startUp = true;
    if(startUp)
    {
        QSizeF sz = m_scene->getActualSize();
        ui->graphicsView->fitInView(QRectF(0, 0, sz.width(), sz.height()), Qt::KeepAspectRatio);

        QPointF zero = ui->graphicsView->mapFromScene(QPointF(0,0));
        //ui->graphicsView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
        ui->graphicsView->horizontalScrollBar()->setValue(zero.x());
        ui->graphicsView->verticalScrollBar()->setValue(zero.y());

        startUp = false;
    }
    QWidget::showEvent(event);
}

This, with or without the alignment setting (which I think may have unwanted effects elsewhere), moves the view... too far.

Upvotes: 1

Views: 2043

Answers (2)

Tomasz T
Tomasz T

Reputation: 65

If I understand your question correctly, to achieve desired effect you can use method

QGraphicsView::setAlignment(Qt::Alignment alignment):

ui->graphicsView->setAlignment( Qt::AlignTop | Qt::AlignLeft );

Which is commented in your code. This method with those arguments aligns view top-left, you don't have to move or fit anything.

Upvotes: 6

Thalia
Thalia

Reputation: 14605

While there must be a better way... I figured out a way to get my 0's aligned by doing fitInView twice:

void MyWidget::showEvent(QShowEvent *event)
{
    static bool startUp = true;
    if(startUp)
    {
        QSizeF sz = m_scene->getActualSize();
        // First I do a normal `fitInView` that centers the rectangle
        ui->graphicsView->fitInView(QRectF(0, 0, sz.width(), sz.height()), Qt::KeepAspectRatio);

        // Then, knowing the shift, I fit it again adding twice the shift to the size.
        QPointF zero = ui->graphicsView->mapToScene(QPoint(0,0));
        ui->graphicsView->fitInView(QRectF(0, 0, sz.width() - 2 * zero.x(), sz.height() - 2 * zero.y()), Qt::KeepAspectRatio);

        startUp = false;
    }
    QWidget::showEvent(event);
}

Upvotes: 1

Related Questions