将可调整大小的小部件放在滚动区域内

问题描述 投票:1回答:1

我有一个包含可调整大小的小部件的滚动区域。用户能够递增和递减此内部窗口小部件的整数比例因子(其更改其大小)。当用户递增比例时,左上角可见的内部窗口小部件的部分保持固定。这样可以放大到视图的左上角。

当内部窗口小部件的大小发生变化时,我需要滚动内部窗口小部件,使其看起来像用户正在缩放到视图的中心。我希望在调整大小时将小部件的一部分保持在视图中心固定在中心。

我绘制了一些图表来帮助可视化问题。粉红色矩形是内部小部件。棕色矩形是通过滚动区域到窗口小部件的视图。绿点是内部小部件上的固定点。

Before scaling缩放之前

After scaling (current undesirable behaviour)缩放后(当前不良行为)

After scaling (desired behaviour)缩放后(所需行为)

正如你所能(希望)从这些粗略绘制的图表中看到的那样。简单地增加滚动区域内小部件的大小会导致缩放到左上角或视图。我必须做更多的事情来放大视图的中心。此外,内部窗口小部件可以比滚动区域小得多。我只想在内部窗口小于滚动区域时移动内部窗口小部件。

这是不良行为的最小示例。按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();
}

要重现此问题,请放大几次,然后将其中一个矩形放在窗口中央。缩放将矩形移向右下角。我想缩放以保持矩形在中心。

这感觉就像一个简单的问题,但我似乎无法理解数学。我已经尝试了滚动值的各种计算,但它们似乎没有像我想要的那样表现。

c++ qt qt5
1个回答
0
投票

我把这些数字搞砸了一会然后我想出来了。这是完全可行的解决方案。

#include <QtGui/qpainter.h>
#include <QtWidgets/qscrollbar.h>
#include <QtWidgets/qmainwindow.h>
#include <QtWidgets/qscrollarea.h>
#include <QtWidgets/qapplication.h>

class InnerWidget final : public QWidget {
public:
  explicit InnerWidget(QScrollArea *parent)
    : QWidget{parent}, parent{parent}, scale{1} {
    updateSize();
    setFocusPolicy(Qt::StrongFocus);
  }

private:
  QScrollArea *parent;
  int scale;

  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 adjustScroll(const int oldScale) {
    if (scale == oldScale) return;
    QScrollBar *hbar = parent->horizontalScrollBar();
    QScrollBar *vbar = parent->verticalScrollBar();
    if (width() >= parent->width()) {
      const int halfWidth = parent->width() / 2;
      hbar->setValue((hbar->value() + halfWidth) * scale / oldScale - halfWidth);
    }
    if (height() >= parent->height()) {
      const int halfHeight = parent->height() / 2;
      vbar->setValue((vbar->value() + halfHeight) * scale / oldScale - halfHeight);
    }
  }

  void keyPressEvent(QKeyEvent *event) override {
    if (event->isAutoRepeat()) return;
    const int oldScale = scale;
    if (event->key() == Qt::Key_Z) {
      scale = std::min(scale + 1, 64);
      updateSize();
      adjustScroll(oldScale);
    } else if (event->key() == Qt::Key_X) {
      scale = std::max(scale - 1, 1);
      updateSize();
      adjustScroll(oldScale);
    }
  }
};

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();
}
© www.soinside.com 2019 - 2024. All rights reserved.