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

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

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

当PushButton1不可见时,是否有任何方法/技巧可以从左侧边缘裁剪?
发布于 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。)
这就是我最后的结局:
#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:
#!/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):

https://stackoverflow.com/questions/65412975
复制相似问题