Portierung eines Beispielprogramms von Tkinter nach PyQt5

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

Sonntag 11. November 2018, 15:27

Hallo

Die Portierung meines Beispielprogramms von Tkinter nach PyQt5 schreitet voran.

1. Mittlerweile bin ich beim zeitverzögerten Aufruf der Methode `change_screen_color()` zum Ändern der Bildschirmhintergrundfarbe angekommen. Hier kommt es nun zu einem Problem, wo ich auch mit meiner Standardsuchmaschine keine Lösung finden konnte. Die Fehlermeldung ist folgende:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/ata/source/Farbkonzentrationstest/main-qt.py", line 88, in show_concentration_test_window
    self.change_screen_color()
  File "/home/ata/source/Farbkonzentrationstest/main-qt.py", line 114, in change_screen_color
    timer.timeout.connect(self.change_screen_color)
AttributeError: 'PyQt5.QtCore.pyqtSignal' object has no attribute 'connect'
2. Außerdem meldet PyCharm an mehreren Stellen folgendes Problem:

Code: Alles auswählen

Unresolved attribute reference 'connect' for class 'pyqtBoundSignal'
main-qt.py:

Code: Alles auswählen

import sys
from random import choice
#from statistics import mean

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



start_color = QtCore.Qt.black
designated_color = QtCore.Qt.red
switch_time = 1000
colors = [QtCore.Qt.black, QtCore.Qt.blue, QtCore.Qt.cyan, QtCore.Qt.green, QtCore.Qt.magenta, QtCore.Qt.red, QtCore.Qt.yellow]



class MainWindow(QMainWindow):

    switch_window = QtCore.pyqtSignal()

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

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


class ConcentrationTestWindow(QMainWindow):

    switch_window = QtCore.pyqtSignal()

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

        self.pal = self.palette()
        self.setAutoFillBackground(True)
        self.pal.setColor(self.backgroundRole(), start_color)
        self.setPalette(self.pal)

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


class ResultsWindow(QDialog):

    switch_window = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        loadUi("resultswindow.ui", self)
        self.pushButton_OK.clicked.connect(self.switch)

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



class Controller:

    def __init__(self):
        self.colors = colors
        self.color = None
        self.reaction_times = []
        self.false_positives = 0
        self.color_missed = 0
        self.key_too_often_pressed = 0
        self.stop_test = False
        self.color_locked = False

    def show_main_window(self):
        self.main_window = MainWindow()
        self.main_window.switch_window.connect(self.show_concentration_test_window) # IDE: Unresolved attribute reference 'connect' for class 'pyqtBoundSignal'
        self.main_window.show()

    def show_results_window(self):
        self.results_window = ResultsWindow()
        self.results_window.switch_window.connect(self.results_window.reject) # IDE: Unresolved attribute reference 'connect' for class 'pyqtBoundSignal'
        self.results_window.show()

    def show_concentration_test_window(self):
        self.concentration_test_window = ConcentrationTestWindow()
        self.concentration_test_window.switch_window.connect(self.concentration_test_window.close) # IDE: Unresolved attribute reference 'connect' for class 'pyqtBoundSignal'
        self.concentration_test_window.show()
        self.change_screen_color()

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.concentration_test_window.switch()


    def change_screen_color(self, color_locked=True):
        # if self.stop_test:
        #     self.concentration_test_window.switch()

        if not self.color_locked and self.color == designated_color:
            self.color_missed += 1

        self.color_locked = color_locked
        current_color = self.color

        while self.color == current_color:
            self.color = choice(self.colors)

        self.concentration_test_window.pal.setColor(self.concentration_test_window.backgroundRole(), self.color)
        self.concentration_test_window.setPalette(self.concentration_test_window.pal)

        #self.start_time = time.monotonic()

        timer = QtCore.QTimer
        timer.timeout.connect(self.change_screen_color) # Zeile 114 ist hier; IDE: Unresolved attribute reference 'connect' for class 'pyqtBoundSignal'
        timer.start(switch_time)


