#python #pyqt #pyqt5 #positioning #qmainwindow
#python #pyqt #pyqt5 #позиционирование #qmainwindow
Вопрос:
Я использую PyQt5 для создания приложения с несколькими основными окнами. Я хочу иметь возможность разрешать пользователю сохранять и загружать размеры окон и положения окон. Это легко сделать, например, с QMainWindow.saveGeometry()
помощью and QMainWindow.loadGeometry()
или соответствующих .saveState()
.loadState()
вариантов and . Они отлично подходят для положения и размера, но если пользователь перемещает или изменяет размер одного окна так, чтобы оно перекрывало другое, я хочу также восстановить это позиционирование. Я не против написать свой собственный код для сохранения информации для каждого окна, но я не вижу никакого способа определить относительный порядок окон по Z. Я пропускаю это в документах или это невозможно?
Чтобы понять, что я имею в виду, попробуйте следующее:
from PyQt5.QtWidgets import QApplication, QMainWindow, QPlainTextEdit
from PyQt5.QtCore import QSettings
from PyQt5.QtGui import QCloseEvent
'''
context: Linux Mint 19.3 Tricia x86_64
Python 3.9
PyQt5 5.15.1
'''
class RememberWin(QMainWindow):
def __init__(self, win_name: str):
super(RememberWin, self).__init__()
self.win_name = win_name
self.setWindowTitle(win_name)
self.can_close = False
def restore_window(self) -> bool:
try:
settings = QSettings("PyQtExamples", "RememberWinTest")
self.restoreGeometry(settings.value(f'{self.win_name} Geometry'))
self.restoreState(settings.value(f'{self.win_name} State'))
return True
except:
return False
def closeEvent(self, event: QCloseEvent):
if not self.can_close:
event.ignore()
else:
settings = QSettings("PyQtExamples", "RememberWinTest")
settings.setValue(f'{self.win_name} Geometry', self.saveGeometry())
settings.setValue(f'{self.win_name} State', self.saveState())
QMainWindow.closeEvent(self, event)
class ControlWindow(RememberWin):
def __init__(self, win_name: str = "ControlWindow"):
super(ControlWindow, self).__init__(win_name=win_name)
self.can_close = True
self.window1 = RememberWin(win_name='WindowOne')
self.window2 = RememberWin(win_name='WindowTwo')
self.text = QPlainTextEdit(self)
s = "Try making Window1 wide enough to cover Window2.n"
"Then close this window (auto closes others).n"
"Re-run the app and you'll notice that Window2n"
"is not on top of Window1 which means that thisn"
"info isn't getting saved."
self.text.setPlainText(s)
self.setCentralWidget(self.text)
if not self.restore_window():
self.setGeometry(100, 390, 512, 100)
if not self.window1.restore_window():
self.window1.setGeometry(100, 100, 512, 384)
if not self.window2.restore_window():
self.window2.setGeometry(622, 100, 512, 384)
self.window1.show()
self.window2.show()
def closeEvent(self, event: QCloseEvent):
for win in (self.window1, self.window2):
win.can_close = True
win.close()
super(ControlWindow, self).closeEvent(event)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = ControlWindow(win_name='ControlWindow (You can only close this one)')
window.show()
sys.exit(app.exec_())
Ответ №1:
Самый простой способ сделать то, чего вы хотите достичь, — это отслеживать текущий сфокусированный виджет или, если быть точным, окно верхнего уровня последнего сфокусированного виджета.
Вы можете сохранить сфокусированные окна в настройках в виде списка, используя уникальные objectName
для каждого окна (вы уже делаете это, поэтому вам просто нужно использовать setObjectName()
), затем восстановить окно, показывая их в правильном порядке, если имя объекта совпадает.
class RememberWin(QMainWindow):
def __init__(self, win_name: str):
super(RememberWin, self).__init__()
self.win_name = win_name
self.setObjectName(win_name)
self.setWindowTitle(win_name)
self.can_close = False
# ...
class ControlWindow(RememberWin):
def __init__(self, win_name: str = "ControlWindow"):
# ...
self.settings = QSettings("PyQtExamples", "RememberWinTest")
self.zOrder = []
QApplication.instance().focusObjectChanged.connect(self.focusChanged)
windowOrder = self.settings.value('windowOrder', type='QStringList')
topLevelWindows = QApplication.topLevelWidgets()
if windowOrder:
for objName in windowOrder:
for win in topLevelWindows:
if win.objectName() == objName:
win.show()
else:
self.window1.show()
self.window2.show()
def focusChanged(self, obj):
if not obj or obj.window() == self.window():
return
if obj.window() in self.zOrder[:-1]:
self.zOrder.remove(obj.window())
self.zOrder.append(obj.window())
def closeEvent(self, event: QCloseEvent):
for win in (self.window1, self.window2):
win.can_close = True
win.close()
self.settings.setValue('windowOrder',
[w.window().objectName() for w in self.zOrder])
super(ControlWindow, self).closeEvent(event)