用户使用QTimer在QDialog组合框中选择了间隔后,如何从QDialog启动QMainwindow

时间:2020-03-22 19:10:06

标签: pyqt5

我有一个名为Main的QMainWIndow,它调用了名为popup_on_waiver的QDialog。 QDialog有一个组合框可以选择小时数。用户选择小时数并单击“确定”后,我想关闭弹出窗口,隐藏QMainwindow,并在组合框中选择小时数后启动QMainwindow。该程序将一直运行,直到用户选择小时数和单击确定为止。它关闭弹出窗口并隐藏主窗口。(要求应用程序必须永远在隐藏状态下运行,因此必须隐藏主窗口)。当它调用launch_after_interval时,其失败,并显示错误“进程已完成,退出代码为1073741845”。请告知正确的步骤。 我将在下面未提供的某些其他条件下启动主窗口,因此我编写了一个单独的块,用于在用户选择的豁免时间之后再次启动主窗口。另外,我尝试获取弹出窗口的结果,接受还是拒绝,但没有返回任何内容。

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import QUrl, Qt, QTimer, QSize, QRect
import sys


class popup_on_waiver(QDialog):
    #pop up window
    def __init__(self, parent=None):
        super(QDialog,self).__init__(parent)
        self.setWindowFlags(Qt.WindowStaysOnTopHint)
        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)  #buttons

        vbox = QVBoxLayout(self)   #layout
        vbox.addWidget(self.cb)
        vbox.addWidget(self.buttons)
        self.setLayout(vbox)


    def hide_main(self, hours):
        self.accept
        self.parent().hide()
        launch_after_interval(self.interval)  #calling timer function


    def returnInterval(self, hours):      #combobox value that is number of hours
        self.interval = int(hours) * 3600 * 1000

#QMainwindow
class Main(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowFlags(Qt.WindowStaysOnTopHint)
        self.initUI()

    def initUI(self):
        self.centralwidget = QWidget(self)
        self.Waiver = QPushButton('Waiver')
        self.Waiver.clicked.connect(lambda: self.popup())

        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):
        self.p = popup_on_waiver()
        self.p.exec_()


def launch_after_interval(interval): 
    timer = QTimer()
    timer.setSingleShot(True)
    timer.setInterval(interval)
    timer.timeout().connect(lambda: Main())
    timer.start()

1 个答案:

答案 0 :(得分:0)

您的代码存在各种问题:

  1. 您在不设置父级的情况下创建了对话框,因此当您尝试调用self.parent().hide()时该对话框将不起作用,因为parent()返回了None,而显然{{1} 1}}属性;
  2. 您已将hide信号连接到accepted,这需要一个参数,但是accepted信号没有任何内容;
  3. 您错过了hide_mainaccepted的括号,因此不会被调用;
  4. hide_main仅在组合索引更改时设置,但如果用户不更改(保留默认值),则不会设置任何self.interval
  5. 您正在设置self.interval标志,仅 ,它将重置其他所有窗口标志;结果将是您将没有新窗口,但有一个“嵌入”在父级中的小部件;正确设置标志,您应该使用WindowStaysOnTopHint;
  6. 信号不能被“调用”,因此self.setWindowFlags(self.flags() | Qt.WindowStaysOnTopHint)中应该没有括号;
  7. timer.timeout().connect对象在timer范围之外没有引用,也没有设置父对象,因此一旦函数返回,它将被删除并且永远不会被触发;
  8. li>

修改后的代码(修改以粗体显示):

launch_after_interval

其他相对小问题:

    应避免使用
  • 相似的属性名称(例如class popup_on_waiver(QDialog): def __init__(self, parent=None): super(QDialog,self).__init__(parent) self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) 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 self.interval = 3600000 # no arguments here! def hide_main(self): self.accept() # <-- 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(self.windowFlags() | Qt.WindowStaysOnTopHint) 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 self.Waiver.clicked.connect(self.popup) 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(self) 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 = QTimer(QApplication.instance()) timer.setSingleShot(True) timer.setInterval(interval) timer.timeout.connect(lambda: Main()) timer.start() ,它与QMainWindow的centralwidget太相似了),因为它们会造成混乱并导致难以发现错误和问题;
  • 不应在将最终调用/访问/显示该对象的对象之外(即使是间接地)创建作用于该对象的计时器;尽管从技术上讲它没有什么问题,但通常最好将对象保持“有序”,以便在需要时可以访问它们(例如,显示窗口并在超时之前停止计时器);
  • 不建议创建一个新的主窗口实例,因为已经存在。这与上一点有关:如果您直接引用计时器窗口,则也可以调用centralWidget();
  • 避免混淆命名方式:对于属性(self.someWindow.show())使用大写名称,对于类(Waiver)使用小写名称,但应该相反。然后还有mixCase(popup_on_waiver)和under_score(returnInterval);选择一种样式并保留该样式(请在style guide for Python code(又名PEP-8中阅读有关样式)的详细信息;

我更喜欢只编辑代码的那些阻止程序正常工作的部分,但是您应该牢记上面的内容,即使它们“相对较小”(强调相对 )。

最后,(琐碎但无关紧要):应避免混合使用来自相同模块的导入模式:您可以使用hide_main之类的通配符导入(但通常使用shouldn't)或{ {1}};对于PyQt5这样的大模块,通常会导入子模块,例如from module import *

好:

from module import ClassA, ClassB, [...]

也不错,但是却常常令人讨厌,因为每次需要一个新类时,您都必须记住要添加类,并且最终可能会得到很长的导入列表,最终可能会导致不必要的类。不使用某些功能(我也怀疑,至少在Qt上有很大的好处):

from PyQt5 import QtWidgets

不太好,但是可以(保留子模块名称来记住它们的“作用域”可能很有用),其行为与上一个相同:

from PyQt5 import QtWidgets

class SomeWidget(QtWidgets.QWidget):
    # ...

这是错误(我的意思是,它可以工作,但是没有任何意义):

from PyQt5.QtWidgets import QWidget, QHBoxLayout # etc...

class SomeWidget(QWidget):
    # ...
相关问题