def main():
    app = QApplication(sys.argv)
    controller = Controller()
    controller.show_main_window()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
mainwindow.ui: (Logik dafür fehlt noch in main-qt.py):

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>634</width>
    <height>552</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Farbkonzentrationstest</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout_2">
    <item row="0" column="0">
     <layout class="QVBoxLayout" name="verticalLayout">
      <item>
       <spacer name="verticalSpacer_2">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
          <width>20</width>
          <height>40</height>
         </size>
        </property>
       </spacer>
      </item>
      <item>
       <layout class="QGridLayout" name="gridLayout">
        <item row="0" column="0">
         <widget class="QLabel" name="label_start_color">
          <property name="text">
           <string>Startfarbe:</string>
          </property>
          <property name="alignment">
           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
          </property>
         </widget>
        </item>
        <item row="0" column="1">
         <widget class="QComboBox" name="comboBox_start_color"/>
        </item>
        <item row="1" column="0">
         <widget class="QLabel" name="label_designated_color">
          <property name="text">
           <string>Zielfarbe:</string>
          </property>
          <property name="alignment">
           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
          </property>
         </widget>
        </item>
        <item row="1" column="1">
         <widget class="QComboBox" name="comboBox_designated_color">
          <property name="currentText">
           <string/>
          </property>
         </widget>
        </item>
        <item row="2" column="0">
         <widget class="QLabel" name="label_switch_time">
          <property name="text">
           <string>Umschaltzeit (ms):</string>
          </property>
          <property name="alignment">
           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
          </property>
         </widget>
        </item>
        <item row="2" column="1">
         <widget class="QSpinBox" name="spinBox_switch_time">
          <property name="maximum">
           <number>100000</number>
          </property>
          <property name="value">
           <number>1000</number>
          </property>
         </widget>
        </item>
       </layout>
      </item>
      <item>
       <spacer name="verticalSpacer">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
          <width>20</width>
          <height>40</height>
         </size>
        </property>
       </spacer>
      </item>
      <item>
       <widget class="QPushButton" name="pushButton_start_test">
        <property name="layoutDirection">
         <enum>Qt::LeftToRight</enum>
        </property>
        <property name="text">
         <string>Test starten</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>634</width>
     <height>28</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>
resultswindow.ui (Logik dafür fehlt noch in main-qt.py):

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog_results</class>
 <widget class="QDialog" name="Dialog_results">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Ergebnisse</string>
  </property>
  <layout class="QGridLayout" name="gridLayout_2">
   <item row="0" column="0">
    <layout class="QVBoxLayout" name="verticalLayout">
     <item>
      <layout class="QGridLayout" name="gridLayout">
       <item row="0" column="1">
        <widget class="QLabel" name="label_result_too_often">
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
       <item row="1" column="0">
        <widget class="QLabel" name="label_color_missed">
         <property name="text">
          <string>Bei richtiger Farbe nicht gedrückt:</string>
         </property>
         <property name="alignment">
          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
         </property>
        </widget>
       </item>
       <item row="3" column="0">
        <widget class="QLabel" name="label_mean_reaction_time">
         <property name="text">
          <string>Gemittelte Reaktionszeit:</string>
         </property>
         <property name="alignment">
          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
         </property>
        </widget>
       </item>
       <item row="3" column="1">
        <widget class="QLabel" name="label_result_mean_reaction_time">
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
       <item row="4" column="0">
        <widget class="QLabel" name="label_reaction_times">
         <property name="text">
          <string>Reaktionszeit pro richtig gedrückter Farbe:</string>
         </property>
         <property name="alignment">
          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
         </property>
        </widget>
       </item>
       <item row="2" column="1">
        <widget class="QLabel" name="label_result_false_positives">
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
       <item row="1" column="1">
        <widget class="QLabel" name="label_result_color_missed">
         <property name="text">
          <string/>
         </property>
        </widget>
       </item>
       <item row="2" column="0">
        <widget class="QLabel" name="label_false_positives">
         <property name="text">
          <string>Bei falscher Farbe gedrückt:</string>
         </property>
         <property name="alignment">
          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
         </property>
        </widget>
       </item>
       <item row="0" column="0">
        <widget class="QLabel" name="label_too_often">
         <property name="text">
          <string>Bei richtiger Farbe zu oft gedrückt:</string>
         </property>
         <property name="alignment">
          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
         </property>
        </widget>
       </item>
       <item row="4" column="1">
        <widget class="QListView" name="listView_result_reaction_times"/>
       </item>
      </layout>
     </item>
     <item>
      <spacer name="verticalSpacer">
       <property name="orientation">
        <enum>Qt::Vertical</enum>
       </property>
       <property name="sizeHint" stdset="0">
        <size>
         <width>20</width>
         <height>40</height>
        </size>
       </property>
      </spacer>
     </item>
     <item>
      <widget class="QPushButton" name="pushButton_OK">
       <property name="text">
        <string>OK</string>
       </property>
      </widget>
     </item>
    </layout>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>
Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 4013
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Sonntag 11. November 2018, 15:44

