每当我点击 + 按钮时,我都想像第一行一样添加一个新行(lineEdit 旁边的一个新 + 按钮),并在相应的 lineEdit 中打印文本。
我设法这样做了,但我不明白程序如何知道我点击了哪个按钮来打印旁边的文本!
from PyQt5 import QtCore, QtGui, QtWidgets
count = 1
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(569, 176)
self.formLayout = QtWidgets.QFormLayout(Form)
self.formLayout.setObjectName("formLayout")
self.lineEdit_1 = QtWidgets.QLineEdit(Form)
self.lineEdit_1.setObjectName("lineEdit_1")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineEdit_1)
self.pushButton_1 = QtWidgets.QPushButton(Form)
self.pushButton_1.setObjectName("pushButton_1")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.pushButton_1)
self.pushButton_print = QtWidgets.QPushButton(Form)
self.pushButton_print.setObjectName("pushButton_print")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.pushButton_print)
self.pushButton_1.clicked.connect(self.add)
self.pushButton_print.clicked.connect(self.appear)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton_1.setText(_translate("Form", "+"))
self.pushButton_print.setText(_translate("Form", "print 4th"))
def add(self):
global count
count+=1
new_btn = QtWidgets.QPushButton("+", Form)
new_line = QtWidgets.QLineEdit(Form)
#new_btn.setObjectName(f"pushButton_{count}")
#new_line.setObjectName(f"lineEdit_{count}")
self.formLayout.setWidget(count, QtWidgets.QFormLayout.LabelRole, new_btn)
self.formLayout.setWidget(count, QtWidgets.QFormLayout.FieldRole, new_line)
new_btn.clicked.connect(lambda: print(new_line.text()))
new_btn.clicked.connect(self.add)
def appear(self):
lineEdit = Form.findChild(QtWidgets.QLineEdit, f"lineEdit_4")
print(lineEdit.text())
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
此外,当我将新按钮绑定到“self”(如“self.new_button”)时,它只会打印最新的 lineEdit 而不是较早的。
为什么会这样?有没有更好的方法来做我想做的事?
答案 0 :(得分:1)
您将局部变量的范围与实例属性混淆了。
lambda 函数始终使用创建它的函数的 local 范围。
在您的示例中,new_line
是在函数 app
中创建的引用,创建时。结果是它总是引用那个行编辑。
如果你创建了一个实例属性(比如self.new_line
),那么引用会在对象树上解析;换句话说:找到“self
”的“new_line”属性(它是Ui_Form
实例,以及任何实例方法的函数的第一个参数)。由于您总是在每次创建新行时覆盖该属性,因此它将始终引用 最新 行编辑。
我准备了一个小例子,大概可以说明这两个方面的区别。文本字段将显示点击的结果:实际点击的行(row
函数的 范围 中的 add
)和该行的实例属性设置,每次创建新行时都会覆盖该属性。
from PyQt5 import QtWidgets
class ScopeTest(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.row = 0
layout = QtWidgets.QVBoxLayout(self)
self.logView = QtWidgets.QPlainTextEdit(readOnly=True, minimumHeight=200)
layout.addWidget(self.logView)
self.addButton = QtWidgets.QPushButton('Add row')
layout.addWidget(self.addButton)
layout.addWidget(QtWidgets.QFrame(frameShape=QtWidgets.QFrame.HLine))
self.addButton.clicked.connect(self.add)
def add(self):
self.row += 1
# note that the following line is important!
# "row" is a *local* variable! "self.row" is an *instance attribute*!
row = self.row
button = QtWidgets.QPushButton('Row {}'.format(self.row))
self.layout().addWidget(button)
button.clicked.connect(lambda: self.log(row, self.row))
def log(self, clickedRow, scopeRow):
self.logView.appendPlainText('Clicked: {}, Scope: {}'.format(
clickedRow, scopeRow))
self.logView.verticalScrollBar().setValue(
self.logView.verticalScrollBar().maximum())
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = ScopeTest()
test.show()
sys.exit(app.exec_())
一些进一步的建议:
lambda
和 functool.partial
之间的区别:它们的行为相似(因为它们都返回对函数的引用),但它们对参数的评估不同;在某些情况下,您可能需要其中一种;pyuic
生成的文件不应该、永远被修改(你也不应该尝试模仿它们的行为);有很多原因被认为是不好的做法,而且由于它们不是主题,我只会给你一个“除非你真的知道你什么,否则不要这样做”重新做”(这通常会导致:“如果你知道你在做什么,你就不会编辑它们”);在关于 using Designer 的官方指南中阅读有关这些文件的正确使用的更多信息;幸运的是,最新的 PyQt 版本添加了一个更详细的警告,并且该警告永远不应被低估;findChild
(和 findChildren
)应该只用于 Qt 内部创建的小部件(例如 QCalendarWidget 的导航按钮);使用 pyuic 文件(或 uic
模块函数)自动为所有小部件生成属性;如果您在 Designer 中有一个名为 lineEdit_4
的小部件,并且您从 .ui
文件或使用 pyuic 创建了 GUI,则您已经可以使用 self.lineEdit_4
;