GUI wird scheinbar ignoriert

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Falcon
User
Beiträge: 2
Registriert: Mittwoch 15. August 2018, 14:23

Mittwoch 15. August 2018, 14:51

Hallo,

ich hoffe, dass ich mein Anliegen verständlich in Worte fassen kann.

Erst einmal zum Aufbau:
Ich habe zwei Klassen geschrieben, eine für die GUI mit PyQt5 und die zweite Klasse beinhaltet eine relativ simple Zeitscheibe.
Das ganze läuft auf einem Raspberry Pi 3 und ist über die SPI-Schnittstelle mit einem Port-Expander(MCP23S17) verknüpft.

Folgendes Problem:
Wenn ich den Code starte, läuft ausschließlich die Zeitscheibe und die GUI wird augenscheinlich ignoriert.
Was mich verwirrt ist, dass wenn ich während der Ausführung des Codes [ENTER] drücke, wird die GUI ausgeführt
jedoch bleibt die Zeitscheibe stehen.

Mein Ziel:
Das die GUI ausgeführt wird und währenddessen die Zeitscheibe durchläuft, im folgenden
möchte ich nämlich, dass unter Port B die schwarzen Kästchen grün aufleuchten, wenn ich
ein Signal an einem Eingang anlege.

Würde mich sehr freuen, wenn jemand versteht was ich meine
und vielleicht sogar meinen Fehler erkennt :)

Gruß Falcon

Code: Alles auswählen


from PyQt5.QtWidgets import (QWidget, QPushButton,QFrame, QApplication, QDialog)
import mcp23s17 as PortExpander
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import threading
import time
import sys