`timer` ist an die *Klasse* `QtCore.Qtimer` gebunden. Du möchtest da aber ein Exemplar haben, also in die Klasse auch *aufrufen*. Dann gibt's auch ein `connect()`.

Ich weiss es war total meine Schuld das ich das einfach ausgeführt habe aber Beispielcode der einfach mal ein komplett schwarzes Fenster als Vollbildschirm öffnet, ohne das man eine direkte Möglichkeit präsentiert bekommt das auch wieder zu schliessen ist etwas überraschend und nervig.

Edit: Konstanten werden per Konvention immer noch KOMPLETT_GROSS geschrieben. Und schau Dir mal die Konvention bei Qt-Signalen an. Das sollte also eher `window_switched` heissen.
“Programmieren ist ein Hobby, bei dem es einen riesigen Baumarkt mit quasi jedem Bauteil und Werkzeug und fast immer kostenlos gibt. Ob man deswegen in der Lage ist einen Kölner Dom zu bauen ist eine andere Frage. Arbeit steckt auf jeden Fall drin ;).” — Greebo, forum.ubuntuusers.de
Atalanttore
User
Beiträge: 341
Registriert: Freitag 6. August 2010, 17:03

Sonntag 11. November 2018, 21:21

@__blackjack__: Danke für die Mühe, dass du meinen stetig größer werdenden Code immer noch durchschaust.

Ich habe mein Beispielprogramm nun noch mehr Richtung MVC umgebaut. Die .ui-Dateien habe ich lediglich in das neue Verzeichnis `views` verschoben und ansonsten nicht verändert.

1. Achtung: Der Abbruch des Vollbildfensters mit der ESC-Taste funktioniert leider immer noch nicht. Woran liegt das?

2. Anstatt einem RGB-Wert liefern die QColor-Objekte nur einen Integer-Wert zurück (siehe Doku). Muss man für jede Farbe einen eigenen RGB-Wert definieren, obwohl es bereits vordefinierte Farben gibt?

main.py:

Code: Alles auswählen

import sys
from PyQt5.QtWidgets import QApplication
from controller import Controller

class Main(QApplication):
    def __init__(self, *args):
        super().__init__(*args)
        self.controller = Controller()
        self.controller.show_main_window()

if __name__ == '__main__':
    app = Main(sys.argv)
    sys.exit(app.exec_())

controller.py:

Code: Alles auswählen

from random import choice
#from statistics import mean

from PyQt5 import QtCore

from views import windows
from model import Data

