Je voudrais activer ou désactiver QDialogButtonBox ou de préférence uniquement le bouton OK dans QDialog, en fonction du texte sélectionné de deux QComboBox (s).
Mon exemple est comme ci-dessous. Il ne fonctionne pas actuellement et les deux ComboBox fonctionnent indépendamment l'un de l'autre lors de l'activation ou de la désactivation de QDialogButtonBox.
class SheetColumns(QDialog): def __init__(self, column_header): super().__init__() self.setMinimumWidth(300) self.setWindowTitle("Input Column Names") self.column_headers = column_header self.column_headers.insert(0, ' ') self.setWhatsThis('Please match columns in your data sheet names' ' with the right side labels') col_names = ["Student Name:", "Student ID:", "Cohort:", "Gender:", "College:", "Department:", "Major:", "Minor", "Email:", "Adviser", "Adviser Email"] self.form_group_box = QGroupBox("Specify Column Names") self.layout = QFormLayout() for col_name in col_names: combo = QComboBox() combo.addItems(self.column_headers) self.layout.addRow(QLabel(col_name), combo) self.form_group_box.setLayout(self.layout) self.button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_box.setEnabled(False) self.mapper = QSignalMapper(self) comb_bx1 = self.layout.itemAt(0, 1).widget() comb_bx2 = self.layout.itemAt(1, 1).widget() comb_bx1.currentTextChanged.connect(self.mapper.map) comb_bx2.currentTextChanged.connect(self.mapper.map) self.mapper.setMapping(comb_bx1, comb_bx1.currentText()) self.mapper.setMapping(comb_bx2, comb_bx2.currentText()) self.mapper.mapped.connect(self.check_validity) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) main_layout = QVBoxLayout() main_layout.addWidget(self.form_group_box) main_layout.addWidget(self.button_box) self.setLayout(main_layout) def check_validity(self, text): print(text) if text == ' ': self.button_box.setEnabled(False) else: self.button_box.setEnabled(True)
Je voudrais que QDialogButtonBox soit activé lorsque le (s) currentText (s) dans les deux ComboBox, il y a autre chose que «», alors qu'il est désactivé quand ils sont tous les deux ».
J'ai essayé d'utiliser QSignalMapper
.
Cependant, je n'ai pas réussi à le faire fonctionner.
import sys from PyQt5.QtCore import QSignalMapper, pyqtSlot from PyQt5.QtWidgets import (QGroupBox, QFormLayout, QLabel, QComboBox, QApplication, QDialog, QDialogButtonBox, QVBoxLayout) class SheetColumns(QDialog): def __init__(self, column_header): super().__init__() self.setMinimumWidth(300) self.setWindowTitle("Input Column Names") self.column_headers = column_header self.column_headers.insert(0, ' ') self.setWhatsThis('Please match columns in your data sheet names' ' with the right side labels') col_names = ["Student Name:", "Student ID:", "Cohort:", "Gender:", "College:", "Department:", "Major:", "Minor", "Email:", "Adviser", "Adviser Email"] self.form_group_box = QGroupBox("Specify Column Names") self.layout = QFormLayout() for col_name in col_names: combo = QComboBox() combo.addItems(self.column_headers) self.layout.addRow(QLabel(col_name), combo) self.form_group_box.setLayout(self.layout) self.button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_box.setEnabled(False) self.layout.itemAt(0, 1).widget().currentTextChanged.connect( self.check_validity) self.layout.itemAt(1, 1).widget().currentTextChanged.connect( self.check_validity) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) main_layout = QVBoxLayout() main_layout.addWidget(self.form_group_box) main_layout.addWidget(self.button_box) self.setLayout(main_layout) def check_validity(self, text): print(text) if text == ' ': self.button_box.setEnabled(False) else: self.button_box.setEnabled(True) if __name__ == '__main__': app = QApplication(sys.argv) dialog = SheetColumns(['name student', 'id', 'cohort', 'test 1']) sys.exit(dialog.exec_())
Quelqu'un pourrait-il me dire ce que je fais mal, ou y a-t-il une meilleure approche ?
Merci d'avance
3 Réponses :
Personnellement, je trouve le mappeur de signaux extrêmement déroutant et l'évite comme la peste. Voici comment je procéderais (je vais utiliser une classe factice pour rendre la vie plus facile):
class DummyDialog(QDialog): def __init__(self): self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.combo_box_1 = QComboBox() self.combo_box_2 = QComboBox() self.combo_1_text = "" # This could also be self.combo_box_1.text() self.combo_2_text = "" self.combo_box_1.currentTextChanged.connect(self.combo_one_changed) self.combo_box_2.currentTextChanged.connect(self.combo_two_changed) def combo_one_changed(self, text): self.combo_1_text = text def combo_two_changed(self, text): self.combo_2_text = text def check_validity(self): if self.combo_1_text and self.combo_2_text: self.button_box.setEnabled(True) else: self.button_box.setEnabled(False)
Faites-moi savoir si vous avez des problèmes avec cela, je viens de trouver cela rapidement.
EDIT: Je remarque également que vous définissez vos combos comme des locaux dans votre méthode init, ce qui peut également être un problème à cause de la propriété de pyqt. Si vous ne stockez pas de référence à l'objet, vous n'êtes pas assuré qu'il restera en existence et python pourrait le ramasser des déchets, ce qui signifie que vous risquez de perdre complètement vos connexions de signaux. Je ne peux pas dire que c'est ce qui se passe, mais en général, il est plus sûr de leur conserver une instance dans votre méthode init en les définissant plutôt comme des variables d'instance.
Votre "EDIT" est incorrect car lorsque vous ajoutez un widget à une mise en page, la propriété du widget sera prise par le widget où le widget a été défini, dans votre cas, la propriété de la QComboBox sera prise par la QGroupBox donc il n'y a pas problèmes avec le GC.
Ah c'est vrai que je ne faisais pas attention au fait qu'ils faisaient partie de la mise en page.
L'utilisation de QSignalMapper est surdimensionnée pour ce dont vous avez besoin, dans votre cas, il vous suffit d'itérer sur la QComboBox et de vérifier qu'elle n'a pas l'option appropriée et, en conséquence, d'activer le bouton comme indiqué ci-dessous:
class SheetColumns(QDialog): def __init__(self, column_header, parent=None): super().__init__(parent) self.setMinimumWidth(300) self.setWindowTitle("Input Column Names") self.column_headers = column_header self.setWhatsThis( "Please match columns in your data sheet names" " with the right side labels" ) col_names = [ "Student Name:", "Student ID:", "Cohort:", "Gender:", "College:", "Department:", "Major:", "Minor", "Email:", "Adviser", "Adviser Email", ] self.combos = [] flay = QFormLayout() for i, col_name in enumerate(col_names): combo = QComboBox() combo.addItems([""] + self.column_headers) flay.addRow(col_name, combo) if i in (0, 1): combo.currentIndexChanged.connect(self.check_validity) self.combos.append(combo) self.form_group_box = QGroupBox("Specify Column Names") self.form_group_box.setLayout(flay) self.button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel ) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) main_layout = QVBoxLayout(self) main_layout.addWidget(self.form_group_box) main_layout.addWidget(self.button_box) @pyqtSlot() def check_validity(self): is_enabled = True for combo in self.combos: if not combo.currentText(): is_enabled = False break button = self.button_box.button(QDialogButtonBox.Ok) button.setEnabled(is_enabled)
Merci à @eyllanesc pour sa réponse qui fonctionne parfaitement bien.
Le code ci-dessous convient mieux à mon cas d'utilisation et il est assez similaire à la réponse donnée par @eyllanesc suivant son concept .
class SheetColumns(QDialog): def __init__(self, column_header, parent=None): super().__init__(parent) self.setMinimumWidth(300) self.setWindowTitle("Input Column Names") self.column_headers = column_header self.setWhatsThis( "Please match columns in your datasheet names" " with the right side labels" ) col_names = [ "Student Name:", "Student ID:", "Cohort:", "Gender:", "College:", "Department:", "Major:", "Minor", "Email:", "Adviser", "Adviser Email", ] self.combos = [] flay = QFormLayout() for i, col_name in enumerate(col_names): combo = QComboBox() combo.addItems([""] + self.column_headers) flay.addRow(col_name, combo) if i in (0, 1): combo.currentIndexChanged.connect(self.check_validity) self.combos.append(combo) self.form_group_box = QGroupBox("Specify Column Names") self.form_group_box.setLayout(flay) self.button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel ) self.button = self.button_box.button(QDialogButtonBox.Ok) self.button.setEnabled(False) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) self.label = QLabel() self.label.setText('Student Name and ID cannot be empty') main_layout = QVBoxLayout(self) main_layout.addWidget(self.form_group_box) main_layout.addWidget(self.label) main_layout.addWidget(self.button_box) @pyqtSlot() def check_validity(self): if all([combo.currentText() for combo in self.combos]): self.button.setEnabled(True) self.label.setText('') else: self.button.setEnabled(False) self.label.setText('Student Name and ID cannot be empty')
changer self.label.setText ('')
en self.label.clear ()
, est plus lisible.