首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从两边裁剪Qt窗口?

问如何从两边裁剪Qt窗口?
EN

Stack Overflow用户
提问于 2020-12-22 17:13:43
回答 1查看 202关注 0票数 1

我有一个Qt窗口,所有小部件都已插入到中央小部件中,因此,当窗口调整大小时,小部件大小不会改变(原始窗口):

​

​

有时,我不需要在右侧或左侧看到一些小部件,所以我尝试裁剪Windows,因为这些小部件是不可见的(右裁剪的窗口):

​

​

然而,对于Qt窗口右侧的小部件来说,这是正确的,当我尝试从左侧裁剪窗口时,左侧的窗口小部件并不隐藏(右裁剪窗口):

​

​

当PushButton1不可见时,是否有任何方法/技巧可以从左侧边缘裁剪?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-12-23 11:47:30

我必须承认,我并不完全清楚我是否完全明白“行动纲领”的意图。不过,@musicamente的评论引起了我的注意:

没有一种直接和安全的方法可以知道小部件的“什么”边框实际上导致了大小的调整

我相信这并不是很复杂。为了证明我是对还是错,我刚刚开始了一个MCVE来检验这个问题。

因此,我从这样的假设开始,即通过拖动左和/或顶部窗口边框来调整大小也会导致更改窗口坐标。因此,应该有可能确定这一点,并保持该研究报告的立场。与桌面相关的窗口子变量(而不是Qt中常见的顶部/左侧窗口角)。

这可以通过简单的补偿窗口的运动,通过负移动的resp。窗户的孩子们。这可能(或不可能)仅限于调整窗口大小。(如果它也应用于窗口运动,则会产生另一种有趣的效果,使窗口像窥视孔一样。)

子窗口的放置在Qt中,通常是布局管理器的主题(源自QLayout)。虽然有各种内置的布局管理器(可以满足日常业务的需要),但是也可以选择制作一个自定义布局管理器。另一种选择是不使用任何布局管理器,而是直接放置和调整子部件的大小。为了保持MCVE的简洁性,我使用了后一种选择。

当我摆弄这件事的时候,我注意到一些我以前不知道的效果,我试着分别去处理。

  • 当在resizeEvent()中检索当前窗口位置时,它提供了旧位置。无法从调用数据(类型为QResizeEvent)中检索当前位置。解决方案是推迟补偿子部件的移动,直到完成调整大小的处理。这可以方便地实现一个一次性定时器(与延迟0)。
  • 当拖动左边或顶部窗口边框时,resizeEvent()会附带一个moveEvent()。(对我来说有点道理。)因此,我必须区分由于窗口移动而产生的moveEvents()和由于窗口大小调整而产生的moveEvents()。我注意到(在我的情况下) resizeEvent()s总是在moveEvent()s之前发送。很有希望,这可能是可靠的,我使用了一个标志来忽略resizeEvent()中的moveEvent()s,直到我推迟处理子运动为止。

(我必须承认Python只是我的第二种(或第三种)语言,而我的第一种语言是C++。因此,我用C++编写了一个概念证明,将端口推迟到Python/PyQt。)

这就是我最后的结局:

代码语言:javascript
复制
#include <QtWidgets>

class Window: public QWidget {
  private:
    QVector<QWidget*> _pQWidgetsMove;
    int _x, _y;
    bool _updateXY = true;

  public:
    Window(QWidget *pQParent = nullptr): QWidget(pQParent) { }
    virtual ~Window() = default;

    Window(const Window&) = delete;
    Window& operator=(const Window&) = delete;

    void setMoveWidgets(QVector<QWidget*> pQWidgetsMove)
    {
      _pQWidgetsMove = pQWidgetsMove;
    }

  protected:
    virtual void showEvent(QShowEvent *pQEvent) override;
    virtual void resizeEvent(QResizeEvent *pQEvent) override;
    virtual void moveEvent(QMoveEvent *pQEvent) override;
};

void Window::showEvent(QShowEvent *pQEvent)
{
  QWidget::showEvent(pQEvent);
  _x = x(); _y = y();
}

void Window::moveEvent(QMoveEvent* pQEvent)
{
  QWidget::moveEvent(pQEvent);
  if (_updateXY) {
    _x += pQEvent->pos().x() - pQEvent->oldPos().x();
    _y += pQEvent->pos().y() - pQEvent->oldPos().y();
  }
}

