Python 如何从PyQt5中的对话框窗口触发主窗口中的方法?
我是PyQt的初学者,尝试用用户在另一个对话框窗口中提供的信息更新主窗口中的小部件 这是我的主窗口:Python 如何从PyQt5中的对话框窗口触发主窗口中的方法?,python,class,methods,pyqt5,signals,Python,Class,Methods,Pyqt5,Signals,我是PyQt的初学者,尝试用用户在另一个对话框窗口中提供的信息更新主窗口中的小部件 这是我的主窗口: class Window(QtWidgets.QMainWindow): def __init__(self): super(Window, self).__init__() uic.loadUi('GUI_MainWindow.ui',self) self.setWindowTitle("BR")
class Window(QtWidgets.QMainWindow):
def __init__(self):
super(Window, self).__init__()
uic.loadUi('GUI_MainWindow.ui',self)
self.setWindowTitle("BR")
self.statusBar()
#save File Action
saveFile= QtWidgets.QAction('&Profil speichern',self)
saveFile.setShortcut('CTRL+S')
saveFile.setStatusTip('Save File')
saveFile.triggered.connect(self.file_save)
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('&Datei')
fileMenu.addAction(saveFile)
self.home()
def home(self):
self.dlg = self.findChild(QtWidgets.QPushButton, 'addfile')
self.dlg.clicked.connect(self.opensecondwindow)
self.show()
# this is the method that I want to call
def updatebez(self,widgetname,filename):
self.widg = self.findChild(QLabel, str(self.widgetname))
self.widg.setText(filename)
self.update()
print(self.widg.Text())
#calling the dialog window
def opensecondwindow(self):
self.sw = lesen(self)
self.sw.show()
def file_save(self):
name, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Save File',options=QFileDialog.DontUseNativeDialog)
file = open(name, 'w')
text = self.textEdit.toPlainText()
file.write(text)
file.close()
这是对话框窗口:
class lesen(QtWidgets.QDialog):
def __init__(self,parent):
global afl
global calendar
global fn
super(lesen, self).__init__(parent)
uic.loadUi('Kal.ui',self)
self.setWindowTitle("Parametrierung")
afl = self.findChild(QtWidgets.QLineEdit, 'Aufloesung')
calendar = self.findChild(QtWidgets.QCalendarWidget, 'Calendar')
self.addfile = self.findChild(QtWidgets.QPushButton, 'chooseFile')
slot = self.findChild(QtWidgets.QSpinBox, 'spinBox')
slotnr = slot.text()
widgetname = 'ZRName'+ slotnr
self.filename = self.findChild(QtWidgets.QLineEdit, 'Bez')
self.addfile.clicked.connect(self.updatebez(widgetname,self.filename))
self.addfile.clicked.connect(self.file_open)
def Datenanpassung(self, tempfile):
list=[]
zeitabstand = int(afl.text())*60
datum = calendar.selectedDate()
a = datetime.datetime(datum.year(),datum.month(),datum.day(),00,00,00)
for row in tempfile:
a = a + datetime.timedelta(0,zeitabstand)
datetimestr= str(a.date()) + ' ' + str(a.time())
row = [datetimestr, row[0]]
list.append(row)
return list
def file_open(self):
#Dateiauswahl
global name
global tempfile
global fn
tempfile = []
filters = ""
selected_filter = "csv or json (*.csv *.json)"
name, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Datei auswählen', filters, selected_filter,
options=QFileDialog.DontUseNativeDialog)
file = open(name, 'r', newline='')
for row in csv.reader(file):
tempfile.append(row)
self.anpassen = self.findChild(QtWidgets.QCheckBox, 'checkBox')
if self.anpassen.isChecked():
newfile = self.Datenanpassung(tempfile)
with open(os.path.basename(file.name)[:-4] +'_mit_DateTime.csv', 'w', newline='') as csvFile:
writer = csv.writer(csvFile)
writer.writerows(newfile)
file = open(os.path.basename(file.name)[:-4] +'_mit_DateTime.csv', 'r', newline='')
reader = csv.DictReader( file, fieldnames = ( "DateTime","Wert"))
out = json.dumps(list(reader))
f = open( os.path.basename(file.name)[:-4] +'_mit_DateTime.json', 'w')
f.write(out)
else:
pass
编辑:我得到的错误是:(不知何故,它只将第一行粘贴为代码)
updatez方法背后的目标是从用户在对话框窗口的QLineEdit中键入的文本更新主窗口中的QLabel对象。
在添加方法并尝试在对话框窗口中调用它之前,一切正常。现在,当我尝试单击显示对话框窗口的按钮时,会出现错误
我知道最好的解决方案是为主窗口和对话框窗口之间的信号设置一个新类,但我无法正确地获得它。因此,我想知道是否有可能使代码在不使用信号的情况下完成它必须做的事情
提前感谢,网络奇才们 您的代码存在各种问题,我将在回答时尝试解决这些问题 该错误的主要原因是,在错误报告中,您试图调用不存在的类实例的属性:
updatebez
是主窗口的成员,而不是对话框的成员(请记住:self
是类实例的成员)
无论如何,即使通过调用parent.updatebez
解决了这个问题,它也不会工作:信号/插槽连接通过使用可调用函数(插槽)工作,因为连接是“交互式接口”,每次都必须根据信号的参数做出不同的反应;当您连接一个信号时,您实际上传递了一个对该函数的引用(它还没有运行,也不应该运行!),并且只有在发出该信号时才会实际调用该函数,可能会使用信号参数作为其参数。在您的情况下,您连接到一个函数调用,而不是它的引用,并且该调用可能会返回一些值或无值(所有未显式返回值的函数都隐式返回无值),这将导致连接错误:Qt希望引用一个可调用函数,但由于函数正在被就地调用,相反,它会返回其返回值,导致“未处理的TypeError”异常 “交互界面”的概念很重要:即使解决了上述问题,您也将始终以
slotnr
和widgetname
变量的“静态”值结束。在python中,变量和属性通常是静态的:slotnr
如果spinbox值发生变化,则永远不会改变
您需要创建一个函数,每次单击按钮时计算widgetname
“动态”,然后调用主窗口的函数
class Lesen(QtWidgets.QDialog):
def __init__(self, parent):
# ...
self.addfile.clicked.connect(self.sendUpdate)
def sendUpdate(self):
widgetname = 'ZRName'+ self.spinBox.text()
self.parent().updatebez(widgetname, self.Bez.text()))
或者,也可以使用函数。不过,在使用它们时应该小心:虽然它们是有用的“单定时器快捷方式”,但出于可读性和调试目的,有时最好编写一个实际的函数
最后但并非最不重要的一点是,lambda是函数,因此如果不保留对它们的引用,就无法断开与它们单独连接的信号
class Lesen(QtWidgets.QDialog):
def __init__(self, parent):
# ...
self.addfile.clicked.connect(lambda: self.parent().updatebez(
'ZRName' + self.spinBox.text(), self.Bez.text()))
关于上述示例和您的代码的一些注释:
- 无需使用
获取您正在寻找的小部件;当使用findChild
(或loadUi
)时,Qt会自动使用其Qt对象名称为UI的所有对象创建属性名称:如果您的QSpinBox对象名称在Designer中为“spinBox”,则只需使用self.setupUi(self)
即可访问它;如果使用单继承方法,小部件将是self.spinBox
的子部件(因此,在上面的示例中,self.ui
)李>self.ui.spinBox
- 基于上述原因,每次调用
函数槽时,无需设置updatebez
李>self.widg
- 使用
后不需要调用setText()
,因为它会自动刷新标签李>update()
- 您可能希望在
(updatebez()
)中使用行编辑self.Bez.text()
),否则您将得到行编辑对象(它不是字符串)李>text()
- 如果对话框是持久的(非持久的),主窗口将始终获得鼠标/键盘交互,即使显示该对话框,这将导致用户能够打开多个对话框;你可能不想这样李>
- 通常最好避免在
中调用
李>show()
- 然而,对于简单的情况,使用其他类实例的静态函数名的实现没有错,接口通常是首选的,这就是信号和插槽存在的目的:除了对象可重用性,主要的好处是可读性、调试和进一步编辑(特别是重构时);因此,是的,最好为对话框创建自己的信号,然后从主窗口连接它李>
- 正如建议的那样:类名应始终大写,逗号后应始终有一个空格,类实例和变量名应为小写(处理Qt时可能使用
)李>mixedCase
下面是一个基于您的代码的示例,其中包括上面编写的所有内容(我只展示了不同之处): 最后,在StackOverflow上发布问题时,您应该采取(甚至可以编写全新的代码,这通常有助于在提问之前找到解决方案);此外,最好还是坚持使用英语,避免使用本地化的函数和变量名,因为这确实提高了人们专注于你的问题的能力(因此更容易帮助你),而不是被那些对他们来说可能毫无意义的名字分散注意力:你会惊讶于有那么多人放弃帮助你
class Lesen(QtWidgets.QDialog):
def __init__(self, parent):
# ...
self.addfile.clicked.connect(lambda: self.parent().updatebez(
'ZRName' + self.spinBox.text(), self.Bez.text()))
class Window(QtWidgets.QMainWindow):
def __init__(self):
super(Window, self).__init__()
uic.loadUi('GUI_MainWindow.ui', self)
self.setWindowTitle("BR")
self.statusBar()
#save File Action
saveFile= QtWidgets.QAction('&Profil speichern', self)
saveFile.setShortcut('CTRL+S')
saveFile.setStatusTip('Save File')
saveFile.triggered.connect(self.file_save)
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu('&Datei')
fileMenu.addAction(saveFile)
# create the dialog, just once
self.lesenDialog = Lesen(self)
self.sw.dataChanged.connect(self.updatebez)
# show the dialog when clicking on the button, no need to create a
# new one each time;
self.addfile.clicked.connect(self.sw.show)
def updatebez(self, index, filename):
widgetname = 'ZRName{}'.format(index)
widget = getattr(self, widgetname)
widget.setText(filename)
print(self.widg.Text())
class Lesen(QtWidgets.QDialog):
dataChanged = QtCore.pyqtSignal(int, str)
def __init__(self, parent):
# ...
self.addfile.clicked.connect(lambda: self.dataChanged.emit(
self.spinBox.value(), self.Bez.text()))