class Controller():
    def __init__(self, *args, **kwargs):
        super().__init__()

        self.data = Data()
        self.windows = windows

    def show_main_window(self):
        self.main_window = self.windows.MainWindow()
        self.main_window.window_switched.connect(self.show_concentration_test_window)
        self.main_window.show()

    def show_results_window(self):
        self.results_window = self.windows.ResultsWindow()
        self.results_window.window_switched.connect(self.results_window.reject)
        self.results_window.show()

    def show_concentration_test_window(self):
        self.concentration_test_window = self.windows.ConcentrationTestWindow(self.data.start_color)
        self.concentration_test_window.window_switched.connect(self.concentration_test_window.close) #4
        self.concentration_test_window.show()
        self.change_screen_color()

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape: #1
            self.concentration_test_window.switch() #2


    def change_screen_color(self, color_locked=True):
        # if self.stop_test:
        #     self.concentration_test_window.switch()

        if not self.data.color_locked and self.data.color == self.data.designated_color:
            self.data.color_missed += 1

        self.data.color_locked = color_locked
        current_color = self.data.color

        while self.data.color == current_color:
            self.data.color = choice(self.data.COLORS)

        self.concentration_test_window.pal.setColor(self.concentration_test_window.backgroundRole(), self.data.color)
        self.concentration_test_window.setPalette(self.concentration_test_window.pal)

        #self.start_time = time.monotonic()

        timer = QtCore.QTimer()
        timer.timeout.connect(self.change_screen_color)
        timer.start(self.data.switch_time)
model.py:

Code: Alles auswählen

import sys
from PyQt5.QtCore import Qt


class Data():
    def __init__(self, *args, **kwargs):
        super().__init__()
        self.COLORS = [Qt.black,
                       Qt.blue,
                       Qt.cyan,
                       Qt.green,
                       Qt.magenta,
                       Qt.red,
                       Qt.yellow]

        self.start_color = Qt.black # In GUI auswählbar machen
        self.designated_color = Qt.red # In GUI auswählbar machen
        self.switch_time = 1000 # In GUI auswählbar machen

        self.color = None
        self.reaction_times = []
        self.false_positives = 0
        self.color_missed = 0
        self.key_too_often_pressed = 0
        self.stop_test = False
        self.color_locked = False

views/windows.py (Logik noch ziemlich unvollständig):

Code: Alles auswählen

from PyQt5.QtWidgets import QMainWindow, QDialog
from PyQt5.QtCore import pyqtSignal
from PyQt5.uic import loadUi

class MainWindow(QMainWindow):

    window_switched = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        loadUi("views/mainwindow.ui", self)
        self.pushButton_start_test.clicked.connect(self.switch)

    def switch(self):
        self.window_switched.emit()

class ConcentrationTestWindow(QMainWindow):

    window_switched = pyqtSignal()

    def __init__(self, color, parent=None):
        super().__init__(parent)
        self.showFullScreen()
        self.pal = self.palette()
        self.setAutoFillBackground(True)
        self.pal.setColor(self.backgroundRole(), color)
        self.setPalette(self.pal)

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


class ResultsWindow(QDialog):

    window_switched = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        loadUi("views/resultswindow.ui", self)
        self.pushButton_OK.clicked.connect(self.switch)

    def switch(self):
        self.window_switched.emit()
Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 4013
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Sonntag 11. November 2018, 22:07

@Atalanttore: Ach Du meine Güte. MVC. Der Anfang vom Ende. Ich bin raus hier. Ich fand das ja in der letzten Iteration schon zu unsinnig aufgeblasen, jetzt wird es langsam aberwitzig. Vielleicht möchtest Du lieber in Java programmieren. ;-)

Bei 2. verstehe ich die Frage nicht.
“Programmieren ist ein Hobby, bei dem es einen riesigen Baumarkt mit quasi jedem Bauteil und Werkzeug und fast immer kostenlos gibt. Ob man deswegen in der Lage ist einen Kölner Dom zu bauen ist eine andere Frage. Arbeit steckt auf jeden Fall drin ;).” — Greebo, forum.ubuntuusers.de
Sirius3
User
Beiträge: 10347
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 11. November 2018, 22:19