void Window::resizeEvent(QResizeEvent* pQEvent)
{
  QWidget::resizeEvent(pQEvent);
  _updateXY = false;
  QTimer::singleShot(0, // 0 ms -> idle callback
    [this, x = x(), y = y()]() {
      for (QWidget* pQWidget : _pQWidgetsMove) {
        pQWidget->move(pQWidget->x() + _x - x, pQWidget->y() + _y - y);
      }
      _x = x; _y = y;
      _updateXY = true;
    });
}

int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // config GUI
  const int wMain = 320, hMain = 240; // initial size of main window
  const int nBtns = 4; // number of buttons
  // setup GUI
  Window qWinMain;
  qWinMain.setWindowTitle("Fun with Resize");
  qWinMain.resize(wMain, hMain);
  QPushButton qBtns[nBtns];
  { int i = 0;
    for (QPushButton& qBtn : qBtns) {
      const int xBtn = i * wMain / nBtns, wBtn = wMain / nBtns;
      qBtn.setParent(&qWinMain);
      qBtn.move(xBtn, 0);
      qBtn.resize(wBtn, hMain);
      qBtn.setText(QString("Button %1").arg(i + 1));
      ++i;
    }
  }
  QCheckBox qTglStick("Stick Buttons to Desktop", &qWinMain);
  qTglStick.move(2, 2);
  qWinMain.show();
  // install signal handlers
  QObject::connect(&qTglStick, &QCheckBox::toggled,
    [&](bool checked) {
      QVector<QWidget*> pQWidgetsMove;
      if (checked) {
        for (QPushButton& qBtn : qBtns) pQWidgetsMove.push_back(&qBtn);
      }
      qWinMain.setMoveWidgets(pQWidgetsMove);
    });
  // runtime loop
  return app.exec();
}

输出(Windows,Visual Studio 2019):

​

这看起来没那么糟。

当窗口通过拖动顶部和/或左边框调整大小时,按钮中有一些抖动。我假设这是对QWidget::move()调用所产生的事件的顺序处理的结果。我真不知道怎么解决这个问题。(抑制paintEvent()s进行重新定位。持续时间?)所以,我决定暂时接受这个。

当它在Windows上工作时,Linux怎么样?

因此,我在Debian (在VM中)进行了重建和测试。

输出(Debian,g++ 8.3.0):

​

最后,上述MCVE的端口到Python3 / PyQt5:

代码语言:javascript
复制
#!/usr/bin/python3

import sys
from PyQt5.QtCore import QT_VERSION_STR
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QCheckBox

class Window(QWidget):

  def __init__(self, parent = None):
    QWidget.__init__(self, parent)
    self.widgetsMove = list()
    self.x, self.y = (0, 0)
    self.updateXY = True

  def setMoveWidgets(self, widgets):
    self.widgetsMove = widgets
    self.x, self.y = QWidget.x(self), QWidget.y(self)

  def moveEvent(self, event):
    QWidget.moveEvent(self, event)
    if self.updateXY:
      self.x += event.pos().x() - event.oldPos().x()
      self.y += event.pos().y() - event.oldPos().y()

  def moveWidgets(self, xOld, yOld):
    for widget in self.widgetsMove:
      widget.move( \
        widget.x() + self.x - xOld, \
        widget.y() + self.y - yOld)
    self.x, self.y = xOld, yOld
    self.updateXY = True

  def resizeEvent(self, event):
    QWidget.resizeEvent(self, event)
    self.updateXY = False
    QTimer.singleShot(0, \
      lambda x = QWidget.x(self), y = QWidget.y(self): \
        Window.moveWidgets(self, x, y))

if __name__ == '__main__':
  print("Qt Version: {}".format(QT_VERSION_STR))
  app = QApplication(sys.argv)
  # config GUI
  wMain, hMain = 320, 240
  nBtns = 4
  # setup GUI
  qWinMain = Window()
  qWinMain.setWindowTitle("Fun with Resize (PyQt5)")
  qWinMain.resize(wMain, hMain)
  qBtns = list()
  for i in range(0, nBtns):
    xBtn = i * wMain / nBtns
    wBtn = wMain / nBtns
    qBtn = QPushButton(qWinMain)
    qBtn.move(xBtn, 0)
    qBtn.resize(wBtn, hMain)
    qBtn.setText("Button {}".format(i + 1))
    qBtns.append(qBtn)
  qTglStick = QCheckBox("Stick Buttons to Desktop", qWinMain)
  qTglStick.move(2, 2)
  qWinMain.show()
  # install signal handlers
  qTglStick.toggled.connect(lambda checked: \
    qWinMain.setMoveWidgets(qBtns if checked else list()))
  # runtime loop
  sys.exit(app.exec_())

输出(Debian、Python3、PyQt5):

​

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65412975

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档