重新加载 PyQt5 应用程序而不先重新启动它
Posted
技术标签:
【中文标题】重新加载 PyQt5 应用程序而不先重新启动它【英文标题】:Reloading a PyQt5 App without Restarting it first 【发布时间】:2021-04-07 15:11:19 【问题描述】:我创建了一个应用程序,并在其中一个 Windows (CreateProjectWindow(QDialog)
) 上填写了一份表格,然后我使用 self.buttonBox.accepted.connect(self.getInfo)
提交了该表格。
提交时,我希望UpdateProjecWindow(QDialog)
中的self.tableComboBox
自动并立即更新,而无需我先重新启动应用程序。 CreateProjectWindow(QDialog)
中的最后四行代码是我尝试过的,但它们都不起作用。下面是sn-p的代码:
from __future__ import print_function
from datetime import date
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
import os
import subprocess
import pandas as pd
import time
Class CreateProjectWindow(QDialog):
def __init__(self):
super(CreateProjectWindow, self).__init__()
self.setWindowTitle("Create a new project")
self.setGeometry(100, 100, 300, 400)
self.timeStampLineEdit = QDateTime.currentDateTime().toString('MM-dd-yyyy hh:mm:ss')
self.surnameLineEdit = QLineEdit()
self.firstnameLineEdit = QLineEdit()
self.dateOfBirthLineEdit = QDateEdit(calendarPopup=True, displayFormat='MM-dd-yyyy')
self.createForm()
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.buttonBox.accepted.connect(self.getInfo)
self.buttonBox.rejected.connect(self.reject)
def getInfo():
output = 'timestamp': self.timeStampLineEdit,\
'surname' : self.surnameLineEdit,\
'firstname' : self.firstnameLineEdit,\
'dob' : self.dateOfBirthLineEdit
df = pd.DataFrame(output, index=[0])
df.to_excel('to/some/local/path/profiles_data.xlsx')
return None
QApplication.processEvents() # attempt 1 but doesn't work
QApplication(sys.argv).reload() # attempt 2 but doesn't work
subprocess.Popen([sys.executable, FILEPATH]) # attempt 3 restarts the app which I don't want
os.execl(sys.executable, sys.executable, * sys.argv) # attempt 4 restarts the app which I don't want.
def creatForm(self):
layout = QFormLayout()
layout.addRow(QLabel("Surname"), self.surnameLineEdit)
layout.addRow(QLabel("First Name"), self.firstnameLineEdit)
layout.addRow(QLabel("D.O.B"), self.dateOfBirthLineEdit)
self.formGroupBox.setLayout(layout)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(self.buttonBox)
self.setLayout(mainLayout)
class UpdateProjectWindow(QDialog):
def __init__(self):
super(UpdateProjectWindow, self).__init__()
self.setWindowTitle("Parameter Inputs")
self.setGeometry(100, 100, 300, 400)
self.formGroupBox = QGroupBox("Some Window")
self.tableComboBox = QComboBox()
df = pd.read_excel('to/some/local/path/profiles_data.xlsx')
names = df['surname']
self.tableComboBox.addItems(names)
createForm()
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.buttonBox.accepted.connect(self.processInfo)
self.buttonBox.rejected.connect(self.reject)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
mainLayout.addWidget(self.buttonBox)
self.setLayout(mainLayout)
def processInfo(self):
get_name = self.tableComboBox.currentText()
print(get_name)
def createForm(self):
layout = QFormLayout()
layout.addRow(QLabel("Select Surname"), self.tableComboBox)
self.formGroupBox.setLayout(layout)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# setting window title
self.setWindowTitle("MyApp")
# setting geometry to the window
self.setGeometry(200, 200, 400, 10)
self.window1 = CreateProjectWindow()
self.window2 = UpdateProjectWindow()
l = QVBoxLayout()
button1 = QPushButton("Create a Project")
button1.clicked.connect(
lambda checked: self.toggle_window(self.window1)
)
l.addWidget(button1)
button2 = QPushButton("Update a Project")
button2.clicked.connect(
lambda checked: self.toggle_window(self.window2)
)
l.addWidget(button2)
w = QWidget()
w.setLayout(l)
self.setCentralWidget(w)
def toggle_window(self, window):
if window.isVisible():
window.hide()
else:
window.show()
if __name__=="__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
【问题讨论】:
附代码时请注意:您的示例包含多个问题(“Class”应该是小写的,缩进问题很多,对createForm
的函数调用都是错误的,并且有属性在声明之前使用)。在粘贴之前总是尝试你的代码,我们应该专注于你的代码做了什么,而不是纠正你的语法。
【参考方案1】:
通常不需要重新启动 Qt 应用程序,当然这对于您的情况也不是必需的:重新启动 QApplication 几乎就像关闭程序并再次打开它,这样做只是为了更新一些数据并不会产生任何影响完全有感觉。
一种可能的解决方案是为第一个窗口类创建一个自定义信号,该信号将在数据库更新时发出,然后将该信号连接到另一个窗口中加载数据的函数(这意味着该函数将也可以在开头调用)。
class CreateProjectWindow(QDialog):
dataChanged = pyqtSignal()
# ...
def getInfo(self):
# note that your original data was completely wrong, as you tried to add
# the *widgets* to the frame, while you need to add their *values*
output = 'timestamp': self.timeStampLineEdit,
'surname' : self.surnameLineEdit.text(),
'firstname' : self.firstnameLineEdit.text(),
'dob' : self.dateOfBirthLineEdit.date().toString()
df = pd.DataFrame(output, index=[0])
df.to_excel('to/some/local/path/profiles_data.xlsx')
self.dataChanged.emit()
self.accept()
class UpdateProjectWindow(QDialog):
def __init__(self):
# ...
self.tableComboBox = QComboBox()
self.updateData()
self.createForm()
# ...
def updateData(self):
self.tableComboBox.clear()
df = pd.read_excel('to/some/local/path/profiles_data.xlsx')
names = df['surname']
self.tableComboBox.addItems(names)
class MainWindow(QMainWindow):
def __init__(self):
# ...
self.window1.dataChanged.connect(self.window2.updateData)
除此之外,你必须对你的代码更加小心:我花了更多的时间来纠正你的语法和错误,而不是真正给你这个答案。请注意,您的示例还有其他各种问题,但我不会在这里解决它们,因为它不在主题范围内。本质上,写程序的时候一定要多加注意。
【讨论】:
谢谢@musicamante。我已尝试实施您的解决方案,但我认为 getInfo() 中的输出在连接时有空白字段,因为我收到以下错误:ValueError: No engine for filetype: ''
再次感谢@musicamante,问题已解决。我更改了以下内容以使其正常工作:从:self.window1.dataChanged.connect(self.window2.updateData)
到:self.window1.dataChanged.connect(self.window2.__init__)
@MichaelKateregga 不,不!这真是一个糟糕,可怕的想法!如果你有那个错误,那么你可能做错了什么,从那个错误可能是路径(如上所述,你应该更加小心你的语法)。因为这样的错误而调用__init__
是完全和绝对错误的(实际上,无论如何它都是错误的,除非你真的,真的知道你在做什么)。错误应该根据他们的信息来解决,而不是试图做随机的事情。如果您在开车时看到燃油灯亮起,您不会跳下车窗去买新车。
嗨@musicamante,该错误是由于在尚未填充数据时调用updateData,即姓氏,名字字段等是空字符串''所以我的其余代码不起作用。调用 init 会以某种方式填充所有字段并更新第二个窗口。我没有给你完整的代码,但是 updateData 函数有几个组合框,它们在其他组合框中的 currentTextChanged 上得到更新。您可以通过 michaelk@aims.ac.za 给我发送电子邮件,以便进一步讨论。
我看不出应该讨论什么。如果在__init__
期间数据为空,请添加正确避免问题的检查,或者您正确实现 updateData 函数。 再次调用 init 作为解决方法只是懒惰,它不是解决方案,而且迟早肯定会产生大问题。
以上是关于重新加载 PyQt5 应用程序而不先重新启动它的主要内容,如果未能解决你的问题,请参考以下文章
使用 nodemon 或 supervisor 仅重新加载文件而不重新启动所有服务器 - WebStorm
在 IntelliJ 中强制重新加载环境变量...而不重新启动?