@Atalanttore: ein schönes Beispiel, warum MVC meist falsch umgesetzt wird. Main und Controller sind als Klassen völlig unnötig, eine Klasse `Data` ohne Methoden zumindest unschön.
Was ist der Sinn in Controller.__init__ ein Modul an ein Attribut zu binden? `change_screen_color` gehört entweder in die Klasse `Data`, weil es nur mit Attributen aus Data arbeitet, oder aber in die Klasse `ConcentrationTestWindow` weil es dessen Methoden aufruft. Am besten kombinierst Du `Data` und `ConcentrationTestWindow` zu einer Klasse, dann ist nämlich klar, was zusammengehört.

Dein Programm hat eine Größe, die das Aufteilen auf mehr als eine Datei nur unübersichtlicher macht.
Atalanttore
User
Beiträge: 341
Registriert: Freitag 6. August 2010, 17:03

Montag 12. November 2018, 16:21

@__blackjack__: Java ist mir für den Einstieg dann doch zu umständlich.

Zu 2.: Nach dem Umbau des Codes habe ich das Problem jetzt wahrscheinlich selbst gefunden. Die Hintergrundfarbe wird eigentlich in der Methode `change_screen_color()` festgelegt, weil sie ein paar Zeilen nach der Instanziierung eines `ConcentrationTestWindow()`-Objekts aufgerufen wird.


@Sirius3 + __blackjack__: Den Python-Code habe ich nun wieder in einer Datei zusammengefasst. Die .ui-Dateien liegen wieder im gleichen Verzeichnis. Der Abbruch des Vollbildfensters mit der ESC-Taste funktioniert mittlerweile auch, aber der Farbwechsel in der Methode `change_screen_color()` weiterhin nicht. Woran liegt das?

Der Code ist momentan wie folgt:

Code: Alles auswählen

import sys
from random import choice
#from statistics import mean

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



start_color = QtCore.Qt.black # In GUI auswählbar machen
designated_color = QtCore.Qt.red # In GUI auswählbar machen
switch_time = 1000 # In GUI auswählbar machen
COLORS = [QtCore.Qt.black,
          QtCore.Qt.blue,
          QtCore.Qt.cyan,
          QtCore.Qt.green,
          QtCore.Qt.magenta,
          QtCore.Qt.red,
          QtCore.Qt.yellow]



class MainWindow(QMainWindow):

    window_switched = QtCore.pyqtSignal()

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

    def switch(self):
        self.window_switched.emit()


class ConcentrationTestWindow(QMainWindow):

    window_switched = QtCore.pyqtSignal()

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

        self.colors = COLORS
        self.color = None
        self.reaction_times = []
        self.false_positives = 0
        self.color_missed = 0
        self.key_too_often_pressed = 0
        self.stop_test = False
        self.color_locked = False

        self.pal = self.palette()
        self.setAutoFillBackground(True)
        self.pal.setColor(self.backgroundRole(), start_color)
        self.setPalette(self.pal)


    def change_screen_color(self, color_locked=True):
        # if self.stop_test:
        #     self.concentration_test_window.switch()

        if not self.color_locked and self.color == designated_color:
            self.concolor_missed += 1

        self.color_locked = color_locked
        current_color = self.color

        while self.color == current_color:
            self.color = choice(self.colors)

        self.pal.setColor(self.backgroundRole(), self.color)
        self.setPalette(self.pal)

        #self.start_time = time.monotonic()

        timer = QtCore.QTimer()
        timer.timeout.connect(self.change_screen_color)
        timer.start(switch_time)

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.switch()

    def switch(self):
        self.window_switched.emit()


