QTimer Verständnisproblem

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
caargoo
User
Beiträge: 20
Registriert: Sonntag 26. Januar 2020, 10:42

Hallo zusammen,
ich möchte einen String von einem Mikrocontroller in einer sehr einfachen GUI Anwendung(nur ein Label) angezeigt bekommen.

Code: Alles auswählen

import sys
import PyQt5.QtCore as core
import PyQt5.QtWidgets as widgets
import PyQt5.QtGui as gui
import PyQt5.uic as uic
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtCore import QObject, QTimer
import time
import serial

timer = QTimer()
app = widgets.QApplication(sys.argv) 
win = uic.loadUi("AM2320.ui")

def msgButtonClick():
	pass

def SerialFehler():
	msg = QMessageBox()
	msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
	msg.setIcon(QMessageBox.Critical)
	msg.setWindowTitle("FEHLER!")
	msg.setText("COM nicht vorhanden!")
	msg.setInformativeText("Kann nicht verbinden!")
	msg.setStandardButtons(QMessageBox.Ok)
	msg.buttonClicked.connect(msgButtonClick)
	returnValue = msg.exec()
	if returnValue == QMessageBox.Ok:
		exit()
				
try:
	ser = serial.Serial('COM11',19200, timeout=1)
	ser.close()
	win.statusBar.showMessage(ser.name + " VERBUNDEN") #STATUSBAR!!!!
	
except serial.serialutil.SerialException:
	win.statusBar.showMessage(">> COM NICHT VERBUNDEN! <<") #STATUSBAR!!!! 
	SerialFehler()
	
	
def einlesen():
	if ser.is_open:
		ser.close()
		
	ser.open()
	x = ser.in_waiting
	
	if x >  0:
		s = ser.read(x)
		print(s)
		s = str(s)
		print(s)
		print(s.rfind("F"))
		n = (s.rfind("F"))
		if n == 2:
			win.label_1.setText(s[3:8])
			
		if n == 3:
			win.label_2.setText(s[4:9])
			
		ser.close()

		
timer.timeout.connect(einlesen)
timer.start(1000) 
print(timer.isActive())

win.show()
sys.exit(app.exec_())
Timer.isActive = True, aber er springt nicht nach einlesen().
Kann mir bitte jemand auf die Sprünge helfen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Woher weißt du, dass er nicht in einlesen einspringt? Ich sehe da keine Ausgabe, die das belegen würde. Was auf jeden Fall *nicht* so geht wie du das zu erwarten scheinst: das serielle Daten gepuffert werden, auch wenn kein Gerät geöffnet ist. Das passiert so nicht. Der Kernel hätte sonst eine Menge nutzloser Daten aufzubewahren. Du musst die Verbindung geöffnet halten, und dann später im Timer damit arbeiten. Wozu auch die Verwendung von Objekten anzuraten ist, denn so hantierst du mit globalen Variablen, und die sind boese(tm).
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@caargoo: Eingerückt wird in Python mit vier Leerzeichen pro Ebene, nicht mit Tabs.

Du öffnest eine serielle Verbindung und schliesst sie sofort wieder und informierst den Benutzer dann darüber, dass er Verbunden ist, obwohl er das nach dem `close()` ja gar nicht ist‽

Von der GUI heraus sollte man nicht `sys.exit()` aufrufen. Damit umgeht man den von Qt vorgesehenen Weg eine GUI-Anwendung ordentlich zu beenden. Da sollte man `quit()` auf dem Qt-Anwendungsobjekt aufrufen, damit am Ende dann auch tatsächlich der Punkt erreicht wird, wo das `sys.exit()` in der letzten Zeile ausgeführt wird.

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
Sirius3
User
Beiträge: 18051
Registriert: Sonntag 21. Oktober 2012, 17:20

Eingerückt wird immer mit 4 Leerzeichen pro Ebene, keine Tabs.
`ser.is_open` ist eine Funktion und damit immer wahr. Das close wird also immer ausgeführt. Was auch nicht weiter schlimm ist, aber das if ist überflüssig.
`ser.in_waiting` ist auch eine Funktion, die kann aber nie größer als 1 sein, weil ein Vergleich einer Funktion mit einer Zahl keinen Sinn ergibt.
`x` wäre für eine ganze Zahl auch ein falscher Name, weil man mit x eine Kommazahl verbindet.
Dann sind natürlich die ganzen globalen Variablen schlecht, weil man im ganzen Code nicht durchblickt. Für GUIs braucht man zwangsläufig Klassendefinitionen.
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

`is_open` und `in_waiting` sind beides Attribute. Letzteres ein Property, aber das ist ja letztlich ein Implementierungsdetail. Die alte API hatte `isOpen()` und `inWaiting()` als Methoden.

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
caargoo
User
Beiträge: 20
Registriert: Sonntag 26. Januar 2020, 10:42

Danke für die zahlreichen Antworten.
Fürs erste funktionierts soweit. Hab mich mit ser.open und close selbst in die Irre geführt.
Die Einrückungen waren in der IDE(Wing) auf Tabs gestellt, habs korrigiert.
@Sirius3: Das mit in_waiting funktioniert aber. Ich schicke 2 Strings, einmal mit 8Zeichen und
einmal mit 9Zeichen, dementsprechend ist x entweder 8 oder 9. Viel größer wird das Progrämmchen
nicht, nur ein zweites Label kommt noch hinzu.
Alle anderen nützlichen Hinweise werde ich versuchen nach und nach umzusetzen.
Antworten