QSlider bereitet kleine Probleme

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Benutzeravatar
__blackjack__
User
Beiträge: 13068
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: 1. nein `self.slider_value` ist im Grunde gar keine Variable sondern ein Attribut auf dem Objekt. `slider_value` wäre eine Variable. Und wenn an diesen Namen in der Methode eine Wert gebunden wird, dann ist der Name lokal in der Methode.

2. Mit `self.ui` meine ich `self.ui`. Das benutzt Du nirgends und deshalb macht es auch keinen Sinn das zu definieren. Es zu benutzen würde auch keinen Sinn machen, denn alles was darüber erreichbar ist, ist ja *auch* über das Objekt selbst erreichbar, denn das wurde ja an `loadUI()` als Argument übergeben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@__blackjack__:
  1. Okay. Mit dem Schlüsselwort `self`, also `self.slider_value`, wird die Variable zum Attribut, weil es im gesamten Objekt gültig ist (nennt man das "gültig"?) und in dem Fall ist das nicht nötig. Ohne `self`, also `slider_value`, ist die Variable nur in der Methode `write_slider_value()` gültig.
  2. Sorry, aber ich und die Suchfunktion meiner IDE finden im Code keinen Bezeichner namens `self.ui`.
    BTW: Den Code in der Methode `__init__()` habe ich ursprünglich aus einem Beispiel und anschließend selbst zu einer Klasse umgebaut.
Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 13068
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Der letzte Beitrag von Dir vor meiner Antwort mit dem `self.ui` war der hier: viewtopic.php?f=24&t=44062#p334474

Und da sehe ich auch ohne Suchfunktion ein ``self.ui = …``. Auf das bezog ich mich.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@__blackjack__: Den Test mit PyQt5 habe ich wegen dem Problem mit dem Werten des Sliders kurz durchgeführt. Danach habe ich den Code wieder verworfen, wobei mir sowieso nicht klar ist, ob man lieber PySide2 oder PyQt5 verwenden sollte.

Für die Frage PySide2 oder PyQt5 habe ich ein eigenes Thema erstellt.

Gruß
Atalanttore
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

In meinem Beispiel bin ich jetzt von PySide2 auf PyQt5 umgestiegen und habe es um einen Dialog erweitert, den man über das Menü aufrufen kann. Als Vorlage habe ich das Beispiel von hier genommen.


mainwindow.ui

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>SliderWindow</class>
 <widget class="QMainWindow" name="SliderWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QWidget" name="layoutWidget">
    <property name="geometry">
     <rect>
      <x>40</x>
      <y>40</y>
      <width>721</width>
      <height>51</height>
     </rect>
    </property>
    <layout class="QGridLayout" name="gridLayout">
     <item row="0" column="0">
      <widget class="QLabel" name="label_value">
       <property name="minimumSize">
        <size>
         <width>50</width>
         <height>20</height>
        </size>
       </property>
       <property name="text">
        <string/>
       </property>
      </widget>
     </item>
     <item row="0" column="1">
      <widget class="QSlider" name="horizontalSlider">
       <property name="minimum">
        <number>0</number>
       </property>
       <property name="maximum">
        <number>100</number>
       </property>
       <property name="sliderPosition">
        <number>50</number>
       </property>
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
      </widget>
     </item>
    </layout>
   </widget>
   <widget class="QPushButton" name="pushButton_exit">
    <property name="geometry">
     <rect>
      <x>610</x>
      <y>430</y>
      <width>117</width>
      <height>32</height>
     </rect>
    </property>
    <property name="text">
     <string>Beenden</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>28</height>
    </rect>
   </property>
   <widget class="QMenu" name="menu_file">
    <property name="title">
     <string>Da&amp;tei</string>
    </property>
    <addaction name="action_settings"/>
   </widget>
   <addaction name="menu_file"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <action name="action_settings">
   <property name="text">
    <string>&amp;Einstellungen</string>
   </property>
  </action>
 </widget>
 <resources/>
 <connections/>
</ui>