class ResultsWindow(QDialog):

    window_switched = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        loadUi("resultswindow.ui", self)
        self.pushButton_OK.clicked.connect(self.switch)

    def switch(self):
        self.window_switched.emit()



class Controller:

    def __init__(self):
        pass

    def show_main_window(self):
        self.main_window = MainWindow()
        self.main_window.window_switched.connect(self.show_concentration_test_window)
        self.main_window.show()

    def show_results_window(self):
        self.results_window = ResultsWindow()
        self.results_window.window_switched.connect(self.results_window.reject)
        self.results_window.show()

    def show_concentration_test_window(self):
        self.concentration_test_window = ConcentrationTestWindow()
        self.concentration_test_window.window_switched.connect(self.concentration_test_window.close)
        self.concentration_test_window.show()
        self.concentration_test_window.change_screen_color()



def main():
    app = QApplication(sys.argv)
    controller = Controller()
    controller.show_main_window()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
Gruß
Atalanttore
__deets__
User
Beiträge: 6197
Registriert: Mittwoch 14. Oktober 2015, 14:29

Montag 12. November 2018, 17:01

Es könnte sein, dass dein QTimer das Problem darstellt. Da darunter ein C++-Objekt liegt, kann es sein, dass dein Timer sofort wider stirbt, da du dir keine Referenz auf ihn merkst. Binde den mal an self, und schau, ob das die Situation verbessert.
Benutzeravatar
__blackjack__
User
Beiträge: 4013
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Montag 12. November 2018, 17:43

@Atalanttore: Alternativ könnte man dem `QTimer` beim erstellen wahrscheinlich auch `self` übergeben, damit es ein Qt-Elternobjekt hat und solange lebt wie das lebt.

Du gehst/gingst mit Deinem Code aber sehr in Richtung (unnötige) Komplexität die bei Java nicht unüblich ist. GUI und Logik zu trennen ist sinnvoll, aber einfach so MVC machen zu wollen nur weil man MVC machen will, ist nicht sinnvoll. Ich finde die `Controller`-Klasse auch jetzt immer noch unsinnig. Die hat ja gar keinen Zustand. Und die `window_switched`-Signale die von einer `switch()`-Methode ausgelöst werden die gar nichts umschaltet sondern nur dieses Signal auslöst ist auch sehr verwirrend.
“Programmieren ist ein Hobby, bei dem es einen riesigen Baumarkt mit quasi jedem Bauteil und Werkzeug und fast immer kostenlos gibt. Ob man deswegen in der Lage ist einen Kölner Dom zu bauen ist eine andere Frage. Arbeit steckt auf jeden Fall drin ;).” — Greebo, forum.ubuntuusers.de
Atalanttore
User
Beiträge: 341
Registriert: Freitag 6. August 2010, 17:03

Montag 12. November 2018, 23:16

__deets__ hat geschrieben:
Montag 12. November 2018, 17:01
Es könnte sein, dass dein QTimer das Problem darstellt. Da darunter ein C++-Objekt liegt, kann es sein, dass dein Timer sofort wider stirbt, da du dir keine Referenz auf ihn merkst. Binde den mal an self, und schau, ob das die Situation verbessert.
__blackjack__ hat geschrieben:
Montag 12. November 2018, 17:43
@Atalanttore: Alternativ könnte man dem `QTimer` beim erstellen wahrscheinlich auch `self` übergeben, damit es ein Qt-Elternobjekt hat und solange lebt wie das lebt.
Bingo! Beide Lösungsvorschläge funktionieren. Welche ist jetzt die bessere/elegantere Lösung?



@__blackjack__: Meinst du mit Zustand den Zustand eines endlichen Automaten?

Sowohl die `Controller`-Klasse als auch die `switch()`-Methode habe ich von dem Beispiel hier übernommen.

Gruß
Atalanttore
__deets__
User
Beiträge: 6197
Registriert: Mittwoch 14. Oktober 2015, 14:29

Montag 12. November 2018, 23:20

