Seite 2 von 3
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Dienstag 13. Juni 2017, 12:27
von Alfons Mittelmeyer
stefanxfg hat geschrieben:Hallo Alfons, ich denke Blackjack hat recht. Das heißt nicht, dass der GUIDesigner nicht gut ist. Du musst das eben anfangen, dass was bei dir oder einem anderen Editor automatisch passiert.
Ja stimmt, ich habe mir das unter windows noch gar nicht angeschaut. Sondern nur in Linux. Unter Windows wird anscheinend cp1252 gschgrieben. Da paßt natürlich der Kommentar nicht.
Da muß ich, wie Blackjack bereits angemerkt hatte, bei den paar Stellen, wo ich speichere, dafür sorgen, dass da in UTF-8 geschrieben wird. Und gut wäre, wenn die Script-Files auch alle utf-8 wären, obwohl das in Python3 nichts ausmacht, solange man nicht editieren will. Naja ist nur eine Kleinigkeit. Aber man merkt es eben nicht, wenn man nur in Linux gearbeitet hat.
Das mache ich gleich.
Was hat das für eine Bedeutung?
Verfasst: Dienstag 13. Juni 2017, 12:30
von Alfons Mittelmeyer
Man findet of das, was hier in der ersten Zeile steht:
Sieht aus, wie ein Linux Verzeichnis. Hat das eine Bedeutung?
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Dienstag 13. Juni 2017, 12:42
von stefanxfg
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Dienstag 13. Juni 2017, 12:46
von BlackJack
@Alfons Mittelmeyer: Dadurch weiss Linux wie es die Datei ausführen soll. Wenn man die Datei mit ``chmod`` als ausführbar kennzeichnet, dann wird das nach dem ``#!`` genommen und der Dateiname hinten angehängt und dann das ganze ausgeführt. Also wenn das in einer Datei mit dem Namen ``hallo.py`` steht, dann würde bei der Eingabe von ``./hallo.py`` in dem Verzeichnis in einer Shell ``/usr/bin/env python hallo.py`` ausgeführt. Dadurch kann man in Linux jede Textdatei als Programm ausführen und sagen welches Programm die Textdatei interpretieren soll. Das Programm muss dann nur diese erste Zeile ignorieren, entweder explizit, oder weil das ``#`` sowieso als Kennzeichen für eine Kommentarzeile behandelt wird.
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Dienstag 13. Juni 2017, 13:22
von Melewo
BlackJack hat geschrieben:@Melewo: Doch, ziemlich sicher verwechselst Du ANSI und ASCII. Denn das was Du schreibst gilt für ASCII, aber nicht für ANSI. ASCII ist von den fast allen Zeichenkodierungen die wir hier im Westen benutzen eine Untermenge. Unter anderem ist ASCII auch von ANSI und von UTF-8 und von allen ISO-8859-*-Kodierungen und vielen Windows-Codepages eine Untermenge. ANSI ist dagegen weder von UTF-8 noch von den ISO-8859-*-Kodierungen eine Untermenge. Du kannst also nicht als ANSI speichern und problemlos als UTF-8 oder ISO-8859-irgendwas öffnen. Das geht aber mit ASCII.
Gut, dann dürfte es am Editor liegen, dass der solange in einer Datei nur Zeichen entsprechend ASCII enthalten sind, diese mit ANSI anzeigt, obwohl eigentlich ASCII zutreffend sein sollte. Jedenfalls gab es noch nie Probleme damit, weil ein Parser oder Interpreter die enthaltenen Codes richtig abarbeitet und allenfalls die Ausgabe oder Speicherung in einer DB von betroffen sein könnte. Bei einer Verbindung zur Datenbank muss ich nur einen Charset setzen, bei Regex war es auch mit Umlauten so.
utf-8 codierung bei allen read und write Dateioperationen
Verfasst: Dienstag 13. Juni 2017, 14:38
von Alfons Mittelmeyer
stefanxfg hat geschrieben:Hallo Alfons, ich denke Blackjack hat recht. Das heißt nicht, dass der GUIDesigner nicht gut ist. Du musst das eben anfangen, dass was bei dir oder einem anderen Editor automatisch passiert.
Habe jetzt utf-8 Codierung bei allen read und write Dateioperationen implementiert. Ist schon auf GitHub. Damit dürften die Probleme unter Windows beseitigt sein.
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Dienstag 13. Juni 2017, 19:42
von stefanxfg
Der GuiDesigner legt ja für jeden Container eine neue Klasse an. Wenn ich nun aus dem call_code eine Funktion, sagen wir über eine Buttonbetätigung aus einer Toolbbar, anspreche, möchte ich Hauptframes ein- und ausblenden.
Aber ehrlich gesagt bin ich zu faul um jeden Frame für alle Klassen anprechbar zu machen. Wäre das dann besser über Eventbroker zu bewerkstelligen?
Zur Verdeutlichung:
Buttonbetätigung aus Toolbar => liegt in einer Datei
Input in einem Hauptframe => liegt in anderer Datei
Output in einem Hauptframe => nochaml andere Datei
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Mittwoch 14. Juni 2017, 12:28
von Alfons Mittelmeyer
stefanxfg hat geschrieben:Aber ehrlich gesagt bin ich zu faul um jeden Frame für alle Klassen anprechbar zu machen. Wäre das dann besser über Eventbroker zu bewerkstelligen?
Das wäre auch völlig falsch. Da würdest Du ja den Code verflechten. Früher gab es mal im Auto ein Kabelgewirr. Heute erfolgt alles ordentlich über gemeinsame Busse.
Da fangen wir einmal an mit einem Schalter. Der Schalter sollte eine funktionelle Einheit sein, und überall verwendet werden können. Um natürlich etwas bewirken zu können, muss er angeschlossen werden.
Das ist die GUI für den Schalter (inklusive App):
Code: Alles auswählen
# -*- coding: utf-8 -*-
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
#import DynTkInter as tk # for GuiDesigner
import switch_code
# Application definition ============================
class Application(tk.Tk):
def __init__(self,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.minsize(800, 100)
# widget definitions ===================================
self.switch = Switch(self,name='#0_switch')
self.switch.pack(fill='both', expand=1)
class Switch(tk.Frame):
def __init__(self,master,**kwargs):
tk.Frame.__init__(self,master,**kwargs)
self.myclass = 'Switch'
# widget definitions ===================================
self.canvas = Canvas(self,name='#1_canvas')
self.canvas.place(x=0,y=0)
# call Code ===================================
switch_code.switch_init(self)
class Canvas(tk.Canvas):
def __init__(self,master,**kwargs):
tk.Canvas.__init__(self,master,**kwargs)
self.config(height='100', relief='raised', highlightbackground='#e8e9ee', insertwidth='0', bg='#615e58', bd='10', selectborderwidth='0', highlightthickness='10', width='100', highlightcolor='lightgray')
self.start_width = 100
# widget definitions ===================================
coords = (30,30,110,110)
item = self.create_oval(*coords)
self.itemconfig(item,width = '0.0',fill = '#ff7431',tags = 'led')
if __name__ == '__main__':
#Application().mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
Application().mainloop()
Und das ist der Code:
switch_code.py
Code: Alles auswählen
def switch_init(self):
# for connection =========================
self.eventbroker = None
self.message = None
# ========================================
# bindings ===============================
def width_height(event):
frame_height = event.height
bd = frame_height/14
canvas_height = frame_height-4*bd
scale_factor = canvas_height/self.canvas_height_before
self.canvas_height_before = canvas_height
self.canvas.config(width = canvas_height,height = canvas_height,bd = bd,highlightthickness=bd)
self.canvas.scale('led',0,0,scale_factor,scale_factor)
def switch(event):
self.on = not self.on
self.canvas.itemconfig('led',fill = 'lightgreen' if self.on else '#ff7431')
self.canvas['relief'] = 'sunken' if self.on else'raised'
if self.eventbroker:
self.eventbroker.publish(self.message,self.on)
self.canvas_height_before = 100
self.bind('<Configure>',width_height,'+')
self.on = False
self.canvas.bind('<Button-1>',switch)
Dieser Switch Schalter ist überall verwendbar für eine horizontale Toolbar, da er sich der Höhe anpasst und außerdem nicht selber auf irgendetwas außerhalb zugreift, außer man schließt ihn an.
Hierfür sind in Zeile 4 und 5 zwei Attribute vorgesehen, über die man ihn anschließen kann.
@stefanxfg:
Frage, soll dieser Schalter in der Toolbar den Button beim Toggleframe ersetzten? Wenn Ja, dann könnte man ihn einmal anschließen.
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Mittwoch 14. Juni 2017, 13:54
von stefanxfg
Hallo Alfons, nein. Der CHeckbutton im ToggleFrame ist nur für das Einklappen der SubFrames verantwortlich. Demnach kann er sogar lokal gesetzt werden.
Der Switch soll von der Toolbar aus gesteuert werden. Demnach von einer andere Datei aus.
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Mittwoch 14. Juni 2017, 18:05
von Alfons Mittelmeyer
@stefanxfg: Die Logik mit eventbroker ist doch ganz einfach.
Zuvor habe ich nochmals mir das Modul communication angeschaut. Es ist doch überflüssig, hier noch dein Modul zu importieren. Da sollte man doch auch gleich den event broker mit reinmachen:
communication.py:
Code: Alles auswählen
import sys
def output(param):
sys.stdout.write(param+'\n')
class EventBroker():
def __init__(self):
self._dictionary_ = {}
def subscribe(self,message_id,callback):
if message_id in self._dictionary_:
output('EventBroker: callback already defined for message id: {}\nThe callback before will be overwritten'.format(message_id))
self._dictionary_[message_id] = callback
def publish(self,message_id,*args,**kwargs):
if message_id not in self._dictionary_:
output('EventBroker: no callback defined for message: {},*{},**{}'.format(message_id,args,kwargs))
else:
self._dictionary_[message_id](*args,**kwargs)
eventbroker = EventBroker()
publish = eventbroker.publish
subscribe = eventbroker.subscribe
Dann denke ich mir. dass zuerst die Eingabe angezeigt werden soll und da ist der Schalder noch auf aus. Gedrückter Schalter heißt also 'AUSGABE_EIN'. Deshalb habe ich die Message mal so genannt. DAnn habe ich gesehen, dass der Code Aufruf bei der Eingage groß geschrieben war und 'InputCode' heißt. Dann wird das wohl eine Klasse sein und für die Ausgabe wird es wohl dann 'OutpuCode' heißen?
Jedenfalls wäre das dann die Lösung:
testcode.py
Code: Alles auswählen
from communication import eventbroker, publish, subscribe
class InputCode:
def __init__(self,container):
self.container = container
subscribe('AUSGABE_EIN',self.lift_eingabe)
def lift_eingabe(self,ausgabe_ein):
if not ausgabe_ein:
self.container.lift()
class OutputCode:
def __init__(self,container):
self.container = container
subscribe('AUSGABE_EIN',self.lift_ausgabe)
def lift_ausgabe(self,ausgabe_ein):
if ausgabe_ein:
self.container.lift()
Ach so, Du hattest mir mitgeteilt, bei Dir hätte lift nicht funktioniert. Du mußt für Eingabe und Ausgabe dieselbe Grid Zelle nehmen und keine andere Zeile oder Spalte, sonst kann es natürlich nicht funktionieren.
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Mittwoch 14. Juni 2017, 18:35
von Alfons Mittelmeyer
Das wäre dann ein sichtbares Beispiel für Deine InputGUI. Natürlich toggelt da jetzt nichts.
AppInput.py
Code: Alles auswählen
# -*- coding: utf-8 -*-
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
#import DynTkInter as tk # for GuiDesigner
#============= imports call Code ===================
import testcode
# Application definition ============================
class Application(tk.Tk):
def __init__(self,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.minsize(300, 300)
# widget definitions ===================================
self.InputContentGUI = InputGUI(self,name='#0_InputContentGUI')
self.InputContentGUI.pack(expand=1, fill='both')
class InputGUI(tk.Frame):
def __init__(self,master,**kwargs):
tk.Frame.__init__(self,master,**kwargs)
self.myclass = 'InputGUI'
self.call_code = 'testcode.InputCode'
self.config(relief='solid', bd=4)
# widget definitions ===================================
self.sub_frameA = tk.Frame(self,name='#1_sub_frameA',height=40, bg='#ffffd3')
self.sub_frameB = tk.Frame(self,name='#2_sub_frameB',height=40, bg='#e4f3fc')
self.sub_frameC = tk.Frame(self,name='#3_sub_frameC',relief='sunken', width=50, bg='#cbeed8')
self.sub_frameA.pack(fill='x')
self.sub_frameB.pack(fill='x')
self.sub_frameC.pack(expand=1, fill='both', side='left')
# call Code ===================================
testcode.InputCode(self)
if __name__ == '__main__':
#Application().mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
Application().mainloop()
Für die OutputGUI hast Du kein eigenes Modul spendiert. Warum nicht, machen wir es doch schön symmetrisch.
Dann ist das:
AppOutput.py
Code: Alles auswählen
# -*- coding: utf-8 -*-
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
#import DynTkInter as tk # for GuiDesigner
#============= imports call Code ===================
import testcode
# Application definition ============================
class Application(tk.Tk):
def __init__(self,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.minsize(400, 400)
# widget definitions ===================================
self.OutputContentGUI = OutputGUI(self,name='#0_OutputContentGUI')
self.OutputContentGUI.pack(fill='both', expand=1)
class OutputGUI(tk.Frame):
def __init__(self,master,**kwargs):
tk.Frame.__init__(self,master,**kwargs)
self.myclass = 'OutputGUI'
self.call_code = 'testcode.OutputCode'
self.config(bd=4, bg='#ffeb00', relief='solid')
# call Code ===================================
testcode.OutputCode(self)
if __name__ == '__main__':
#Application().mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
Application().mainloop()
Toobar
Verfasst: Mittwoch 14. Juni 2017, 20:46
von Alfons Mittelmeyer
Der Toolbar Code ist sehr einfach:
testcode.py
Code: Alles auswählen
from communication import eventbroker, publish, subscribe
class InputCode:
def __init__(self,container):
self.container = container
subscribe('AUSGABE_EIN',self.lift_eingabe)
def lift_eingabe(self,ausgabe_ein):
if not ausgabe_ein:
self.container.lift()
class OutputCode:
def __init__(self,container):
self.container = container
subscribe('AUSGABE_EIN',self.lift_ausgabe)
def lift_ausgabe(self,ausgabe_ein):
if ausgabe_ein:
self.container.lift()
def ToolbarCode(self):
self.schalter1.connect(eventbroker,'AUSGABE_EIN',False)
Es braucht hier nur der Schalter verbunden werden.
Nachdem der led_switch fertig ist:
led_switch.py
Code: Alles auswählen
# -*- coding: utf-8 -*-
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
#import DynTkInter as tk # for GuiDesigner
# Application definition ============================
class Application(tk.Tk):
def __init__(self,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.minsize(800, 100)
# widget definitions ===================================
self.switch = Switch(self,name='#0_switch')
self.switch.pack(fill='both', expand=1)
class Switch(tk.Frame):
def __init__(self,master,**kwargs):
tk.Frame.__init__(self,master,**kwargs)
self.myclass = 'Switch'
# widget definitions ===================================
self.canvas = Canvas(self,name='#1_canvas')
self.canvas.place(x=0,y=0)
# fitting canvas to frame height and enable switching =====
self.canvas_height_before = 100
self.bind('<Configure>',self.width_height,'+')
self.on = False
self.eventbroker = None
self.message = None
self.canvas.bind('<Button-1>',self.switch)
# for connection and state at beginning ============
def connect(self,eventbroker,message,on = False):
self.on = on
self.eventbroker = eventbroker
self.message = message
self.switch_update()
def width_height(self,event):
frame_height = event.height
frame_width = event.width
frame_size = min(event.height,event.width)
bd = frame_size/14
canvas_height = frame_size-4*bd
scale_factor = canvas_height/self.canvas_height_before
self.canvas_height_before = canvas_height
self.canvas.config(width = canvas_height,height = canvas_height,bd = bd,highlightthickness=bd)
self.canvas.scale('led',0,0,scale_factor,scale_factor)
x = (frame_width - frame_size)/2
y = (frame_height - frame_size)/2
self.canvas.place(x = x, y = y)
# show and signal on status =========================
def switch_update(self):
self.canvas.itemconfig('led',fill = 'lightgreen' if self.on else '#ff7431')
self.canvas['relief'] = 'sunken' if self.on else'raised'
if self.eventbroker:
self.eventbroker.publish(self.message,self.on)
def switch(self,event):
self.on = not self.on
self.switch_update()
class Canvas(tk.Canvas):
def __init__(self,master,**kwargs):
tk.Canvas.__init__(self,master,**kwargs)
self.config(height='100', relief='raised', highlightbackground='#e8e9ee', insertwidth='0', bg='#615e58', bd='10', selectborderwidth='0', highlightthickness='10', width='100', highlightcolor='lightgray')
self.start_width = 100
# widget definitions ===================================
coords = (30,30,110,110)
item = self.create_oval(*coords)
self.itemconfig(item,width = '0.0',fill = '#ff7431',tags = 'led')
if __name__ == '__main__':
#Application().mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
Application().mainloop()
Kann er leicht in die Toolbar eingebunden werden:
AppToolbar.py
Code: Alles auswählen
# -*- coding: utf-8 -*-
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
#import DynTkInter as tk # for GuiDesigner
#============= imports baseclass ===================
import led_switch
#============= imports call Code ===================
import testcode
# Application definition ============================
class Application(tk.Tk):
def __init__(self,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.minsize(400, 100)
# widget definitions ===================================
self.ToolbarGUI = Toolbar(self,name='#0_ToolbarGUI')
self.ToolbarGUI.pack(fill='both', expand=1)
class Toolbar(tk.Frame):
def __init__(self,master,**kwargs):
tk.Frame.__init__(self,master,**kwargs)
self.myclass = 'Toolbar'
self.call_code = 'testcode.ToolbarCode'
# widget definitions ===================================
self.schalter1 = Schalter1(self,name='#1_schalter1')
self.schalter1.place(relwidth='0.2', height='-20', x='10', y='10', relheight='1')
# call Code ===================================
testcode.ToolbarCode(self)
class Schalter1(led_switch.Switch):
def __init__(self,master,**kwargs):
led_switch.Switch.__init__(self,master,**kwargs)
self.myclass = 'Schalter1'
self.baseclass = 'led_switch.Switch'
if __name__ == '__main__':
#Application().mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
Application().mainloop()
Der Schalter tut schon, man sieht es am Konsolen Output. Dann bräuchte man nur noch alles zusammenbauen
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Mittwoch 14. Juni 2017, 20:53
von Alfons Mittelmeyer
Oh, es gibt da noch ein Problem. Dieser Eventbroker ist nicht für mehre Empfänger ausgerüstet. Da müßte man ihn zuvor aufrüsten. Ich wollte ihn einfach halten und dabei vermeiden, dass etwa bei Widgets Löschen und wieder aufbauen immer mehr Callbacks entstehen. Bei meinem eigenen Eventbroker ist die destroy Methode aller Containerwidgets überschrieben, so dass bei destroy alle Message Abonnements für sie gelöscht werden. Aber das geht hier zu weit.
Entweder man bleibt bei diesem Eventbroker und nimmt einen Verteiler, der eine Message in mehrere andere umschaufelt, aber besser ist, man rüstet dieses beim Eventbroker nach.
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Mittwoch 14. Juni 2017, 21:33
von stefanxfg
Also zunächst einmal Danke. Ich habe erst einmal meinen Button im Toolbar mit einem Command ausgestattet und in dann auf Publish gesetzt. Der Rest läuft, wie du bereits geschrieben hast.
Ich glaube mich zu erinnern, dass beim Eventbroker durchaus mehrmalige Betätigung auch schon zu Fehlern geführt hatte.
Wenn er nun nicht mehrere Empfänger bedienen kann, dann kann ich nicht einfach den Button im Toolbar drücken, die Eingaben im InputGUI ausblenden und die Ausgaben im OutputGUI einblenden, weil dass dann 2 Empfänger sind. Vielleicht hast du ja doch noch eine ruhige Minute und kannst ihn mal dazu aufrüsten.
Ich würde mich freuen.
Übrigens, warum exportiert der GUIDesigner mit Leerzeichen und nicht mit Tabs?
Viele Grüße Stefan
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Mittwoch 14. Juni 2017, 21:52
von stefanxfg
Naja und jetzt geht mir ein Licht auf, was ich schon vorher falsch gemacht hatte. Ich hatte immer zur Hauptklasse gesendet und empfangen.
Also werde ich es nun richtig machen und jede einzelne Klasse mit Widget zum Sender machen. Also z.B. beim Toolbar gibt es das Fileframe, welche die Buttons "newfile" und "openfile" beinhaltet. Hierzu ein Sender und nicht aus der darüber befindlichen Klasse,welche als Container alle Untercontainer der einzelnen Toolbarleisten in sich herbergt.
Ob ich das beim Input als Empfänger genauso mache, weiß ich noch nicht. Liegt möglicherweise am Umstand, was man machen möchte.
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Mittwoch 14. Juni 2017, 22:06
von BlackJack
@stefanxfg: Eingerückt wird mit vier Leerzeichen pro Ebene. Nicht mit Tabs. Siehe den
Style Guide for Python Code.
Re: Workshop: Gui Entwicklung in tkinter
Verfasst: Mittwoch 14. Juni 2017, 22:13
von Alfons Mittelmeyer
stefanxfg hat geschrieben:Ich glaube mich zu erinnern, dass beim Eventbroker durchaus mehrmalige Betätigung auch schon zu Fehlern geführt hatte.
Mehrmaliges publish sicher nicht. Aber wenn zwei Empfänger eines subscribe auf dieselbe Message machen, dann klaut sie der zweite vom ersten. Da gibt es aber eine Konsolenausgabe dafür. Der Grund nur einen Callback zu erlauben, ist dass man bei Widget Löschen und wieder neu subscribe zu machen, keine ungüpltige callbacks mehr übrig bleiben.
stefanxfg hat geschrieben:Übrigens, warum exportiert der GUIDesigner mit Leerzeichen und nicht mit Tabs?
Damit man den Code hier in das Forum stellen kann. Statt Tabs nimmt man hier vier Leerzeichen.
stefanxfg hat geschrieben:Wenn er nun nicht mehrere Empfänger bedienen kann, dann kann ich nicht einfach den Button im Toolbar drücken, die Eingaben im InputGUI ausblenden und die Ausgaben im OutputGUI einblenden, weil dass dann 2 Empfänger sind. Vielleicht hast du ja doch noch eine ruhige Minute und kannst ihn mal dazu aufrüsten.
Ich würde mich freuen.
Viele Grüße Stefan
Schon geschehen, aber noch nicht auf GitHub
Code: Alles auswählen
import sys
def output(param):
sys.stdout.write(param+'\n')
class EventBroker():
def __init__(self):
self._dictionary_ = {}
def subscribe(self,message_id,callback_or_alias):
is_string = True
try: # python2
is_string = isinstance(callback_or_alias,basestring)
except NameError: #python 3
is_string = isinstance(callback_or_alias,str)
if is_string:
if message_id not in self._dictionary_:
self._dictionary_[message_id] = set()
self._dictionary_[message_id].add(callback_or_alias)
else:
if message_id in self._dictionary_:
output('EventBroker: callback already defined for message id: {}\nThe callback before will be overwritten'.format(message_id))
self._dictionary_[message_id] = callback_or_alias
def publish(self,message_id,*args,**kwargs):
if message_id not in self._dictionary_:
output('EventBroker: no callback defined for message: {},*{},**{}'.format(message_id,args,kwargs))
else:
callback = self._dictionary_[message_id]
if not isinstance(callback ,set):
return callback(*args,**kwargs)
for element in callback:
if element in self._dictionary_:
callback = self._dictionary_[element]
if isinstance(callback,set):
output("EventBroker: for message id '{}' is alias '{}' allowed, but no furter aliases for this alias".format(message_id,element))
else:
callback(*args,**kwargs)
eventbroker = EventBroker()
publish = eventbroker.publish
subscribe = eventbroker.subscribe
if __name__ == '__main__':
# =========================== Test ==============================
# for aliases are only strings allowed
def receiver_A():
def got(info):
output('receiver_A got info: ' + info)
subscribe('BROADCAST','BROADCAST_A')
subscribe('BROADCAST_A',got)
def receiver_B():
def got(info):
output('receiver_B got info: ' + info)
subscribe('BROADCAST','BROADCAST_B')
subscribe('BROADCAST_B',got)
receiver_A()
receiver_B()
publish('BROADCAST','NEWS')
Jetzt ist es fertig
Verfasst: Mittwoch 14. Juni 2017, 23:44
von Alfons Mittelmeyer
Nach Korrektur dieses Codes:
testcode.py
Code: Alles auswählen
from communication import eventbroker, publish, subscribe
class InputCode:
def __init__(self,container):
self.container = container
subscribe('AUSGABE_EIN','LIFT_EINGABE')
subscribe('LIFT_EINGABE',self.lift_eingabe)
def lift_eingabe(self,ausgabe_ein):
if not ausgabe_ein:
self.container.lift()
class OutputCode:
def __init__(self,container):
self.container = container
subscribe('AUSGABE_EIN','LIFT_AUSGABE')
subscribe('LIFT_AUSGABE',self.lift_ausgabe)
def lift_ausgabe(self,ausgabe_ein):
if ausgabe_ein:
self.container.lift()
def ToolbarCode(self):
self.schalter1.connect(eventbroker,'AUSGABE_EIN',False)
wurden dann bei diesem Anfangsbeispiel:
viewtopic.php?f=18&t=40677
mit dem GuiDesigner die Text Felder herausgelöscht und stattdessen Frames hineingesetzt und für diese die entsprechenden Eintragungen gemacht. Das ist dann das Resultat:
Code: Alles auswählen
# -*- coding: utf-8 -*-
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
#import DynTkInter as tk # for GuiDesigner
#============= imports baseclass ===================
import AppOutput
import AppToolbar
import AppInput
# === general grid table definition =================
def grid_general_rows(container,rows,**kwargs):
for row in range(rows):
container.rowconfigure(row,**kwargs)
def grid_general_cols(container,columns,**kwargs):
for column in range(columns):
container.columnconfigure(column,**kwargs)
# Application definition ============================
class Application(tk.Tk):
def __init__(self,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.minsize(500, 400)
# widget definitions ===================================
self.frame_guinotes = GuiNotes(self,name='#0_frame_guinotes')
self.frame_menunotes = FrameMenunotes(self,name='#1_frame_menunotes')
self.frame_toolbarnotes = FrameToolbarnotes(self,name='#2_frame_toolbarnotes')
self.label_PS = tk.Label(self,name='#3_label_PS',bd='4', anchor='w', pady='4', fg='#a90000', relief='solid', font='TkFixedFont 10 bold', text='Welches Layout soll man nehmen?\nUnd soll man einen GuiBuilder nehmen?\nWenn ja, welchen?', padx='4', justify='left')
self.frame_menunotes.pack(fill='x')
self.frame_toolbarnotes.pack(fill='x')
self.frame_guinotes.pack(expand=1, fill='both')
self.label_PS.pack(fill='x', pady=3)
class GuiNotes(tk.Frame):
def __init__(self,master,**kwargs):
tk.Frame.__init__(self,master,**kwargs)
self.myclass = 'GuiNotes'
self.config(bg='#ceff00', highlightthickness=7, highlightbackground='#a90000', highlightcolor='#a90000')
# general grid definition ==============================
grid_general_rows(self,1, minsize = 100, pad = 0, weight = 1)
grid_general_cols(self,1, minsize = 100, pad = 0, weight = 1)
# widget definitions ===================================
self.InputContentGUI = Input(self,name='#4_InputContentGUI')
self.InputContentGUI.grid(row=0, sticky='nesw')
self.OutputGUI = Output(self,name='#5_OutputGUI')
self.OutputGUI.grid(row=0, sticky='nesw')
class Input(AppInput.InputGUI):
def __init__(self,master,**kwargs):
AppInput.InputGUI.__init__(self,master,**kwargs)
self.myclass = 'Input'
self.baseclass = 'AppInput.InputGUI'
class Output(AppOutput.OutputGUI):
def __init__(self,master,**kwargs):
AppOutput.OutputGUI.__init__(self,master,**kwargs)
self.myclass = 'Output'
self.baseclass = 'AppOutput.OutputGUI'
class FrameMenunotes(tk.Frame):
def __init__(self,master,**kwargs):
tk.Frame.__init__(self,master,**kwargs)
self.config(highlightbackground='blue', highlightthickness=7, highlightcolor='blue')
# widget definitions ===================================
self.notes_menu = tk.Text(self,name='#6_notes_menu',font='TkFixedFont 12 bold', pady=8, width=1, fg='blue', padx=8, height=1)
self.notes_menu.delete(1.0, tk.END)
self.notes_menu.insert(tk.END,'Oben soll ein Menü sein')
self.notes_menu.pack(expand=1, fill='both')
class FrameToolbarnotes(tk.Frame):
def __init__(self,master,**kwargs):
tk.Frame.__init__(self,master,**kwargs)
self.config(relief='sunken', highlightbackground='#008900', highlightthickness=7, highlightcolor='#008900')
# widget definitions ===================================
self.ToolbarGUI = Toolbar(self,name='#7_ToolbarGUI')
self.ToolbarGUI.pack(expand=1, fill='both')
class Toolbar(AppToolbar.Toolbar):
def __init__(self,master,**kwargs):
AppToolbar.Toolbar.__init__(self,master,**kwargs)
self.myclass = 'Toolbar'
self.baseclass = 'AppToolbar.Toolbar'
self.config(height=60)
if __name__ == '__main__':
#Application().mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
Application().mainloop()
Lediglich eine kleine Nachpesserung war nötig. In AppToolbar.py war das Padding mittels y und height etwas zu hoch eingestellt, wodurch dann der LED Switch zu klein wurde.
Code: Alles auswählen
self.schalter1.place(relwidth='0.2', height='-10', x='10', y='5', relheight='1')
Hier war zuerst y = 10 und height = -20 und das war etwas zuviel. Wenn man einmal von meinem LED Switch absieht, war das bißchen in testcode.py der ganze zu schreibende Code.
Ist klar, dass man den ganzen generierten Code nicht händisch schreiben sollte, wenn man alles bequem und live erlebend mit dem GuiDesigner erledigen kann.
tkinter und DynTkInter
Verfasst: Donnerstag 15. Juni 2017, 00:05
von Alfons Mittelmeyer
Noch eine wichtige Anmerkung:
wenn man statt den normalen tkinter Importen das importiert
Und statt dem normalen mainloop dieses aufruft:
Code: Alles auswählen
Application().mainloop('guidesigner/Guidesigner.py') # for GuiDesigner
Dann startet der GuiDesigner mit zur Gui. Und da ist noch etwas wichtig. Wenn man das nur bei der Applikation macht und bei den anderen Modulen die normalen imports lässt, ist alles schön und funktionierend im GuiDesigner zu sehen. Bearbeiten und speichern kann man dann allerdings nur die Applikation. Denn diese ist dann in DynTkInter und für den GuiDesigner da. Das andere, obwohl sichtbar und funktionierend, nicht für den GuiDesigner existent.
Das ist dann sehr gut, wenn man nur die Applikation bearbeiten und speichern möchte, nicht aber die in Komponenten aufgeteilte Gui wieder zu einer zusammengefügt haben will.
Die Gui zusammenfügen kann man, wenn man auch für die Komponenten die Importe mit DynTkInter macht.
Eventbroker auf GitHub
Verfasst: Donnerstag 15. Juni 2017, 10:18
von Alfons Mittelmeyer
Der neue Eventbroker ist jetzt auf GitHub im Verzeichnis Utilities