Вот еще одно возможное решение;хотя он может показаться немного более сложным, чем другой , предложенный CodeSurgeon, на мой взгляд, он гораздо более расширяемый - и как-то более элегантный.
Подвох здесь подклассQLineEdit, который встраивает дочерний QLabel, который становится видимым, только если в поле есть текст.Переопределение resizeEvent
было добавлено, чтобы гарантировать, что метка "*" всегда корректно размещается при изменении размера окна.
У этого подхода много преимуществ, но самое важное то, что подкласс «основного» виджета,вместо создания нового, встраивающего другие виджеты, автоматически предоставляются все его методы и свойства.
Итак, все это позволяет вам добавлять столько [текстовых] полей, сколько вы хотите, и включать / отключать отправку.Кнопка только в том случае, если в каждом из них есть какой-то контент.
import sys
from PyQt5 import QtCore, QtWidgets
class MyLineEdit(QtWidgets.QLineEdit):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# the "invalid" label *has* to be a child of this QLineEdit
self.invalidLabel = QtWidgets.QLabel('*', self)
self.invalidLabel.setStyleSheet('color: red;')
spacing = 2
# get default margins and re-set them accordingly
self.leftMargin, self.topMargin, self.rightMargin, self.bottomMargin = self.getContentsMargins()
self.rightMargin += self.invalidLabel.minimumSizeHint().width() + spacing
self.setContentsMargins(self.leftMargin, self.topMargin, self.rightMargin + spacing, self.bottomMargin)
self.textChanged.connect(self.setValid)
self.setValid(self.text())
def setValid(self, text):
self.invalidLabel.setVisible(not bool(text))
def isValid(self):
return bool(self.text())
def resizeEvent(self, event):
self.invalidLabel.setGeometry(self.width() - self.rightMargin, self.topMargin,
self.invalidLabel.minimumSizeHint().width(), self.height() - self.topMargin - self.bottomMargin)
class MyApp(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setup()
def setup(self):
self.form = QtWidgets.QGroupBox("Add Student")
self.setCentralWidget(self.form)
self.formLayout = QtWidgets.QFormLayout()
self.form.setLayout(self.formLayout)
self.fields = []
self.create_field('Starting Date:', defaultValue=QtCore.QDate.currentDate().toString('MM/dd/yyyy'))
self.create_field('First Name:')
self.create_field('Last Name:')
self.create_submit_button()
def create_field(self, label, defaultValue=''):
field = MyLineEdit(defaultValue)
self.fields.append(field)
field.defaultValue = field.text()
self.formLayout.addRow(label, field)
field.textChanged.connect(self.checkFields)
def create_submit_button(self):
self.submitButton = QtWidgets.QPushButton('Add Student')
self.formLayout.addRow(self.submitButton)
self.submitButton.clicked.connect(self.submit)
self.submitButton.setEnabled(False)
self.checkFields()
def checkFields(self):
self.submitButton.setEnabled(all(field.isValid() for field in self.fields))
def submit(self):
# doSomething([field.text() for field in self.fields)
for field in self.fields:
field.setText(field.defaultValue)
app = QtWidgets.QApplication(sys.argv)
w = MyApp()
w.show()
sys.exit(app.exec_())
Как уже указывалось, вам следует подумать о проверке содержимого даты (так как можно ввести что угодно), так как вы используете строкуedit.
Лучшее решение - использовать QDateEdit, но вам нужно будет создать его подкласс, как я это делал с QLineEdit, и создать отдельную функцию create
, и, очевидно, она будет "проигнорирована" при отправке "проверки"поскольку поля QDateEdit автоматически допускают допустимые вводы даты.
В противном случае вы можете использовать QValidator, ноt это было бы общеизвестной болью в a **, главным образом потому, что QDateTime уже обеспечивает проверку и хорошее представление календаря с помощью setCalendarPopup(True)
, а проверка даты с помощью регулярного выражения действительно раздражает.