settingswindow.ui

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>SettingsWindow</class>
 <widget class="QDialog" name="SettingsWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Einstellungen</string>
  </property>
  <widget class="QDialogButtonBox" name="buttonBox">
   <property name="geometry">
    <rect>
     <x>30</x>
     <y>240</y>
     <width>341</width>
     <height>32</height>
    </rect>
   </property>
   <property name="orientation">
    <enum>Qt::Horizontal</enum>
   </property>
   <property name="standardButtons">
    <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>buttonBox</sender>
   <signal>accepted()</signal>
   <receiver>SettingsWindow</receiver>
   <slot>accept()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>248</x>
     <y>254</y>
    </hint>
    <hint type="destinationlabel">
     <x>157</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>buttonBox</sender>
   <signal>rejected()</signal>
   <receiver>SettingsWindow</receiver>
   <slot>reject()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>316</x>
     <y>260</y>
    </hint>
    <hint type="destinationlabel">
     <x>286</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

mainwindow.py

Code: Alles auswählen

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog
from PyQt5.uic import loadUi
from PyQt5 import QtCore


class MainWindow(QMainWindow):

    switch_window = QtCore.pyqtSignal() # 1

    def __init__(self, parent=None):
        super().__init__(parent)
        loadUi("mainwindow.ui", self)

        self.horizontalSlider.sliderMoved.connect(self.write_slider_value)
        self.action_settings.triggered.connect(self.switch) # 2
        #self.pushButton_exit.clicked.connect(self.quit, parent=self) # funktioniert nicht

    def write_slider_value(self):
        slider_value = self.horizontalSlider.value()
        self.label_value.setText(str(slider_value))

    def switch(self):
        self.switch_window.emit() # 3


class SettingsWindow(QDialog):

    def __init__(self, parent=None):
        super().__init__(parent)
        loadUi("settingswindow.ui", self)


class Controller:

    def __init__(self):
        pass

    def show_main_window(self):
        self.main_window = MainWindow()
        self.main_window.switch_window.connect(self.show_settings_window) # 4
        self.main_window.show()

    def show_settings_window(self):
        self.settings_window = SettingsWindow()
        self.settings_window.show()



if __name__ == "__main__":
    app = QApplication(sys.argv)
    controller = Controller()
    controller.show_main_window()
    sys.exit(app.exec_())
Irgendwie öffnet sich durch die Methoden `QtCore.pyqtSignal()` und `emit()` tatsächlich der gewünschte Dialog `SettingsWindow`. Die Doku zu Signals and Slots habe ich zwar gelesen, aber trotzdem weiß ich nicht was bei den nummerierten Stellen 1 bis 4 genau vor sich geht.

Mein nächster Versuch den Button zum Beenden mit einer Methode zum Beenden zu verknüpfen ist mit folgender Fehlermeldung erneut gescheitert.

Code: Alles auswählen

 File "/home/ata/source/slider/mainwindow.py", line 53, in <module>
    controller.show_main_window()
  File "/home/ata/source/slider/mainwindow.py", line 40, in show_main_window
    self.main_window = MainWindow()
  File "/home/ata/source/slider/mainwindow.py", line 17, in __init__
    self.pushButton_exit.clicked.connect(self.quit, parent=self)
AttributeError: 'MainWindow' object has no attribute 'quit'
Gruß
Atalanttore
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

QMainWindow hat ja auch kein quit. Die application hat das.

Die Stelle 1 legt halt einfach ein Signal an, so dass du das benuzten kannst. 2 verbindet ein Signal mit einer Methode, in Qt oft als Slot bezeichnet. Früher musste man die extra anlegen, heute geht da fast alles, was aufrufbar ist. Und 3 emittiert dein in 1 erklärtes Signal. Damit werden alle damit verbundenen slots aufgerufen. Und da du in 4 eine solche Verbindung hergestellt hast, wird die hakt aufgerufen.
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Mit `app.quit` beendet sich das Programm tatsächlich. Mit den Methoden aller eingebauten Klassen in Python/PyQt muss ich mich noch intensiver beschäftigen.

Zu 1.: Kann man sich `switch_window` als ganz normales Objekt der Klasse `PyQt5.QtCore.pyqtSignal` vorstellen oder ist das etwas besonderes?

Zu 3.: Ist das "Emittieren eines Signals" vergleichbar mit einem Methodenaufruf?

Zu 4.: Funktioniert das `switch_window` in der Anweisung `self.main_window.switch_window.connect(self.show_settings_window)` genauso wie ein `clicked` oder `triggered`?

Gruß
Atalanttore
Antworten