У меня есть область прокрутки, которая содержит изменяемый виджет. Пользователь может увеличивать и уменьшать целочисленный масштабный коэффициент этого внутреннего виджета (который изменяет его размер). Когда пользователь увеличивает масштаб, часть внутреннего виджета, видимая в верхнем левом углу, остается неизменной. Это дает эффект увеличения в верхнем левом углу вида.
Когда размер внутреннего виджета изменяется, мне нужно прокрутить внутренний виджет, чтобы он выглядел так, как будто пользователь масштабирует центр изображения. Я хочу, чтобы при изменении размера часть виджета находилась в центре поля зрения в центре.
Я нарисовал несколько диаграмм, чтобы помочь визуализировать проблему. Розовый прямоугольник - это внутренний виджет. Коричневый прямоугольник - это вид на виджет через область прокрутки. Зеленые точки - это фиксированные точки на внутреннем виджете.
До масштабирования
После масштабирования (текущее нежелательное поведение)
После масштабирования (желаемое поведение)
Как вы можете (надеюсь) увидеть из этих грубо нарисованных диаграмм. Простое увеличение размера виджета внутри области прокрутки приводит к увеличению масштаба в верхнем левом углу или представлении. Я должен сделать что-то еще, чтобы увеличить центр обзора. Также внутренний виджет может быть намного меньше, чем область прокрутки. Я хочу сдвигать внутренний виджет только тогда, когда он больше области прокрутки.
Это минимальный пример нежелательного поведения. Нажатие Z (после нажатия на внутренний виджет для изменения фокуса) увеличит верхний левый угол представления. Я хочу увеличить центр обзора.
#include <QtGui/qpainter.h>
#include <QtWidgets/qscrollbar.h>
#include <QtWidgets/qscrollarea.h>
#include <QtWidgets/qmainwindow.h>
#include <QtWidgets/qapplication.h>
class InnerWidget final : public QWidget {
public:
explicit InnerWidget(QScrollArea *parent)
: QWidget{parent}, parent{parent} {
updateSize();
setFocusPolicy(Qt::StrongFocus);
}
private:
QScrollArea *parent;
int scale = 1;
void updateSize() {
setFixedSize(256 * scale, 256 * scale);
}
void paintEvent(QPaintEvent *) override {
QPainter painter{this};
const QColor green = {0, 255, 0};
painter.fillRect(0, 0, width(), height(), {255, 255, 255});
painter.fillRect(32 * scale, 32 * scale, 16 * scale, 16 * scale, green);
painter.fillRect(128 * scale, 128 * scale, 16 * scale, 16 * scale, green);
}
void keyPressEvent(QKeyEvent *event) override {
if (event->isAutoRepeat()) return;
QScrollBar *hbar = parent->horizontalScrollBar();
QScrollBar *vbar = parent->verticalScrollBar();
if (event->key() == Qt::Key_Z) {
// need to call bar->setValue and bar->value here
scale = std::min(scale + 1, 64);
updateSize();
} else if (event->key() == Qt::Key_X) {
// here too
scale = std::max(scale - 1, 1);
updateSize();
}
}
};
int main(int argc, char **argv) {
QApplication app{argc, argv};
QMainWindow window;
QScrollArea scrollArea{&window};
InnerWidget inner{&scrollArea};
window.setBaseSize(512, 512);
window.setCentralWidget(&scrollArea);
scrollArea.setAlignment(Qt::AlignCenter);
scrollArea.setWidget(&inner);
window.show();
return app.exec();
}
Чтобы воспроизвести проблему, увеличьте пару раз, затем поместите один из прямоугольников в центр окна. Масштабирование сместит прямоугольник к нижнему правому углу. Я хочу, чтобы масштабирование сохраняло прямоугольник в центре.
Это похоже на легкую проблему, но я не могу разобраться с математикой. Я пробовал различные вычисления значений прокрутки, но ни одно из них не работает так, как я хочу.