![](/img/trans.png)
[英]How to open second window from main dialog window with pyqt5 and qt designer
[英]How to trigger a method in a main Window from a dialog window in PyQt5?
我是 PyQt 的初学者,并尝试使用用户在另一个对话框 window 中提供的信息更新主 window 中的小部件。
这是我的主要 window:
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()
这是对话框 window:
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
编辑:我得到的错误是:(不知何故它只将第一行粘贴为代码)
Traceback (most recent call last):
File "D:/Data/Zeitreihen_1.0x2.py", line 141, in opensecondwindow
self.sw = lesen(self)
File "D:/Data/Zeitreihen_1.0x2.py", line 35, in __init__
self.addfile.clicked.connect(self.updatebez(widgetname,self.filename))
AttributeError: 'lesen' object has no attribute 'updatebez'
An exception has occurred, use %tb to see the full traceback.
SystemExit: 0
方法 updatez 背后的目标是从用户在对话框 window 中输入的文本中更新主 window 中的 QLabel object。 在添加方法并尝试在对话框 window 中调用它之前,一切正常。 当我尝试单击显示对话框 window 的按钮时,现在会出现错误。
我知道最好的解决方案是为主要 window 和对话框 window 之间的信号设置一个新的 class ,但我无法正确处理。 因此,我想知道是否可以让代码在不使用信号的情况下完成它必须做的事情。
在此先感谢,互联网向导!
您的代码存在各种问题,我会在回答时尝试解决这些问题。
该错误的主要原因是,正如错误报告的那样,您正在尝试调用不存在的 class 实例的属性: updatebez
是主 window 的成员,而不是对话框的成员(记住: self
是约定命名参考class 实例)。
无论如何,即使解决了这个问题(通过调用parent.updatebez
),它也不会起作用:信号/插槽连接通过使用可调用函数(插槽)来工作,因为连接是“交互式接口”,每次都必须做出不同的反应根据到信号的参数; 当你连接一个信号时,你实际上传递了一个对 function 的引用(它还没有运行,也不应该运行),并且只有在发出该信号时才会实际调用 function。 可能使用信号 arguments 作为其参数。
在您的情况下,您连接到 function调用,而不是它的引用,并且该调用可能会返回某个值或 None (所有未显式返回值的函数都隐式返回 None),这将导致连接错误:Qt期望对可调用对象的引用,但由于 function 正在就地调用,它取而代之的是返回其返回值,从而导致“未处理的 TypeError”异常。
“交互式界面”概念很重要:即使解决了上述问题,您也将始终以slotnr
和widgetname
变量的“静态”值结束。 在 python 中,变量和属性通常是 static:如果 spinbox 值更改,则slotnr
将永远不会更改。
您需要创建一个widgetname
,每次单击按钮时“即时”计算小部件名称,然后调用主 Z05B8C74CBD96FBF2DE4C1A352702FFF4Z 的 function。
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
函数。 但是,您应该小心使用它们:虽然它们是有用的“一次性快捷方式”,但有时为了可读性和调试目的,最好编写一个实际的 function 来代替。
最后但同样重要的是,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
来获取您要查找的小部件; when using loadUi
(or self.setupUi(self)
with the multiple inheritance approach ) Qt automatically creates attribute names for all objects of the UI using their Qt object name: if your QSpinBox object name is "spinBox" in Designer, you can simply access它与self.spinBox
; 如果使用单个 inheritance 方法,则小部件将是self.ui
的子级(因此,上面示例中的self.ui.spinBox
);updatebez
function 插槽时,无需设置self.widg
;setText()
后不需要调用update()
) ,因为它会自动刷新 label;updatebez()
( self.Bez.text()
)中使用行编辑text()
) ,否则您将获得行编辑 object (不是字符串);__init__
中调用show()
;mixedCase
实例和变量名称应小写(在处理 Qt 时可能使用混合大小写);这是一个基于您的代码的示例,其中包含上面编写的所有内容(我只显示不同之处):
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()))
最后,在 StackOverflow 上发布问题时,您应该花一些时间仔细编辑您的示例(甚至到编写全新代码的程度,这通常有助于在提出问题之前找到解决方案); 此外,最好坚持使用英语并避免本地化 function 和变量名称,因为它确实提高了人们专注于您的问题的能力(因此更容易帮助您),而不是被可能对您没有意义的名称分心他们:你会惊讶于有那么多人因为这个原因而放弃帮助别人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.