pyserial und with
- __blackjack__
- User
- Beiträge: 13076
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@kaytec: Ich finde die Aufteilung komisch. Nicht zuletzt weil Programmlogik und GUI nicht sauber getrennt ist.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Hallo BlackJack,
ist bestimmt komisch, doch ich hatte auf einen brauchbaren Beitrag von dem Verlag gehofft. Ich messe evtl. nur einige Durchläufe und bilde einen Mittelwert. Eine ständige Interaktion von „Gui/Thread /Adapter“ gibt die Schaltung evtl. nicht her.
Werde eine sinnvolle Trennung versuchen – ist der Fehler schon in dem Beispiel von dem Verlag enthalten ?
Gruß Frank
ist bestimmt komisch, doch ich hatte auf einen brauchbaren Beitrag von dem Verlag gehofft. Ich messe evtl. nur einige Durchläufe und bilde einen Mittelwert. Eine ständige Interaktion von „Gui/Thread /Adapter“ gibt die Schaltung evtl. nicht her.
Werde eine sinnvolle Trennung versuchen – ist der Fehler schon in dem Beispiel von dem Verlag enthalten ?
Gruß Frank
Hallo,
habe mal was umgeschriebe und hoffe die Trennung ist ok. Kann die "queue" geleert werden ?
Gruß Frank
habe mal was umgeschriebe und hoffe die Trennung ist ok. Kann die "queue" geleert werden ?
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import Tkinter as tk
import serial
import time
import threading
import sys
from functools import partial
import Queue
WIDTH = 200
HEIGHT = 100
DEVICE = "/dev/ttyUSB0"
class CapacitanceUI(tk.LabelFrame):
MEASURE_COUNTER = 10
def __init__(self, parent,
width,
height,
device,
update_interval = 1000,
text_color = "blue",
error_font = "system 5 bold",
display_font = "system 18 bold"):
tk.LabelFrame.__init__(self, parent, text = "CAPACITANCE",
relief = "solid")
self.width = width
self.height = height
self.parent = parent
self.device = device
self.update_interval = update_interval
self.text_color = text_color
self.error_font = error_font
self.display_font = display_font
self.queue = Queue.Queue()
self.serial_thread_client = SerialThreadedClient(device, self.queue)
self.after_id = None
self.measure_counter = self.MEASURE_COUNTER
self.measuring_data = list()
self.display = tk.Canvas(self,
width = width,
height = height,
bg="cyan")
self.display.pack(padx = 5, pady = 5)
self.update_cap_display("00.00 uf", False)
button_frame = tk.Frame(self, bg = "gray")
button_frame.pack(padx = 5, pady = 5)
self.buttons = list()
for column, (text, width, command, var) in enumerate(
(("START", 3, self.measure_start_stop, ()),
("+", 2, self.measure_counter_up_down, (1,)),
("-", 2, self.measure_counter_up_down, (-1,)))):
button = tk.Button(button_frame, text=text, width=width,
command=partial(command, *var))
button.grid(column=column, row=0)
self.buttons.append(button)
def measure_start_stop(self):
if not self.after_id:
for button in self.buttons:
button.config(state = "disabled")
self.serial_thread_client.start_stop()
self.measure()
else:
for button in self.buttons:
button.config(state = "active")
self.measuring_data = list()
self.measure_counter = self.MEASURE_COUNTER
self.update_cap_display(
"{0}: {1}".format("COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
self.serial_thread_client.start_stop()
self.measure_counter = self.MEASURE_COUNTER
self.after_cancel(self.after_id)
self.after_id = None
def measure_counter_up_down(self, step):
if not self.after_id:
if self.measure_counter > -step:
self.measure_counter += step
self.update_cap_display(
"{0}: {1}".format("COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
def update_cap_display(self, text, is_error, tag = "cap", width = None,
height = None):
self.display.delete(tag)
display_width = self.width / 2 if not width else width
display_height = self.height / 2 if not height else height
self.display.create_text(
display_width,
display_height,
text = text,
font = self.error_font if is_error else self.display_font,
fill = self.text_color,
tag = tag)
def measure(self):
if self.measure_counter > 0:
try:
measure_time, state = self.queue.get(0)
if not state:
capacity = measure_time * 1000 - 50 * measure_time
self.measuring_data.append(capacity)
self.update_cap_display("{0:2.2f} uf".format(capacity), False,
"cap")
else:
self.update_cap_display(measure_time, state, "error")
self.display.delete("cap")
except Queue.Empty:
if len(self.measuring_data) == 0:
self.update_cap_display("!! WAIT !!",
False)
self.measure_counter -= 1
self.after_id = self.after(self.update_interval, self.measure)
else:
if len(self.measuring_data) > 0:
if len(self.measuring_data) > 1:
total_data = 0
for data in self.measuring_data:
total_data += data
total_data = total_data / len(self.measuring_data)
self.update_cap_display("{0:2.2f} uf".format(total_data),
False)
self.after(int(self.measuring_data[0] * 1.5),
self.measure_start_stop)
else:
self.measure_start_stop()
def release(self):
self.parent.destroy()
self.serial_thread_client.release()
class SerialThreadedClient(object):
def __init__(self, device, queue):
self.device = device
self.queue = queue
self.running = None
def start_stop(self):
if self.running:
self.running = None
else:
self.running = True
self.thread = threading.Thread(target=self.workerThread)
self.thread.start()
def workerThread(self):
end = None
while self.running:
try:
with serial.Serial(self.device) as ser:
ser.dtr = False
start = time.time()
while not ser.dsr:
end = time.time() - start
ser.dtr = True
if end * 1000 >= 1:
self.queue.put((end, False))
else:
self.queue.put(("capacity < 1 µf or not connected",
True))
except (serial.SerialException, IOError) as error:
self.queue.put((error, True))
if end:
time.sleep(end * 3)
def release(self):
self.running = None
sys.exit(1)
def main():
root = tk.Tk()
root.title("CAPACITANCE")
capacitance_ui = CapacitanceUI(root, WIDTH, HEIGHT, DEVICE)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Ohne jetzt den ganzen GUI-Code angeschaut zu haben, sieht die Trennung von Messung und Anzeige jetzt gut aus.
SerialThreadedClient.release sollte kein sys.exit haben, das ist sehr überraschend, dort das komplette Programm zu beenden. Das sollte auch automatisch passieren, in dem sich mainloop beendet.
Auch ist komisch, dass running die Werte None/True annehmen kann, statt False/True.
Idealerweise wäre running auch ein Event, um korrekt mit dem Thread zu kommunizieren.
SerialThreadedClient.release sollte kein sys.exit haben, das ist sehr überraschend, dort das komplette Programm zu beenden. Das sollte auch automatisch passieren, in dem sich mainloop beendet.
Auch ist komisch, dass running die Werte None/True annehmen kann, statt False/True.
Idealerweise wäre running auch ein Event, um korrekt mit dem Thread zu kommunizieren.
Das end = None am Anfang von workerThread() ist gefährlich. Wenn man damit weiterrechnet und keine Zahl eingesetzt wurde, dann kracht es. Hier besser 0 oder 0.0 als Startwert festlegen. Noch eleganter ist es, gänzlich auf solche Startwerte zu verzichten und die Programmlogik ggf anzupassen.
Hallo,
danke Snafu und hier mit Leerung der "queue", die bestimmt nicht schön gelöst ist.
Gruß Frank
danke Snafu und hier mit Leerung der "queue", die bestimmt nicht schön gelöst ist.
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import Tkinter as tk
import serial
import time
import threading
from functools import partial
import Queue
WIDTH = 200
HEIGHT = 100
DEVICE = "/dev/ttyUSB0"
class CapacitanceUI(tk.LabelFrame):
MEASURE_COUNTER = 10
def __init__(self, parent,
width,
height,
device,
update_interval = 1000,
text_color = "blue",
error_font = "system 5 bold",
display_font = "system 18 bold"):
tk.LabelFrame.__init__(self, parent, text = "CAPACITANCE",
relief = "solid")
self.width = width
self.height = height
self.parent = parent
self.device = device
self.update_interval = update_interval
self.text_color = text_color
self.error_font = error_font
self.display_font = display_font
self.queue = Queue.Queue()
self.serial_thread_client = SerialThreadedClient(device, self.queue)
self.after_id = None
self.measure_counter = self.MEASURE_COUNTER
self.measuring_data = list()
self.display = tk.Canvas(self,
width = width,
height = height,
bg="cyan")
self.display.pack(padx = 5, pady = 5)
self.update_cap_display("00.00 uf", False)
button_frame = tk.Frame(self, bg = "gray")
button_frame.pack(padx = 5, pady = 5)
self.buttons = list()
for column, (text, width, command, var) in enumerate(
(("START", 3, self.measure_start_stop, ()),
("+", 2, self.measure_counter_up_down, (1,)),
("-", 2, self.measure_counter_up_down, (-1,)))):
button = tk.Button(button_frame, text=text, width=width,
command=partial(command, *var))
button.grid(column=column, row=0)
self.buttons.append(button)
def measure_start_stop(self):
if not self.after_id:
for button in self.buttons:
button.config(state = "disabled")
self.display.delete("error")
self.serial_thread_client.start_stop()
self.measure()
else:
for button in self.buttons:
button.config(state = "active")
self.measuring_data = list()
self.measure_counter = self.MEASURE_COUNTER
self.update_cap_display(
"{0}: {1}".format("COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
self.serial_thread_client.start_stop()
self.measure_counter = self.MEASURE_COUNTER
self.after_cancel(self.after_id)
self.after_id = None
def measure_counter_up_down(self, step):
if not self.after_id:
if self.measure_counter > -step:
self.measure_counter += step
self.update_cap_display(
"{0}: {1}".format("COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
def update_cap_display(self, text, is_error, tag = "cap", width = None,
height = None):
self.display.delete(tag)
display_width = self.width / 2 if not width else width
display_height = self.height / 2 if not height else height
self.display.create_text(
display_width,
display_height,
text = text,
font = self.error_font if is_error else self.display_font,
fill = self.text_color,
tag = tag)
def measure(self):
if self.measure_counter > 0:
try:
measure_time, state = self.queue.get(-1)
if not state:
capacity = measure_time * 1000 - 50 * measure_time
self.measuring_data.append(capacity)
self.update_cap_display("{0:2.2f} uf".format(capacity), False,
"cap")
self.update_cap_display(
"{0}: {1}".format("COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
else:
self.update_cap_display(measure_time, state, "error",
self.width / 2, 10)
self.display.delete("cap")
except Queue.Empty:
if len(self.measuring_data) == 0:
self.update_cap_display("!! WAIT !!",
False)
self.measure_counter -= 1
self.after_id = self.after(self.update_interval, self.measure)
else:
if len(self.measuring_data) > 0:
if len(self.measuring_data) > 1:
total_data = 0
for data in self.measuring_data:
total_data += data
total_data = total_data / len(self.measuring_data)
self.update_cap_display("{0:2.2f} uf".format(total_data),
False)
for i in xrange(self.queue.qsize()):
self.queue.get(0)
self.after(int(self.measuring_data[0] * 1.5),
self.measure_start_stop)
else:
self.measure_start_stop()
def release(self):
self.parent.destroy()
self.serial_thread_client.release()
class SerialThreadedClient(object):
def __init__(self, device, queue):
self.device = device
self.queue = queue
self.running = False
def clear_queue(self):
for item in xrange(self.queue.qsize()):
try:
self.queue.get(0)
except Queue.Empty:
break
def start_stop(self):
if self.running:
self.running = False
else:
self.running = True
self.thread = threading.Thread(target=self.workerThread)
self.thread.start()
def workerThread(self):
end = 0.0
while self.running:
try:
with serial.Serial(self.device) as ser:
ser.dtr = False
start = time.time()
while not ser.dsr:
end = time.time() - start
ser.dtr = True
if end * 1000 > 1:
self.queue.put((end, False))
else:
self.queue.put(("capacity < 1 µf or not connected",
True))
except (serial.SerialException, IOError) as error:
self.queue.put((error, True))
if end:
self.clear_queue()
time.sleep(end * 3)
def release(self):
self.running = False
def main():
root = tk.Tk()
root.title("CAPACITANCE")
capacitance_ui = CapacitanceUI(root, WIDTH, HEIGHT, DEVICE)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Hallo,
"while self.running" ist raus und durch "after" ersetzt.
"while self.running" ist raus und durch "after" ersetzt.
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import Tkinter as tk
import serial
import time
import threading
from functools import partial
import Queue
WIDTH = 270
HEIGHT = 100
DEVICE = "/dev/ttyUSB0"
class CapacitanceUI(tk.LabelFrame):
MEASURE_COUNTER = 10
def __init__(self, parent,
width,
height,
device,
update_interval = 1000,
text_color = "blue",
error_font = "system 5 bold",
display_font = "system 18 bold"):
tk.LabelFrame.__init__(self, parent, text = "CAPACITANCE",
relief = "solid")
self.width = width
self.height = height
self.parent = parent
self.device = device
self.update_interval = update_interval
self.text_color = text_color
self.error_font = error_font
self.display_font = display_font
self.queue = Queue.Queue()
self.serial_thread_client = SerialThreadedClient(device, parent, self.queue)
self.after_id = None
self.measure_counter = self.MEASURE_COUNTER
self.measuring_data = list()
self.display = tk.Canvas(self,
width = width,
height = height,
bg="cyan")
self.display.pack(padx = 5, pady = 5)
self.update_cap_display("00.00 uf", False)
button_frame = tk.Frame(self, bg = "gray")
button_frame.pack(padx = 5, pady = 5)
self.buttons = list()
for column, (text, width, command, var) in enumerate(
(("START", 3, self.measure_start_stop, ()),
("+", 2, self.measure_counter_up_down, (1,)),
("-", 2, self.measure_counter_up_down, (-1,)))):
button = tk.Button(button_frame, text=text, width=width,
command=partial(command, *var))
button.grid(column=column, row=0)
self.buttons.append(button)
def measure_start_stop(self):
if not self.after_id:
for button in self.buttons:
button.config(state = "disabled")
self.display.delete("error")
self.serial_thread_client.clear_queue(0)
self.serial_thread_client.start_stop()
self.measure()
else:
for button in self.buttons:
button.config(state = "active")
self.measuring_data = list()
self.measure_counter = self.MEASURE_COUNTER
self.update_cap_display(
"{0}: {1}".format("COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
self.serial_thread_client.start_stop()
self.after_cancel(self.after_id)
self.after_id = None
def measure_counter_up_down(self, step):
if not self.after_id:
if self.measure_counter > -step:
self.measure_counter += step
self.update_cap_display(
"{0}: {1}".format("COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
def update_cap_display(self, text, is_error, tag = "cap", width = None,
height = None):
self.display.delete(tag)
display_width = self.width / 2 if not width else width
display_height = self.height / 2 if not height else height
self.display.create_text(
display_width,
display_height,
text = text,
font = self.error_font if is_error else self.display_font,
fill = self.text_color,
tag = tag)
def measure(self):
if self.measure_counter > 0:
try:
measure_time, state = self.queue.get(-1)
if not state:
if measure_time:
capacity = measure_time * 1000 - 50 * measure_time
self.measuring_data.append(capacity)
self.update_cap_display(
"{0:2.2f} uf".format(
capacity),
False,
"cap")
self.update_cap_display(
"{0}: {1}".format(
"COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
else:
self.update_cap_display(
measure_time,
True,
"error",
self.width / 2,
10)
self.measure_counter = 0
except Queue.Empty:
if len(self.measuring_data) == 0:
self.update_cap_display("!! WAIT !!", False)
self.measure_counter -= 1
self.after_id = self.after(self.update_interval, self.measure)
else:
if len(self.measuring_data) > 0:
if len(self.measuring_data) > 1:
self.measuring_data.pop(-1)
total_data = 0
for data in self.measuring_data:
total_data += data
total_data = total_data / len(self.measuring_data)
self.update_cap_display("{0:2.2f} uf".format(total_data),
False)
for i in xrange(self.queue.qsize()):
self.queue.get(0)
self.after(int(self.measuring_data[0] * 1.5),
self.measure_start_stop)
else:
self.measure_start_stop()
def release(self):
self.parent.destroy()
self.serial_thread_client.release()
class SerialThreadedClient(object):
def __init__(self, device, parent, queue):
self.device = device
self.parent = parent
self.queue = queue
self.run = False
def clear_queue(self, min = 1):
while self.queue.qsize() > min:
self.queue.get(0)
def start_stop(self):
if self.run:
self.parent.after_cancel(self.thread_id)
self.thread_id = None
self.run = False
else:
self.run = True
self.thread = threading.Thread(target=self.worker_thread)
self.thread.start()
def worker_thread(self):
end = 0
if self.run:
try:
with serial.Serial(self.device) as ser:
ser.dtr = False
start = time.time()
while not ser.dsr:
end = time.time() - start
ser.dtr = True
if end * 1000 > 1:
self.queue.put((end, False))
else:
self.queue.put(("capacity < 1 µf or not connected",
True))
self.run = False
except (serial.SerialException, IOError) as error:
self.queue.put((error, True))
self.run = False
self.clear_queue()
self.thread_id = self.parent.after(int(end * 10000),
self.worker_thread)
def release(self):
self.running = False
def main():
root = tk.Tk()
root.title("CAPACITANCE")
capacitance_ui = CapacitanceUI(root, WIDTH, HEIGHT, DEVICE)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Fehler beseitgt
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import Tkinter as tk
import serial
import time
import threading
from functools import partial
import Queue
WIDTH = 270
HEIGHT = 100
DEVICE = "/dev/ttyUSB0"
class CapacitanceUI(tk.LabelFrame):
MEASURE_COUNTER = 10
def __init__(self, parent,
width,
height,
device,
update_interval = 3000,
text_color = "blue",
error_font = "system 5 bold",
display_font = "system 18 bold"):
tk.LabelFrame.__init__(self, parent, text = "CAPACITANCE",
relief = "solid")
self.width = width
self.height = height
self.parent = parent
self.device = device
self.update_interval = update_interval
self.text_color = text_color
self.error_font = error_font
self.display_font = display_font
self.queue = Queue.Queue()
self.serial_thread_client = SerialThreadedClient(device, parent, self.queue)
self.after_id = None
self.measure_counter = self.MEASURE_COUNTER
self.measuring_data = list()
self.display = tk.Canvas(self,
width = width,
height = height,
bg="cyan")
self.display.pack(padx = 5, pady = 5)
self.update_cap_display("00.00 uf", False)
button_frame = tk.Frame(self, bg = "gray")
button_frame.pack(padx = 5, pady = 5)
self.buttons = list()
for column, (text, width, command, var) in enumerate(
(("START", 3, self.measure_start_stop, ()),
("+", 2, self.measure_counter_up_down, (1,)),
("-", 2, self.measure_counter_up_down, (-1,)))):
button = tk.Button(button_frame, text=text, width=width,
command=partial(command, *var))
button.grid(column=column, row=0)
self.buttons.append(button)
def measure_start_stop(self):
if not self.after_id:
for button in self.buttons:
button.config(state = "disabled")
self.display.delete("error")
self.serial_thread_client.clear_queue(0)
self.serial_thread_client.start_stop()
self.measure()
else:
for button in self.buttons:
button.config(state = "active")
self.measuring_data = list()
self.measure_counter = self.MEASURE_COUNTER
self.update_cap_display(
"{0}: {1}".format("COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
self.serial_thread_client.start_stop()
self.after_cancel(self.after_id)
self.after_id = None
def measure_counter_up_down(self, step):
if not self.after_id:
if self.measure_counter > -step:
self.measure_counter += step
self.update_cap_display(
"{0}: {1}".format("COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
def update_cap_display(self, text, is_error, tag = "cap", width = None,
height = None):
self.display.delete(tag)
display_width = self.width / 2 if not width else width
display_height = self.height / 2 if not height else height
self.display.create_text(
display_width,
display_height,
text = text,
font = self.error_font if is_error else self.display_font,
fill = self.text_color,
tag = tag)
def measure(self):
measure_time = 1
if self.measure_counter > 0:
try:
measure_time, state = self.queue.get(0)
if not state:
if measure_time:
capacity = measure_time * 1000 - 50 * measure_time
self.measuring_data.append(capacity)
self.update_cap_display(
"{0:2.2f} uf".format(
capacity),
False,
"cap")
else:
self.update_cap_display(
measure_time,
True,
"error",
self.width / 2,
10)
self.measure_counter = 0
measure_time = 1
except Queue.Empty:
if len(self.measuring_data) == 0:
self.update_cap_display("!! WAIT !!", False)
self.update_cap_display(
"{0}: {1}".format(
"COUNTS",
self.measure_counter),
True,
"counter",
30,
self.height - 10)
self.measure_counter -= 1
self.after_id = self.after(int(self.update_interval
* measure_time), self.measure)
else:
if len(self.measuring_data) > 0:
if len(self.measuring_data) > 1:
self.measuring_data.pop(-1)
total_data = 0
for data in self.measuring_data:
total_data += data
total_data = total_data / len(self.measuring_data)
self.update_cap_display("{0:2.2f} uf".format(total_data),
False)
for i in xrange(self.queue.qsize()):
self.queue.get(0)
self.after(int(self.measuring_data[0] * 1.5),
self.measure_start_stop)
else:
self.measure_start_stop()
def release(self):
self.parent.destroy()
self.serial_thread_client.release()
class SerialThreadedClient(object):
def __init__(self, device, parent, queue):
self.device = device
self.parent = parent
self.queue = queue
self.run = False
def clear_queue(self, min = 1):
while self.queue.qsize() > min:
self.queue.get(0)
def start_stop(self):
if self.run:
self.parent.after_cancel(self.thread_id)
self.thread_id = None
self.run = False
else:
self.run = True
self.thread = threading.Thread(target=self.worker_thread)
self.thread.start()
def worker_thread(self):
end = 0
if self.run:
try:
with serial.Serial(self.device) as ser:
ser.dtr = False
start = time.time()
while not ser.dsr:
end = time.time() - start
ser.dtr = True
if end * 1000 > 1:
self.queue.put((end, False))
else:
self.queue.put(("capacity < 1 µf or not connected",
True))
self.run = False
except (serial.SerialException, IOError) as error:
self.queue.put((error, True))
self.run = False
self.clear_queue()
self.thread_id = self.parent.after(int(end * 3000),
self.worker_thread)
def release(self):
self.running = False
def main():
root = tk.Tk()
root.title("CAPACITANCE")
capacitance_ui = CapacitanceUI(root, WIDTH, HEIGHT, DEVICE)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Übrigens: Wenn keine Fragen zum Code bestehen, man aber trotzdem regelmäßig Änderungen protokollieren möchte, dann empfiehlt sich sowas wie https://pastebin.com/ oder https://gist.github.com/ weil man damit nicht durch ellenlange Threads scrollen muss und mehr Übersicht hat...
@kaytec: Du hast Deinen Code jetzt verschlimmbessert. Statt dass die Messung unabhängig von der GUI läuft, rufst Du beim ersten Durchgang aus einem anderen Thread eine GUI-Methode auf (verboten!) und danach läuft die Messung im selben Thread wie die GUI, läßt sie also wieder einfrieren.
Also alles zurück, in SerialThreadedClient darf es keinen Verweis auf `parent` oder irgend ein anderes GUI-Element geben.
Also alles zurück, in SerialThreadedClient darf es keinen Verweis auf `parent` oder irgend ein anderes GUI-Element geben.
Hallo,
snafu und Sirius3. Ich habe immer Fragen und kann nie so richtig sagen, ob ich mit meinen Änderungen richtig liege. Hier bekommt man ja eine sehr gute Hilfe und es haben evtl. auch andere Leser gleiche Probleme. Ich poste eigentlich erst, wenn das Script bei mir fehlerfrei läuft und ich vermute es könnte so stimmen.
Wie mache ich es jetzt richtig - mir gehen die Ideen aus ?
Gruß Frank
snafu und Sirius3. Ich habe immer Fragen und kann nie so richtig sagen, ob ich mit meinen Änderungen richtig liege. Hier bekommt man ja eine sehr gute Hilfe und es haben evtl. auch andere Leser gleiche Probleme. Ich poste eigentlich erst, wenn das Script bei mir fehlerfrei läuft und ich vermute es könnte so stimmen.
Wie mache ich es jetzt richtig - mir gehen die Ideen aus ?
Gruß Frank
Hallo,
und meine Suche ergab noch dies --> https://noisefloor-net.blogspot.com/201 ... reads.html
Müsste ich so hinbekommen - oder noch mehr verschlimmern !
Gruß Frank
und meine Suche ergab noch dies --> https://noisefloor-net.blogspot.com/201 ... reads.html
Müsste ich so hinbekommen - oder noch mehr verschlimmern !
Gruß Frank
Deine Variante vom Montag 4. März 2019, 13:32 Uhr, war doch schon ganz ok. Bis auf das queue-Leeren, was völlig überflüssig und sogar schädlich ist, weil Du die Queue sofort wieder leerst, sobald Du etwas reingeschrieben hast.
Hallo Sirius3,
würde ich ich die "Queue nicht leeren, dann sind noch viele Einträge aus der letzten Messung drin. Beider Messung werden über die gesamte Messdauer Daten geschrieben und eigentlich ist letzte Wert der einzig benötigte. Falls ein Fehler auslöst, dann ist der letzte Eintrag die Fehlermeldung, die für die letzte Anzeige auf dem Display benötigt wird. Würde ich nun die "Queue" nicht komplett leeren, dann ist bei einer neuen Messung im letzte Eintrag noch eine Fehlermeldung mit dem Status=False und es würde der vorhergehende Fehler wieder ausgelöst. Wenn ich heute Abend wieder Zeit habe, dann mache ich ein Minimalbeispiel. So kann es auch ausprobiert werden und die "Hilfesteller" müssen nicht den gesamten "Datenmüll" lesen.
Gruß Frank
würde ich ich die "Queue nicht leeren, dann sind noch viele Einträge aus der letzten Messung drin. Beider Messung werden über die gesamte Messdauer Daten geschrieben und eigentlich ist letzte Wert der einzig benötigte. Falls ein Fehler auslöst, dann ist der letzte Eintrag die Fehlermeldung, die für die letzte Anzeige auf dem Display benötigt wird. Würde ich nun die "Queue" nicht komplett leeren, dann ist bei einer neuen Messung im letzte Eintrag noch eine Fehlermeldung mit dem Status=False und es würde der vorhergehende Fehler wieder ausgelöst. Wenn ich heute Abend wieder Zeit habe, dann mache ich ein Minimalbeispiel. So kann es auch ausprobiert werden und die "Hilfesteller" müssen nicht den gesamten "Datenmüll" lesen.
Gruß Frank
Hallo Sirius3,
Du meinst "while self.queue.qsize()" ? Bei einer Messung von hohen Kapazitäten enstehen recht lange Messzeiten. Bei einer Fehlermeldung wäre es natürlich schön, wenn ich diese nicht noch einige Sekunden sehen muss. Ein Abbruch der Messung führt zu einer nicht vollständig geleerten "Queue".
Gruß Frank
Du meinst "while self.queue.qsize()" ? Bei einer Messung von hohen Kapazitäten enstehen recht lange Messzeiten. Bei einer Fehlermeldung wäre es natürlich schön, wenn ich diese nicht noch einige Sekunden sehen muss. Ein Abbruch der Messung führt zu einer nicht vollständig geleerten "Queue".
Gruß Frank
Hallo Sirius,
hier ist eine entschlackte Version. Man sollte es länger testen, damit auch ein "error" ausgelöst wird. Die Größe der "queue" wird mit einem "print" angezeigt.
Gruß Frank
hier ist eine entschlackte Version. Man sollte es länger testen, damit auch ein "error" ausgelöst wird. Die Größe der "queue" wird mit einem "print" angezeigt.
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import Tkinter as tk
import serial
import time
import random
from threading import Thread, Event
from functools import partial
import Queue
class CapacitanceUI(tk.LabelFrame):
def __init__(self, parent):
tk.LabelFrame.__init__(self, parent)
self.parent = parent
self.queue = Queue.Queue()
self.serial_thread_client = SerialThreadedClient(self.queue)
self.after_id = None
self.measure_counter = 20
self.display = tk.Label(self, width = 20, height = 3)
self.display.pack()
self.start_button = tk.Button(self, text = "START",
command = self.measure_start_stop)
self.start_button.pack()
def measure_start_stop(self):
if not self.after_id:
self.start_button.config(state = "disabled")
self.serial_thread_client.start_stop()
self.measure()
else:
self.start_button.config(state = "active")
self.measure_counter = 20
self.serial_thread_client.start_stop()
self.after_cancel(self.after_id)
self.after_id = None
def measure(self):
measure_time = 1
if self.measure_counter > 0:
if not self.queue.empty():
measure_time, state = self.queue.get(-1)
if not state:
self.display.config(text = measure_time)
else:
self.display.config(text = "error")
self.measure_counter = 0
self.measure_counter -= 1
self.after_id = self.after(1000, self.measure)
else:
self.measure_start_stop()
def release(self):
self.parent.destroy()
class SerialThreadedClient(object):
def __init__(self, queue):
self.queue = queue
self.run = False
self.run_event = None
def clear_queue(self):
while self.queue.qsize() > 0:
self.queue.get(0)
def start_stop(self):
if self.run:
self.run = False
self.run_event.set()
else:
print self.queue.qsize()
self.run_event = Event()
#self.clear_queue()
self.run = True
self.thread = Thread(target=self.worker_thread)
self.thread.start()
def worker_thread(self):
while not self.run_event.is_set():
item = random.randint(0, 4)
if item == 0:
self.queue.put((item, True))
else:
self.queue.put((item, False))
self.run_event.wait(0.5)
def main():
root = tk.Tk()
root.title("CAPACITANCE")
capacitance_ui = CapacitanceUI(root)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
@kaytec: und wo ist die Schleife in `measure`, die die ganze Queue abfragt? Das kann auch deutlich öfter als 1mal pro Sekunde passieren, dann ist die Queue auch nicht so lang.
Du solltest getrennte Funktionen für start und stop haben.
measure_counter dann auf 20 setzen, wenn man mit der Messung startet, nicht, wenn man damit fertig ist.
Du solltest getrennte Funktionen für start und stop haben.
measure_counter dann auf 20 setzen, wenn man mit der Messung startet, nicht, wenn man damit fertig ist.
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import Tkinter as tk
import serial
import time
import random
from threading import Thread, Event
from functools import partial
import Queue
class CapacitanceUI(tk.LabelFrame):
def __init__(self, parent):
tk.LabelFrame.__init__(self, parent)
self.parent = parent
self.queue = Queue.Queue()
self.serial_thread_client = SerialThreadedClient(self.queue)
self.after_id = None
self.measure_counter = 0
self.display = tk.Label(self, width=20, height=3)
self.display.pack()
self.start_button = tk.Button(self, text="START",
command = self.measure_start)
self.start_button.pack()
def measure_start(self):
self.measure_counter = 200
self.start_button['state'] = "disabled"
self.serial_thread_client.start()
self.measure()
def measure_stop(self):
self.start_button['state'] = "active"
self.serial_thread_client.stop()
if self.after_id is not None:
self.after_cancel(self.after_id)
self.after_id = None
def measure(self):
if not self.queue.empty():
while True:
try:
measure_time, error = self.queue.get_nowait()
except Queue.Empty:
break
if error:
self.display['text'] = "error"
self.measure_stop()
return
self.display['text'] = measure_time
self.measure_counter -= 1
if self.measure_counter > 0:
self.after_id = self.after(100, self.measure)
else:
self.measure_stop()
def release(self):
self.measure_stop()
self.parent.destroy()
class SerialThreadedClient(object):
def __init__(self, queue):
self.queue = queue
self.run_event = None
def stop(self):
self.run_event.set()
def start(self):
print self.queue.qsize()
self.run_event = Event()
self.thread = Thread(target=self.worker_thread)
self.thread.daemon = True
self.thread.start()
def worker_thread(self):
while not self.run_event.is_set():
item = random.randint(0, 4)
if item == 0:
self.queue.put((item, True))
else:
self.queue.put((item, False))
self.run_event.wait(0.5)
def main():
root = tk.Tk()
root.title("CAPACITANCE")
capacitance_ui = CapacitanceUI(root)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()