class Form(QDialog):
    
    def __init__(self, parent = None):
        
        super(Form, self).__init__(parent)
        pingg = False
        self.initUI()
        
        
    def initUI(self):      

        self.col = QColor(0, 0, 0)       
        
        """
        Hier wird die Button-bezeichnung für Port-A festgelegt, seine Koordinaten und dass er immer True liefert,
        Wenn der Button geklickt wird, löst es die Funktion setColor aus.
        """
        #Port-A
        pin1_A = QPushButton('Pin 1A', self)
        pin1_A.setCheckable(True)
        pin1_A.move(10, 10)
        
        pin1_A.clicked.connect(self.setColor)
        

        pin2_A = QPushButton('Pin 2A', self)
        pin2_A.setCheckable(True)
        pin2_A.move(10, 60)
        
        pin2_A.clicked.connect(self.setColor)
        
        
        pin3_A = QPushButton('Pin 3A', self)
        pin3_A.setCheckable(True)
        pin3_A.move(10, 110)
        
        pin3_A.clicked.connect(self.setColor)
        

        pin4_A = QPushButton('Pin 4A', self)
        pin4_A.setCheckable(True)
        pin4_A.move(10, 160)
        
        pin4_A.clicked.connect(self.setColor)
        
        
        pin5_A = QPushButton('Pin 5A', self)
        pin5_A.setCheckable(True)
        pin5_A.move(10, 210)
        
        pin5_A.clicked.connect(self.setColor)
        

        pin6_A = QPushButton('Pin 6A', self)
        pin6_A.setCheckable(True)
        pin6_A.move(10, 260)
        
        pin6_A.clicked.connect(self.setColor)
        
        
        pin7_A = QPushButton('Pin 7A', self)
        pin7_A.setCheckable(True)
        pin7_A.move(10, 310)
        
        pin7_A.clicked.connect(self.setColor)
        

        pin8_A = QPushButton('Pin 8A', self)
        pin8_A.setCheckable(True)
        pin8_A.move(10, 360)
        
        pin8_A.clicked.connect(self.setColor)
        
        
        """
        Hier wird ein Rechteck erzeugt mit koordinaten und größenangebe,
        mit setStyleSheet() wird dessen Farbe geändert
        """
        #LED- Anzeige Port-A
        
        self.square1_A = QFrame(self)
        self.square1_A.setGeometry(150, 15, 20, 20)
        self.square1_A.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square2_A = QFrame(self)
        self.square2_A.setGeometry(150, 65, 20, 20)
        self.square2_A.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square3_A = QFrame(self)
        self.square3_A.setGeometry(150, 115, 20, 20)
        self.square3_A.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square4_A = QFrame(self)
        self.square4_A.setGeometry(150, 165, 20, 20)
        self.square4_A.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square5_A = QFrame(self)
        self.square5_A.setGeometry(150, 215, 20, 20)
        self.square5_A.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square6_A = QFrame(self)
        self.square6_A.setGeometry(150, 265, 20, 20)
        self.square6_A.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square7_A = QFrame(self)
        self.square7_A.setGeometry(150, 315, 20, 20)
        self.square7_A.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square8_A = QFrame(self)
        self.square8_A.setGeometry(150, 365, 20, 20)
        self.square8_A.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        

        """
        Hier wird die Button-bezeichnung für Port-B festgelegt,
        seine Koordinaten und dass er immer True liefert,
        wenn er abgefragt wird.
        """
        #Port-B
        pin1_B = QPushButton('Pin 1B', self)
        pin1_B.setCheckable(True)
        pin1_B.move(210, 10)
        pin1_B.setEnabled(False)
        
        pin1_B.clicked.connect(self.setColor)
        

        pin2_B = QPushButton('Pin 2B', self)
        pin2_B.setCheckable(True)
        pin2_B.move(210, 60)
        pin2_B.setEnabled(False)
        
        pin2_B.clicked.connect(self.setColor)
        
        
        pin3_B = QPushButton('Pin 3B', self)
        pin3_B.setCheckable(True)
        pin3_B.move(210, 110)
        pin3_B.setEnabled(False)
        
        pin3_B.clicked.connect(self.setColor)
        
        
        pin4_B = QPushButton('Pin 4B', self)
        pin4_B.setCheckable(True)
        pin4_B.move(210, 160)
        pin4_B.setEnabled(False)
        
        pin4_B.clicked.connect(self.setColor)
        
        
        pin5_B = QPushButton('Pin 5B', self)
        pin5_B.setCheckable(True)
        pin5_B.move(210, 210)
        pin5_B.setEnabled(False)
        
        pin5_B.clicked.connect(self.setColor)
        

        pin6_B = QPushButton('Pin 6B', self)
        pin6_B.setCheckable(True)
        pin6_B.move(210, 260)
        pin6_B.setEnabled(False)
        
        pin6_B.clicked.connect(self.setColor)
        
        
        pin7_B = QPushButton('Pin 7B', self)
        pin7_B.setCheckable(True)
        pin7_B.move(210, 310)
        pin7_B.setEnabled(False)
        
        pin7_B.clicked.connect(self.setColor)
        

        pin8_B = QPushButton('Pin 8B', self)
        pin8_B.setCheckable(True)
        pin8_B.move(210, 360)
        pin8_B.setEnabled(False)
        
        pin8_B.clicked.connect(self.setColor)
        
        
        """
        Hier wird ein Rechteck erzeugt mit koordinaten und größenangebe,
        mit setStyleSheet() wird dessen Farbe geändert
        """
        # LED- Anzeige Port-B
        self.square1_B = QFrame(self)
        self.square1_B.setGeometry(350, 15, 20, 20)
        self.square1_B.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square2_B = QFrame(self)
        self.square2_B.setGeometry(350, 65, 20, 20)
        self.square2_B.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square3_B = QFrame(self)
        self.square3_B.setGeometry(350, 115, 20, 20)
        self.square3_B.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square4_B = QFrame(self)
        self.square4_B.setGeometry(350, 165, 20, 20)
        self.square4_B.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square5_B = QFrame(self)
        self.square5_B.setGeometry(350, 215, 20, 20)
        self.square5_B.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square6_B = QFrame(self)
        self.square6_B.setGeometry(350, 265, 20, 20)
        self.square6_B.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square7_B = QFrame(self)
        self.square7_B.setGeometry(350, 315, 20, 20)
        self.square7_B.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.square8_B = QFrame(self)
        self.square8_B.setGeometry(350, 365, 20, 20)
        self.square8_B.setStyleSheet("QWidget { background-color: %s }" %  
        self.col.name())
        
        self.liste_square = [self.square1_B,self.square2_B,self.square3_B,self.square4_B,self.square5_B,self.square6_B,self.square7_B,self.square8_B]
        
        self.setGeometry(300, 300, 400, 400)
        self.setWindowTitle('Toggle button Port-A/Port-B')
        self.show()
       

      
    # Eingaenge negiert ausgeben    
    def update(self, eingang):
        #self.textEdit.append('(<font color=blue><b>' + dec2bin(eingang) + '</b></font>)' + ' - ' )
        print("Update wurde aufgerufen",dec2bin(~eingang))
        
        
        zahl= dec2bin(eingang)
        
        
        for i in range(0,len(zahl)):
            if zahl[i]=='1':
                self.liste_square[i].setStyleSheet("background-color:black;")
            else:
                self.liste_square[i].setStyleSheet("background-color:green;")
                
                    
    def buttonClicked(self):
        """ Button angeklickt """
        sender = self.sender()
        self.performAction(sender.id)
        
        
    """    
    Bei klicken eines Button wird diese Funktion abgerufen und setzt die Farbe in
    einem neben dem Butten stehenden rechteck von schwarz auf rot
    """
    def setColor(self):
        
        source = self.sender()

        
        #Port-A
        if source.text() == "Pin 1A":
            if source.isChecked()==True:
                self.square1_A.setStyleSheet("background-color:red;")
            #    pin1_gedrueckt=True
            else:
                self.square1_A.setStyleSheet("background-color:black;")
              #  pin1_gedrueckt=False
              
        if source.text() == "Pin 2A":
            if source.isChecked()==True:
                self.square2_A.setStyleSheet("background-color:red;")
            else:
                self.square2_A.setStyleSheet("background-color:black;")
            
        if source.text() == "Pin 3A":
            if source.isChecked()==True:
                self.square3_A.setStyleSheet("background-color:red;")
            else:
                self.square3_A.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 4A":
            if source.isChecked()==True:
                self.square4_A.setStyleSheet("background-color:red;")
            else:
                self.square4_A.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 5A":
            if source.isChecked()==True:
                self.square5_A.setStyleSheet("background-color:red;")
            else:
                self.square5_A.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 6A":
            if source.isChecked()==True:
                self.square6_A.setStyleSheet("background-color:red;")
            else:
                self.square6_A.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 7A":
            if source.isChecked()==True:
                self.square7_A.setStyleSheet("background-color:red;")
            else:
                self.square7_A.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 8A":
            if source.isChecked()==True:
                self.square8_A.setStyleSheet("background-color:red;")
            else:
                self.square8_A.setStyleSheet("background-color:black;")
            
        #Port-B
        if source.text() == "Pin 1B":
            if source.isChecked()==True:
                self.square1_B.setStyleSheet("background-color:green;")
            else:
                self.square1_B.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 2B":
            if source.isChecked()==True:
                self.square2_B.setStyleSheet("background-color:green;")
            else:
                self.square2_B.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 3B":
            if source.isChecked()==True:
                self.square3_B.setStyleSheet("background-color:green;")
            else:
                self.square3_B.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 4B":
            if source.isChecked()==True:
                self.square4_B.setStyleSheet("background-color:green;")
            else:
                self.square4_B.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 5B":
            if source.isChecked()==True:
                self.square5_B.setStyleSheet("background-color:green;")
            else:
                self.square5_B.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 6B":
            if source.isChecked()==True:
                self.square6_B.setStyleSheet("background-color:green;")
            else:
                self.square6_B.setStyleSheet("background-color:black;")
                
        if source.text() == "Pin 7B":
            if source.isChecked()==True:
                self.square7_B.setStyleSheet("background-color:green;")
            else:
                self.square7_B.setStyleSheet("background-color:black;")
                
    def performAction(self, cmd):
        
        print("perfomAction")
        # Port, Pin, Action (Wenn Pin=0 -> Alle Pins)
        port   = cmd[0]
        pin    = int(cmd[1])
        action = cmd[2:]
                
        if source.text() == "Pin 8B":
            if port == 'A':
                if source.isChecked()==True:
                    self.square8_B.setStyleSheet("background-color:green;")
                    self.sendPortA |= (1 << (pin - 1))
                else:
                    self.square8_B.setStyleSheet("background-color:black;")
                    self.sendPortA &= ~(1 << (pin - 1))
            self.mcp23s17Control.sendSPI(PortExpander.mcp23s17.SPI_GPIOA, self.sendPortA) 
                
                
