`QGridLayout` mit Widgets bei Bedarf ein- und ausblenden

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Atalanttore
User
Beiträge: 341
Registriert: Freitag 6. August 2010, 17:03

Donnerstag 2. Mai 2019, 19:21

Hallo

Ich würde gerne ein `QGridLayout`, das mehrere Widgets beinhaltet, bei Bedarf ein- und ausblenden.

Im dafür erstellten Beispielcode kommt beim Auslösen der Umschaltung zwar keine Fehlermeldung, aber an der GUI ändert sich leider auch nichts. Was ist falsch im Code?

main.py

Code: Alles auswählen

#!/usr/bin/python3
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.uic import loadUi


class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        super().__init__(parent)
        self._show_option_1 = True
        self._show_option_2 = True

        loadUi("mainwindow.ui", self)
        self.show()

    def toggle_option_1(self):
        self._show_option_1 ^= True
        if self._show_option_1:
            self.gridLayout_left.setEnabled(True)
            print("Optionen 1 eingeblendet")
        else:
            self.gridLayout_left.setEnabled(False)
            print("Optionen 1 ausgeblendet")

    def toggle_option_2(self):
        self._show_option_2 ^= True
        if self._show_option_2:
            self.gridLayout_right.setEnabled(True)
            print("Optionen 2 eingeblendet")
        else:
            self.gridLayout_right.setEnabled(False)
            print("Optionen 2 ausgeblendet")


def main():
    app = QApplication(sys.argv)
    main_window = MainWindow()

    main_window.pushButton_left.clicked.connect(main_window.toggle_option_1)
    main_window.pushButton_right.clicked.connect(main_window.toggle_option_2)

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()


mainwindow.ui

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>500</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
     <layout class="QGridLayout" name="gridLayout_left">
      <item row="0" column="0">
       <widget class="QLabel" name="label_left">
        <property name="text">
         <string>Optionen 1:</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
       <widget class="QComboBox" name="comboBox_left"/>
      </item>
     </layout>
    </item>
    <item row="0" column="1">
     <layout class="QGridLayout" name="gridLayout_right">
      <item row="0" column="0">
       <widget class="QLabel" name="label_right">
        <property name="text">
         <string>Optionen 2:</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
       <widget class="QComboBox" name="comboBox_right"/>
      </item>
     </layout>
    </item>
    <item row="1" column="0">
     <widget class="QPushButton" name="pushButton_left">
      <property name="text">
       <string>Optionen 1 ein-/ausblenden</string>
      </property>
     </widget>
    </item>
    <item row="1" column="1">
     <widget class="QPushButton" name="pushButton_right">
      <property name="text">
       <string>Optionen 2 ein-/ausblenden</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>500</width>
     <height>28</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 3896
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mittwoch 8. Mai 2019, 08:53

@Atalanttore: Was willst Du denn da erreichen? Ich denke `QLayout.setEnabled()` macht nicht das was Du denkst was es macht. Damit schaltet man die Neuberechnung des Layouts bei Veränderungen aus, wie dem hinzufügen oder entfernen von Widgets zu/von diesem Layout. Da Du nach dem Du es „disablest“ aber weder Widgets hinzufügst oder entfernst, ist da auch kein beobachtbarer Effekt zu erwarten. Ich würde sagen diese Methode braucht man sowieso eher selten. Ich habe die bisher noch nie benutzt.

Anmerkungen zum Code: Das `show()` gehört nicht in die `__init__()`. Dafür aber die Verbindung der Klicks auf die Schaltflächen mit den Methoden.

Der ``^=`` wird hier auf Wahrheitswerte angewendet, was recht überraschend ist, weil das ein bitweiser Operator für ganze Zahlen ist und da kommt dann auch eine Zahl bei heraus, statt eines `bool`. Ich sehe das hier das erste mal das das jemand in Python so macht. Die übliche Schreibweise ist ``flag = not flag`` um einen Wahrheitswert ”umzudrehen”.

Der ``if``- und der ``else``-Zweig unterscheiden sich nur durch statische Werte – einmal `True` und `False` und dann ob bei dem `print()` das Wort „eingeblendet“ oder „ausgeblendet“ ausgeben wird. Die Wahrheitswerte entsprechen dem Flag selbst, also kann man auch einfach das einsetzen, ausserhalb des ``if``/``else``-Konstrukts.

Blieben von so einer Methode diese drei Zeilen übrig:

Code: Alles auswählen

    def toggle_option_1(self):
        self._show_option_1 = not self._show_option_1
        self.gridLayout_left.setEnabled(self._show_option_1)
        print(f'Optionen 1 {"ein" if self._show_option_1 else "aus"}geblendet')
Jetzt ist `_show_option_1` aber überflüssig, denn dieser Zustand existiert ja bereits im Gridlayout und man kann ihn dort auch abfragen. Was zudem unschön ist, ist das man diese Änderungen immer an zwei Methoden vornehmen muss deren Code von der Struktur her identisch ist.

Code: Alles auswählen

#!/usr/bin/env python3
import sys
from functools import partial

from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.uic import loadUi


class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        super().__init__(parent)
        loadUi('mainwindow.ui', self)
        self.pushButton_left.clicked.connect(
            partial(self.toggle_option, self.gridLayout_left, '1')
        )
        self.pushButton_right.clicked.connect(
            partial(self.toggle_option, self.gridLayout_right, '2')
        )

    @staticmethod
    def toggle_option(layout, name):
        state = not layout.isEnabled()
        layout.setEnabled(state)
        print(f'Optionen {name} {"ein" if state else "aus"}geblendet')


def main():
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
“There's also a certain pleasure in actually getting things to work in Java, somewhat like the pleasure, I imagine, of building ships in bottles.”
— David Cook in c.l.p
Atalanttore
User
Beiträge: 341
Registriert: Freitag 6. August 2010, 17:03

Sonntag 12. Mai 2019, 21:03

@__blackjack__: Danke für die vielen Anregungen.

Wie ich aus einer anderen Quelle erfahren habe, ist das von mir gewünschte Verhalten möglich, wenn man die `QGridLayout` durch `QWidget` ersetzt und die Methode `setVisible()` dafür verwendet.

main.py:

Code: Alles auswählen

#!/usr/bin/python3
import sys
from functools import partial

from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.uic import loadUi


class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        super().__init__(parent)

        loadUi("mainwindow.ui", self)
        self.pushButton_left.clicked.connect(
            partial(self.toggle_option, self.widget_left, '1')
        )
        self.pushButton_right.clicked.connect(
            partial(self.toggle_option, self.widget_right, '2')
        )

    @staticmethod
    def toggle_option(layout, name):
        state = not layout.isVisible()
        layout.setVisible(state)
        print(f'Optionen {name} {"ein" if state else "aus"}geblendet')


def main():
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

mainwindow.ui:

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>555</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <property name="locale">
   <locale language="English" country="UnitedKingdom"/>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout_2">
    <item row="0" column="0">
     <widget class="QWidget" name="widget_left" native="true">
      <layout class="QGridLayout" name="gridLayout_left">
       <item row="0" column="2">
        <widget class="QComboBox" name="comboBox_left"/>
       </item>
       <item row="0" column="1">
        <widget class="QLabel" name="label_left">
         <property name="text">
          <string>Option &amp;1:</string>
         </property>
        </widget>
       </item>
       <item row="0" column="0">
        <spacer name="horizontalSpacer_2">
         <property name="orientation">
          <enum>Qt::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
       <item row="0" column="3">
        <spacer name="horizontalSpacer_3">
         <property name="orientation">
          <enum>Qt::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
      </layout>
     </widget>
    </item>
    <item row="0" column="1">
     <widget class="QWidget" name="widget_right" native="true">
      <layout class="QGridLayout" name="gridLayout_right">
       <item row="0" column="2">
        <widget class="QComboBox" name="comboBox_right"/>
       </item>
       <item row="0" column="1">
        <widget class="QLabel" name="label_right">
         <property name="text">
          <string>Option &amp;2:</string>
         </property>
        </widget>
       </item>
       <item row="0" column="3">
        <spacer name="horizontalSpacer">
         <property name="orientation">
          <enum>Qt::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
       <item row="0" column="0">
        <spacer name="horizontalSpacer_4">
         <property name="orientation">
          <enum>Qt::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>20</height>
          </size>
         </property>
        </spacer>
       </item>
      </layout>
     </widget>
    </item>
    <item row="1" column="0" colspan="2">
     <layout class="QGridLayout" name="gridLayout">
      <item row="0" column="0">
       <widget class="QPushButton" name="pushButton_left">
        <property name="text">
         <string>Toggle Option 1</string>
        </property>
       </widget>
      </item>
      <item row="0" column="1">
       <widget class="QPushButton" name="pushButton_right">
        <property name="text">
         <string>Toggle Option 2</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>555</width>
     <height>28</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>
Gruß
Atalanttore
Antworten