Ich hab mich jetzt mal etwas mit dem WCK von effbot beschäftigt und möchte es hier mal mit einem Beispielscript vorstellen.
Als einfaches Beispiel hab ich ein RasterFrame geschrieben, mit dem man 2d-Arrays anzeigen kann. An einem Anwendungsbeispiel, das den tieferen Sinn dieses Widgets zeigt, arbeite ich noch.
Code: Alles auswählen
from WCK import Widget, EventMixin
class RasterFrame(EventMixin, Widget):
"""Widget zum darstellen und ändern von Arrays.
werte = {0:("white", "black"), i: ("color", bd-color")}: Zuordnung von Farben zu den vorkommenden Werten
array = [[1,2,0,0,3],[1,2,0,1],[i,i,i,i],[...]]: 2d-Array (Liste), das anfangs dargestellt wird
editierbar = True: Bool, ob das array manuell (per Mausklick) geändert werden kann"""
ui_option_werte = {0 : ("white", "black"), 1:("black", "white")}
ui_option_array = [[1,0],[0,1]]
ui_option_editierbar = True
ui_option_height = 200
ui_option_width = 200
ui_doublebuffer = 1
# def __init__(self, master, **options):
# self.ui_init(master, options)
def ui_handle_config(self):
self.werte = self.ui_option_werte
self.array = self.ui_option_array
self.editierbar = self.ui_option_editierbar
self.height, self.width = self.ui_option_height, self.ui_option_width
return int(self.ui_option_width), int(self.ui_option_height)
def ui_handle_resize(self, width, height):
self.width, self.height = width, height
def ui_handle_clear(self, draw, x0, y0, x1, y1):
pass
def ui_handle_repair(self, draw, x0, y0, x1, y1):
xeinheit = self.width / len(self.array[0])
yeinheit = self.height / len(self.array)
for i1, x in enumerate(self.array):
for i2, y in enumerate(x):
x1_, y1_ = i1 * xeinheit, i2 * yeinheit
color = self.werte[y]
draw.rectangle((x1_, y1_, x1_ + xeinheit, y1_ + yeinheit),self.ui_pen(color[1]),\
self.ui_brush(color[0]))
def update(self, x, y, wert):
"Aktuallisiert zum zeitsparen nur ein Feld."
xeinheit = self.width / len(self.array[0])
yeinheit = self.height / len(self.array)
x1, y1 = x * xeinheit, y * yeinheit
x2, y2 = x1 + xeinheit, y1 + yeinheit
self.array[x][y] = wert
color = self.werte[wert]
self.ui_draw.rectangle((x1,y1,x2,y2), self.ui_pen(color[1]), self.ui_brush(color[0]))
def onclick(self, event):
"""Bindet Mausklicks: Je nach Taste nimmt das Feld
die nächste oder vorherige Farbe an. Dazu wird
entsprechend das array geändert."""
if self.editierbar:
x, y = event.x, event.y
xeinheit = self.width /len(self.array[0])
yeinheit = self.height /len(self.array)
i1, i2 = x / xeinheit, y / yeinheit
keys = sorted(self.werte.keys())
wert = self.array[i1][i2]
index = keys.index(wert)
if event.num == 1:
if (index - 1) < 0:
index = len(keys)
self.update(i1, i2, keys[index - 1])
elif event.num == 3:
if (index + 1) > len(keys) - 1:
index = -1
self.update(i1, i2, keys[index + 1])
Im scripts-Ordner der Pythoninstallation findet man einige Beispielscripte, die zeigen, "was alles geht".
Um eine eigene Widgetklasse zu schreiben, muss man zunächst von WCK.Widget erben. Das ist die Standartklasse, die alles nötige wie zB. die Geometriemanager usw. enthält.
Dann werden die Attribute als Klassenattribute der Form ui_option_optionname = defaultwert festgelegt. Eine __init__-Methode ist nicht umbedingt nötig.
Als letztes muss die "ui_handle_repair"-Methode definiert werden. Diese ist sozusagen das Zentrum des Widgets, da es hier erzeugt wird. Als Argumente werden "draw" und 4 Punkte übergeben.
Die 4 Punkte beschreiben die Ecken des Widgets (nw und se). Über "draw" kann man direkt auf die Widgetfläche Zeichnen und schreiben, ähnlich wie beim Tkinter.Canvas. Immer, wenn das Widget neu aufgebaut wird, also bei Größenänderung, etc. wird diese Methode aufgerufen.
Zuvor wird das Widget jedoch "geleert". Dazu wird die Methode "ui_handle_clear" aufgerufen, die normalerweise die Widgetfläche mit der Hintergrundfarbe füllt. Wenn man in der repair-Methode aber eh alles neu "malt", kann man durch deaktivierung der clear-Methode etwas Zeit sparen.
Mit weiteren Methoden wie den im Bsp. genutzten kann man interne Events abfangen und verarbeiten.
Richtige Events, also Mausklicks usw. kann man mit verschiedenen Klassen handeln. Recht einfach ist es, die Widgetklasse auch von "EventMixin" erben zu lassen, und die entsprechenden Methoden, die bei Events aufgerufen werden, zu ändern.
Hiermit kann man erstmal sehen, wie die Klasse von oben "aussieht":
Code: Alles auswählen
def maintest(what):
t = tk.Tk()
a1 = [[0,1,0,1],
[1,0,1,0],
[0,1,0,1],
[1,0,1,0]]
w1 = {0 : ("white", "black"), 1:("black", "white")}
a2 = [[1,2,3],
[2,3,1],
[3,1,2]]
w2 = {1: ("blue", "white"), 2: ("red", "white"), 3:("green", "white")}
if what == "schachbrett":
r = RasterFrame(t, werte = w1 , array = a1)
elif what == "farbenfroh":
r = RasterFrame(t, werte = w2 , array = a2)
r.pack(expand = 1, fill = "both")
r.bind("<Any-Button>", eventhandler)
t.mainloop()
def eventhandler(event):
for line in event.widget.array:
print line
print "-" * 6
if __name__ == "__main__":
# eins auswählen:
# maintest("schachbrett")
maintest("farbenfroh")
Mit dem WCK kann man echt viel machen, was man, wenn überhaupt, sonst nur aufwändig aus bereits bestehenden Widgets machen kann.
Ein sehr großes Problem ist jedoch, das es erst recht wenig Doku gibt, und es so etwas schwer fällt, alle Möglichkeiten kennenzulernen.
Es kommt aber auf jeden Fall was professionelles bei raus.
LG, jj