Существуют различные проблемы с вашим кодом:
- вы создаете диалог без установки родителя, поэтому при попытке вызвать
self.parent().hide()
он не будет работать, потому что parent()
возвращает None
, который явно не имеет атрибута hide
; - вы подключили сигнал
accepted
к hide_main
, который требует аргумента, но сигнал accepted
не имеет; - вы пропустили скобки
accepted
в hide_main
, поэтому он не будет вызываться; self.interval
устанавливается только всякий раз, когда индекс комбо изменяется, но если пользователь не меняет его (оставляя значение по умолчанию), self.interval
set не будет; - вы устанавливаете флаг
WindowStaysOnTopHint
only , который сбросит все остальные флаги окна; В результате у вас будет не новое окно, а виджет, который «встроен» в родительский элемент; чтобы правильно установить флаг, вы должны использовать self.setWindowFlags(self.flags() | Qt.WindowStaysOnTopHint)
; - сигналы не могут быть "вызваны", поэтому в
timer.timeout().connect
; - объект
timer
не должен ссылаться вне области действия launch_after_interval
, а также не установлен родительский объект, поэтому он будет удален, как только функция вернется, и никогда не будет запущен;
Исправленный код (изменения выделены жирным шрифтом) :
class popup_on_waiver(QDialog):
def __init__(self, parent=None):
super(QDialog,self).__init__(parent)
self.setWindowFlags(<b>self.windowFlags() | Qt.WindowStaysOnTopHint</b>)
self.setMinimumSize(QSize(660, 340))
self.setWindowTitle("Waiver")
self.cb = QComboBox() #combobox
self.cb.setGeometry(QRect(40, 40, 100, 30))
self.cb.addItems(["1", "2", "3", "4"])
self.cb.currentIndexChanged[str].connect(self.returnInterval)
self.cb.setObjectName("combobox")
self.cb.move(80, 80)
self.buttons = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
self.buttons.accepted.connect(self.hide_main)
self.buttons.rejected.connect(self.reject)
vbox = QVBoxLayout(self)
vbox.addWidget(self.cb)
vbox.addWidget(self.buttons)
self.setLayout(vbox)
# set the default interval
<b>self.interval = 3600000</b>
# no arguments here!
def <b>hide_main(self)</b>:
self.accept<b>()</b> # <-- the parentheses!
self.parent().hide()
launch_after_interval(self.interval)
def returnInterval(self, hours):
self.interval = int(hours) * 3600 * 1000
class Main(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowFlags(<b>self.windowFlags() | Qt.WindowStaysOnTopHint</b>)
self.initUI()
def initUI(self):
self.centralwidget = QWidget(self)
self.Waiver = QPushButton('Waiver')
# if the function does not have arguments, lambda is usually not required
<b>self.Waiver.clicked.connect(self.popup)</b>
hbox = QHBoxLayout()
hbox.addWidget(self.Waiver)
self.centralwidget.setLayout(hbox)
self.setGeometry(50, 50, 1200, 600)
self.setWindowTitle("Timesheet")
self.setWindowIcon(QIcon(""))
self.setStyleSheet("background-color:")
self.setCentralWidget(self.centralwidget)
self.show()
def popup(self):
# the parent is required to make the dialog modal *and* allow it
# to call parent().hide()!
self.p = popup_on_waiver<b>(self)</b>
self.p.exec_()
def launch_after_interval(interval):
# set a parent QObject for the timer, so that it's not removed
# when the function returns
timer = <b>QTimer(QApplication.instance())</b>
timer.setSingleShot(True)
timer.setInterval(interval)
<b>timer.timeout.connect(lambda: Main())</b>
timer.start()
Другие относительно незначительные проблемы:
- аналогичные имена атрибутов (например,
centralwidget
, что слишком аналогично centralWidget()
) QMainWindow следует избегать, поскольку они могут создавать путаницу и приводить к трудностям в обнаружении ошибок и проблем; - таймер, который действует на объект, не должен создаваться вне объекта, который в конечном итоге вызовет / получить доступ / показать его (даже если косвенно); хотя с технической точки зрения в этом нет ничего плохого, обычно лучше сохранять объекты «организованными», чтобы к ним можно было обращаться при необходимости (например, показывать окно и останавливать таймер до истечения времени ожидания);
- создание новый экземпляр главного окна не предлагается, так как он уже существует; это связано с предыдущим пунктом: если у вас есть прямая ссылка на таймер и окна, вы также можете вызвать
self.someWindow.show()
; - , избегая смешивания и путаницы стилей имен: вы ' мы использовали имена в верхнем регистре для атрибутов (
Waiver
) и нижние для классов (popup_on_waiver
), в то время как это должно быть наоборот; тогда есть также mixedCase (returnInterval
) и under_score (hide_main
); выберите стиль и сохраните его (подробнее об этом см. в руководстве по стилю для Python code , он же PEP-8);
Я предпочел редактировать только части вашего кода, который мешал работе программы, но вы должны действительно помнить вышеупомянутые аспекты, даже если они «относительно незначительны» (акцент на относительно ).
Наконец, ( тривиально, но не несущественно): следует избегать смешивания режимов импорта из одних и тех же модулей: либо вы используете импорт с подстановочными знаками, например from module import *
(но обычно не должен ), либо явные, например from module import ClassA, ClassB, [...]
; для больших модулей, таких как PyQt5, обычно импортируется субмодуль, например from PyQt5 import QtWidgets
:
Хорошо:
from PyQt5 import QtWidgets
class SomeWidget(QtWidgets.QWidget):
# ...
Также хорошо, но, как правило, очень неприятный, как вы должны помнить добавляйте классы каждый раз, когда вам нужен новый, и у вас может получиться очень длинный список импорта, что может привести к ненужным классам, поскольку в итоге вы не используете некоторые (также, я сомневаюсь, что есть существенное преимущество, по крайней мере, в Qt) :
from PyQt5.QtWidgets import QWidget, QHBoxLayout # etc...
class SomeWidget(QWidget):
# ...
Не очень хорошо, но это работает (хранение имен подмодулей может быть полезно, также помня об их "области видимости") и ведет себя как предыдущий:
from PyQt5.QtWidgets import *
И это, это просто неправильно (я имею в виду, это работает, но это не имеет никакого смысла):
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QWidget