Ich bevorzuge meine (Überraschung ;) ) weil du dadurch gleich das Problem den timer wieder rekonfigurieren zu wollen löst. Ich würde ihn dann auch nur einmal erzeugen.
Benutzeravatar
__blackjack__
User
Beiträge: 4013
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Montag 12. November 2018, 23:38

@Atalanttore: Mit Zustand bei Klassen sind normalerweise Daten gemeint. Klassen fassen Daten und Funktionen die darauf operieren zu Objekten zusammen. Wenn es eines von beiden nicht gibt, dann ist das aus OOP-Sicht keine Klasse. Wobei mir gerade auffällt das da ja doch Daten sind, aber die werden nicht in der `__init__()` erstellt/initialisiert, sondern in den Methoden. Und jede Methode hat ihr eigenes Datum und keine verwendet etwas von den anderen – das gehört ganz sicher alles so nicht in eine Klasse. Und die Signale/`switch()`-Methode ist komisch. Das Beispiel würde ich nicht als Vorlage für irgendetwas verwenden.

Edit: Okay, die Methoden benutzen doch Attribute die in anderen Methoden eingeführt wurden. Das ist aber immer noch ein sehr komisches Konstrukt.
“Programmieren ist ein Hobby, bei dem es einen riesigen Baumarkt mit quasi jedem Bauteil und Werkzeug und fast immer kostenlos gibt. Ob man deswegen in der Lage ist einen Kölner Dom zu bauen ist eine andere Frage. Arbeit steckt auf jeden Fall drin ;).” — Greebo, forum.ubuntuusers.de
Atalanttore
User
Beiträge: 341
Registriert: Freitag 6. August 2010, 17:03

Dienstag 13. November 2018, 16:27

@__deets__: Bis auf folgende Anweisung findet sich nun kein Code mehr zum Timer in der Methode `change_screen_color()`.

Code: Alles auswählen

self.timer.start(switch_time)

@__blackjack__:
1. Bedeutet dass, dass eine Klasse mit folgendem Muster (leere `__init__`-Methode) aus OOP-Sicht niemals eine Klasse sein kann?

Code: Alles auswählen

class Test:

    def __init__(self):
        pass
        
    def mache_etwas(self):
    	<beliebiger Code>
        
2. Wo ist im Beispielprogramm der beste Platz für Daten, auf die sowohl in einem `MainWindow`-Objekt als auch in einem `ConcentrationTestWindow()`-Objekt zugegriffen wird?

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

Dienstag 13. November 2018, 16:51

@Atalanttore: Man kann die Klasse ja einfach durch folgendes ersetzen:

Code: Alles auswählen

def mache_etwas():
    <beliebiger Code>
Also macht die Klasse als Klasse keinen Sinn.
“Programmieren ist ein Hobby, bei dem es einen riesigen Baumarkt mit quasi jedem Bauteil und Werkzeug und fast immer kostenlos gibt. Ob man deswegen in der Lage ist einen Kölner Dom zu bauen ist eine andere Frage. Arbeit steckt auf jeden Fall drin ;).” — Greebo, forum.ubuntuusers.de
Atalanttore
User
Beiträge: 341
Registriert: Freitag 6. August 2010, 17:03

Mittwoch 14. November 2018, 20:26

@__blackjack__: Danke für die Antwort. Speichert man Daten, auf die verschiedene Objekte zugreifen, einfach als globale Variablen?

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

Mittwoch 14. November 2018, 21:01

@Atalanttore: Nein‽ Man übergibt die.
“Programmieren ist ein Hobby, bei dem es einen riesigen Baumarkt mit quasi jedem Bauteil und Werkzeug und fast immer kostenlos gibt. Ob man deswegen in der Lage ist einen Kölner Dom zu bauen ist eine andere Frage. Arbeit steckt auf jeden Fall drin ;).” — Greebo, forum.ubuntuusers.de
Antworten