def dec2bin(value):
    """ Dezimal nach Binaer (8-Bit) konvertieren """
    result = ''
    for i in range(8):
        result = str((value >> i) & 1) + result
    return result
    print(result)

    



class Slicer:
        
    
    # initialize timeframe, slice list, and running
    def __init__(self, timeframe):
        self.running = False
 
        
        self.timeframe = timeframe
        self.slices = []
        self.running = False
        
        
    # add a slice function with arguments to execute in the loop later
    def add_slice(self, fun, args = ()):
        self.slices.append((fun, args))
        
        
    # start the loop in a new thread if not running
    def start(self):
        if self.running:
            return
        threading.Thread(target = self.loop).start()
        
    
    # stop the loop at the next possible clean exit point
    def stop(self):
        self.running = False
        
        
    # execute all the slice functions in fixed timeframes until stopped
    def loop(self):
        self.running = True
        while self.running:
            for s in self.slices:
                tdiff = self.exec_slice(s[0], s[1])
                if tdiff <= 0:
                    #TODO: Blinkende LED hinzufügen
                    print("Achtung: " + s[0].__name__ + " takes too long (" + str(tdiff) + ")")
            
            if len(self.slices) == 0:
                time.sleep(self.timeframe)
        self.running = False
        
    # execute a slice function and extend its runtime to the timeframe value
    def exec_slice(self, fun, args = ()):
        now = time.time()  # get timestamp
        
        fun(*args)  # pass the arguments and execute the function
        
        delta = time.time() - now  # calculate how long the function took to run
        if delta < self.timeframe:  # if there is time left, sleep to reach the target time
            time.sleep(self.timeframe - delta)
        return self.timeframe - delta
    
    
        pingg = False
        self.initUI()
        self.sendPortA = 0x00
        #self.readPortB = 0x00

        # MCP23S17-Parameter: ID, SCLK, MOSI, MISO, CS
        self.mcp23s17Control = PortExpander.mcp23s17(0, 18, 24, 23, 25)
        self.mcp23s17Control.sendSPI(PortExpander.mcp23s17.SPI_IODIRA, 0x00) # PPIOA als Ausgaenge programmieren
        self.mcp23s17Control.sendSPI(PortExpander.mcp23s17.SPI_IODIRB, 0xFF) # PPIOB als Eingaenge programmieren
        
        
