@Alfons Mittelmeyer: Der Compiler braucht die Variable nicht. Zur Übersetzungszeit existieren ja noch gar keine Variablen, die entsteht erst wenn der Code ausgeführt wird und da ist der Compiler dann schon längst durch mit dem Quelltext.
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf8
import Tkinter as tk
from tkFont import Font
FONT_OPTIONS = {'family': 'Helvetica', 'size': 10}
class MeasuredItem(object):
OK, WARNING, CRITICAL = 'OK', 'WARNING', 'CRITICAL'
def __init__(self, name, max_value):
self.name = name
self.max_value = max_value
self.value = 2000
self.state = self.OK
@property
def is_ok(self):
return self.state == self.OK
MEASURED_ITEM_STATE_TO_COLOR = {
MeasuredItem.OK: 'green',
MeasuredItem.WARNING: 'yellow',
MeasuredItem.CRITICAL: 'red',
}
class ErrorFrame(tk.Frame):
def __init__(self, measured_items, parent, **kwargs):
tk.Frame.__init__(self, parent, **kwargs)
self.font = Font(**FONT_OPTIONS)
self.font['size'] = 20
self.labels = list()
self.measured_items = measured_items
self.update()
def update(self):
for label in self.labels:
label.destroy()
for item in self.measured_items:
if not item.is_ok:
label = tk.Label(
self,
text=item.name,
background=self['background'],
foreground=MEASURED_ITEM_STATE_TO_COLOR[item.state],
font=self.font,
)
label.pack(side=tk.TOP)
class MainWindow(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.font = Font(**FONT_OPTIONS)
self.canvas = tk.Canvas(self, bg='black', height=480, width=320)
self.canvas.pack()
self.measured_items = [
MeasuredItem(name, 6000)
for name in [
'RPM', 'Water', 'EGT', 'Fuel Cap.', 'Fuel Flow', 'Oil Temp'
]
]
self.error_frame = ErrorFrame(
self.measured_items, self, width=120, background='black'
)
self.error_frame.place(x=190, y=0)
self._create_main_buttons(
[
('MAIN', self.draw_main_screen),
('ENG', self.not_implemented),
('NAV', self.not_implemented),
('STAT', self.not_implemented),
],
0,
)
self._create_main_buttons(
[
('PERF.', self.not_implemented),
('MEDIA', self.not_implemented),
('NET', self.not_implemented),
('SETTINGS', self.not_implemented),
],
290,
)
self._draw_boot_screen()
def _create_main_buttons(self, names_and_callbacks, x_offset):
for i, (name, callback) in enumerate(names_and_callbacks):
tk.Button(
self,
text=name,
wraplength=1,
command=callback,
pady=6,
font=self.font,
).place(x=x_offset, y=i * 120)
def draw_gauge(self, x, y, measured_item, scale_factor=0.8):
gauge_value = measured_item.max_value / float(measured_item.value)
#
# Draw hand.
#
self.canvas.create_arc(
x,
y,
x + 100 * scale_factor,
y + 100 * scale_factor,
start=0,
extent=-(220 / gauge_value),
fill=MEASURED_ITEM_STATE_TO_COLOR[measured_item.state],
)
#
# Draw outline.
#
self.canvas.create_arc(
x - 3,
y - 3,
x + 100 * scale_factor + 3,
y + 100 * scale_factor + 3,
start=0,
extent=-220,
style=tk.ARC,
outline='white',
width=2,
)
#
# Draw value box.
#
self.canvas.create_rectangle(
x + 50 * scale_factor,
y + 20 * scale_factor,
x + 100 * scale_factor + 3,
y + 50 * scale_factor,
outline='white',
width=2,
)
font = self.font.copy()
font['size'] = int(14 * scale_factor)
self.canvas.create_text(
x + 52 * scale_factor,
y + 20 * scale_factor,
anchor=tk.NW,
text=measured_item.value,
fill='turquoise',
font=font,
)
font = self.font.copy()
font['size'] = int(20 * scale_factor)
self.canvas.create_text(
x,
y - 15,
anchor=tk.NW,
text=measured_item.name,
fill='white',
font=font,
)
def not_implemented(self):
pass
def _draw_boot_screen(self):
self.canvas.delete(tk.ALL)
self.draw_gauge(70, 50, self.measured_items[0])
def draw_main_screen(self):
self.canvas.delete(tk.ALL)
for i, measured_item in enumerate(self.measured_items[:3]):
self.draw_gauge(50, 20 + i * 100, measured_item)
def main():
main_window = MainWindow()
main_window.mainloop()
if __name__ == '__main__':
main()
Das ursprüngliche Problem wird dabei komplett umgangen, denn es werden einfach keine Label mehr verwendet sondern der Text wird mit `Canvas.create_text()` erzeugt. Damit wird der automatisch beim ``delete(tk.ALL)`` schon erfasst. Sonst hätte man mit den `Label`-Objekten `create_window()` verwenden müssen um diesen Effekt zu erreichen.
Ich würde als nächstes eine Messanzeige als eigenen Datentyp dort heraus ziehen und zwar auf einem eigenen `Canvas` gezeichnet, und dann Tk's Layout-Mechanismen benutzen statt alles an selber berechneten Positionen zu platzieren. Und dann die einzelnen Bildschirme in Klassen auslagern und wahrscheinlich auch alle am Anfang erstellen und dann beim Wechseln nicht löschen sondern auswechseln. Das kann man Beispielsweise erreichen in dem man einen Bildschirm von `tk.Frame` erben lässt und ihn dann mit einer Layout-Methode im Hauptfenster anordnet und mit der entsprechenden `*_forget()`-Methode wieder aus der Anzeige herausnimmt bevor man den nächsten Bildschirm anzeigt.