# Funktionen zur Ausfuehrung

def toggle_led():
    # led on    -> off
    # led off   -> on
    print("OUTPUT")
    pass
    
def check_button():
    # check if the button is pressed
    # do something
    print("INPUT")
    pass

def check_input(gpio_port):
    # read the value from pin
    # save it / do something with it

    pass

def set_output(gpio_port):
    # set some output pin

    pass

def divide_stuff(num1, num2):
    # simulate doing stuff
    for i in range(num1, num2):
        k = i/(i+1)

#Teile aus GUI-Thread
#update = pyqtSignal(int, name='update')
        
def __del__(self):
    self.wait()


if __name__ == "__main__":
    s = Slicer(0.1)  # init slicer
    
    # add all functions
    s.add_slice(toggle_led)
    s.add_slice(check_button)
    #s.add_slice(run)
    #...
    s.add_slice(divide_stuff, (1, 11000))

    # start the slicer
    s.start()


    # wait for keyboard input
    try:
        input() # in python3.x
        # raw_input() in python2.x
    except:
        pass
    # stop the slicer and exit
    s.stop()
    
    
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    form = Form()
    form.show()
    sys.exit(app.exec_())

__deets__
User
Beiträge: 3704
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mittwoch 15. August 2018, 15:02

Du hast das doch selbst so programmiert. Da steht doch sprichwoertlich 'wait for keyboard input'. Und dann wird da eben gewartet. Und danach steht da "stop the slicer". Dann wird der gestoppt. Und DANACH steht da erst die GUI.
__deets__
User
Beiträge: 3704
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mittwoch 15. August 2018, 15:05

Oh, und der slicer hat noch einen fetten Bug, weil du erst in loop den Wert running auf True setzt. Damit gibt es einen Zeitraum zwischen dem tatsaechlichen Start des Threads, und einem eventuell schon einkommenden stop()-call, in dem letzterer zu frueh kommt, und erst DANACH der loop beginnt. Das solltest du ganz schnell aendern und running im main-thread auf True setzen, damit der loop dann nicht doch einfach loslaeuft.
Sirius3
User
Beiträge: 8603
Registriert: Sonntag 21. Oktober 2012, 17:20

Mittwoch 15. August 2018, 19:36

@Falcon: wie bei allen GUIs gilt, dass man sie nur aus dem Hauptthread heraus ändern darf. Ein __del__ sollte es eigentlich nicht geben, ist hier auch überflüssig, ist auch an der falschen Stelle und falsch eingerückt. Das mit dem `self.running` ist auch fehlerhaft, weil man mit Threads nur über entsprechende Datenstrukturen wie Events oder Queues kommunizieren darf.
Falcon
User
Beiträge: 2
Registriert: Mittwoch 15. August 2018, 14:23

Donnerstag 16. August 2018, 05:25

Ja es ist wirklich peinlich den Keyboard input zu übersehen ... !

Werde alles schnll fixen.

Vielen Dank! :)
Antworten