Spazieren in der GUI
Verfasst: Donnerstag 13. August 2015, 00:33
Ich weiß nicht ob Ihr wisst, dass man in der GUI spazieren gehen kann. Was man dazu braucht, ist einfach nur ein tkinter Programm, wie etwa dieses: http://www.python-kurs.eu/tkinter_buttons.php
Und das muss man nur geringfügig anpassen. Das habe ich dann so gemacht:
Statt from tkinter import * habe ich geschrieben: from spazieren import *
Und dann habe ich über einen Thread manuelle Eingaben implementiert. Außerdem mußte ich die python2 print Anweisung auf python3 anpassen. Und was man dazu noch braucht, ist das Modul spazieren:
Wenn man nun das erste Modul startet, dann startet es ganz normal. Aber jetzt kann man in die Konsole etwas eingeben. Und das wäre der Befehl: ls()
Dann sieht man einen Pfeil auf einen Punkt zeigend. Das ist die root. Und dann sieht man einen Frame. Zu dem Frame kan man dann hingehen:
goto('Frame')
ls()
Der Zeiger steht jetzt auf dem Frame. Jetzt kann man in den Frame hineingehen:
goIn()
ls()
Der Zeiger steht wieder auf einem Punkt. Das ist der Frame von innen. Man sieht dort zwei Buttons. Zu einem von diesem kann man ja auch mal hingehen:
goto('Button')
ls()
Wenn man bei gleichem Namen, keine Indexangabe macht, wird der letzte ausgewählt. Doch welcher ist das? Kann man testen:
print(this()['text'])
this() ist das ausgewählte Element. Man kann nun mal die Farbe ändern:
this()['fg'] = '#005000'
Dann wird er grün. Man kann auch auf den Button mit der Maus klicken und natürlich funktioniert dieser noch. Man kann auch einen Button hinzumachen:
Button('MyButton',text = "Mein Knopf).pack()
ls()
Statt dem Master gibt man hier einen Namen an. Oder wenn man den Namen wegläßt, heißt er eben auch 'Button'. Wenn mehrere widgets mit gleichem Namen da sind, dann wählt man sie mit Index:
goto('Button',0)
ls()
Wenn der Button stört, kann man ihn auch wegmachen: this().destroy()
Aus Sicherheitsgründen befindet man sich nach destroy aber wieder in der Root. Man könnte eine veränderte GUI auch abspeichern. Aber da habe ich zur Zeit ein Format, das zwar auch mit dem Modul spazieren geht, aber nicht mit normalem tkinter. Abgespeichert sieht es dann so aus:
So wollen es aber wohl die meisten nicht haben. Habt ihr einen Vorschlag, wie man das abspeichern könnte, damit es normal tkinter kompatibel ist?
Und das muss man nur geringfügig anpassen. Das habe ich dann so gemacht:
Code: Alles auswählen
from spazieren import *
import threading
class MyThread(threading.Thread):
def run(self):
while True:
a = input("> ")
try: eval(compile(a,'<string>', 'exec'))
except: print("Error:",a)
mythread = MyThread()
mythread.daemon = True
mythread.start()
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.button = Button(frame,
text="QUIT", fg="red",
command=frame.quit)
self.button.pack(side=LEFT)
self.slogan = Button(frame,
text="Hello",
command=self.write_slogan)
self.slogan.pack(side=LEFT)
def write_slogan(self):
print("Tkinter is easy to use!")
root = Tk()
app = App(root)
root.mainloop()
Und dann habe ich über einen Thread manuelle Eingaben implementiert. Außerdem mußte ich die python2 print Anweisung auf python3 anpassen. Und was man dazu noch braucht, ist das Modul spazieren:
Code: Alles auswählen
import tkinter as StatTkInter
from tkinter import *
from copy import copy
class Create_Selection:
def __init__(self,widget=None,container = None):
if widget == None: # only for initialisation
self._widget = None
self._container = None
else:
self._widget = widget
if container != None and container.isContainer: self._container = container
else:
master = widget.master
if master == None: self._container = widget
else: self._container = master
def selectContainer(self): self._widget = self._container
def selectWidget(self,widget):
self._widget = widget
master = widget.master
if master == None: self._container = widget
else: self._container = master
def selectOut(self):
self.selectWidget(self._container)
def selectIn(self):
if self._widget.isContainer: self._container = self._widget
_Selection=Create_Selection()
_Application=Create_Selection()
def this():
global _Selection
return _Selection._widget
def ls():
if _Selection._container is _Selection._widget:
print("=> "+"\\.")
else:
print(" "+"\\.")
for n,e in _Selection._container.Dictionary.elements.items():
isNameSelected = False
number = len(e)
if _Selection._widget in e:
print("=>",end=" ")
isNameSelected = True
else:
print(" ",end=" ")
if number == 1: print (n)
else:
if isNameSelected:
i = 0
while i < number and not e[i] is _Selection._widget: i = i+1
print (n + " : " + str(i+1) + " of " + str(number) + " => index ["+str(i)+"]")
else: print (n + " : " + str(number))
def goto(name,nr=-1):
widget = _Selection._container.Dictionary.getEntry(name,nr)
if widget != None:
_Selection._widget = widget
def widget(name,nr=-1):
return _Selection._container.Dictionary.getEntry(name,nr)
def goIn(): _Selection.selectIn()
def goOut(): _Selection.selectOut()
def goCont(): _Selection.selectContainer()
def goApp():
global _Selection
_Selection = copy(_Application)
def _getMasterAndNameAndSelect(name,altname):
if type(name) == str: return _Selection._container,name,True
elif type(name) == tuple: return name[0],name[1],False
else: return name,altname,False
def _initGuiElement(kwargs,tkClass,element,myname,altname,isContainer=False):
element.tkClass = tkClass
master,myname,select = _getMasterAndNameAndSelect(myname,altname)
element.tkClass.__init__(element,master,**kwargs)
element.master = master
element.isContainer = isContainer
GuiElement.__init__(element,myname,select)
class GuiDictionary:
def __init__(self): self.elements = {}
def setElement(self,name,thisone):
if not name in self.elements: self.elements[name] = [thisone]
else: self.elements[name].append(thisone)
def getEntry(self,name,nr=-1):
if name in self.elements: return self.elements[name][nr]
return None
class GuiElement:
def __init__(self,name="nn",select=True):
if select: _Selection._widget = self
if self.master != None: self.master.Dictionary.setElement(name,self)
if self.isContainer:
self.Dictionary = GuiDictionary()
def destroy(self):
self.tkClass.destroy(self)
goApp()
class Tk(GuiElement,StatTkInter.Tk):
def __init__(self,myname="Application",**kwargs):
global _Application
global _Selection
_initGuiElement(kwargs,StatTkInter.Tk,self,myname,"Application",True)
_Application = Create_Selection(self,self)
_Selection = copy(_Application)
class Message(GuiElement,StatTkInter.Message):
def __init__(self,myname="Message",**kwargs):
_initGuiElement(kwargs,StatTkInter.Message,self,myname,"Message")
class Label(GuiElement,StatTkInter.Label):
def __init__(self,myname="Label",**kwargs):
_initGuiElement(kwargs,StatTkInter.Label,self,myname,"Label")
class Button(GuiElement,StatTkInter.Button):
def __init__(self,myname="Button",**kwargs):
_initGuiElement(kwargs,StatTkInter.Button,self,myname,"Button")
class Radiobutton(GuiElement,StatTkInter.Radiobutton):
def __init__(self,myname="Radiobutton",**kwargs):
_initGuiElement(kwargs,StatTkInter.Radiobutton,self,myname,"Radiobutton")
class Checkbutton(GuiElement,StatTkInter.Checkbutton):
def __init__(self,myname="Checkbutton",**kwargs):
_initGuiElement(kwargs,StatTkInter.Checkbutton,self,myname,"Checkbutton")
class Entry(GuiElement,StatTkInter.Entry):
def __init__(self,myname="Entry",**kwargs):
_initGuiElement(kwargs,StatTkInter.Entry,self,myname,"Entry")
class Text(GuiElement,StatTkInter.Text):
def __init__(self,myname="Text",**kwargs):
_initGuiElement(kwargs,StatTkInter.Text,self,myname,"Text")
class Listbox(GuiElement,StatTkInter.Listbox):
def __init__(self,myname="Listbox",**kwargs):
_initGuiElement(kwargs,StatTkInter.Listbox,self,myname,"Listbox")
class Spinbox(GuiElement,StatTkInter.Spinbox):
def __init__(self,myname="Spinbox",**kwargs):
_initGuiElement(kwargs,StatTkInter.Spinbox,self,myname,"Spinbox")
class Frame(GuiElement,StatTkInter.Frame):
def __init__(self,myname="Frame",**kwargs):
_initGuiElement(kwargs,StatTkInter.Frame,self,myname,"Frame",True)
class LabelFrame(GuiElement,StatTkInter.LabelFrame):
def __init__(self,myname="LabelFrame",**kwargs):
_initGuiElement(kwargs,StatTkInter.LabelFrame,self,myname,"LabelFrame",True)
class Scale(GuiElement,StatTkInter.Scale):
def __init__(self,myname="Scale",**kwargs):
self.tkClass = StatTkInter.Scale
_initGuiElement(kwargs,StatTkInter.Scale,self,myname,"Scale")
class PanedWindow(GuiElement,StatTkInter.PanedWindow):
def __init__(self,myname="PanedWindow",**kwargs):
_initGuiElement(kwargs,StatTkInter.PanedWindow,self,myname,"PanedWindow")
class Canvas(GuiElement,StatTkInter.Canvas):
def __init__(self,myname="Canvas",**kwargs):
_initGuiElement(kwargs,StatTkInter.Canvas,self,myname,"Canvas",True)
class Menubutton(GuiElement,StatTkInter.Menubutton):
def __init__(self,myname="Menubutton",**kwargs):
_initGuiElement(kwargs,StatTkInter.Menubutton,self,myname,"Menubutton",True)
class Menu(GuiElement,StatTkInter.Menu):
def __init__(self,myname="Menu",**kwargs):
_initGuiElement(kwargs,StatTkInter.Menu,self,myname,"Menu")
class Scrollbar(GuiElement,StatTkInter.Scrollbar):
def __init__(self,myname="Scrollbar",**kwargs):
_initGuiElement(kwargs,StatTkInter.Scrollbar,self,myname,"Scrollbar")
Dann sieht man einen Pfeil auf einen Punkt zeigend. Das ist die root. Und dann sieht man einen Frame. Zu dem Frame kan man dann hingehen:
goto('Frame')
ls()
Der Zeiger steht jetzt auf dem Frame. Jetzt kann man in den Frame hineingehen:
goIn()
ls()
Der Zeiger steht wieder auf einem Punkt. Das ist der Frame von innen. Man sieht dort zwei Buttons. Zu einem von diesem kann man ja auch mal hingehen:
goto('Button')
ls()
Wenn man bei gleichem Namen, keine Indexangabe macht, wird der letzte ausgewählt. Doch welcher ist das? Kann man testen:
print(this()['text'])
this() ist das ausgewählte Element. Man kann nun mal die Farbe ändern:
this()['fg'] = '#005000'
Dann wird er grün. Man kann auch auf den Button mit der Maus klicken und natürlich funktioniert dieser noch. Man kann auch einen Button hinzumachen:
Button('MyButton',text = "Mein Knopf).pack()
ls()
Statt dem Master gibt man hier einen Namen an. Oder wenn man den Namen wegläßt, heißt er eben auch 'Button'. Wenn mehrere widgets mit gleichem Namen da sind, dann wählt man sie mit Index:
goto('Button',0)
ls()
Wenn der Button stört, kann man ihn auch wegmachen: this().destroy()
Aus Sicherheitsgründen befindet man sich nach destroy aber wieder in der Root. Man könnte eine veränderte GUI auch abspeichern. Aber da habe ich zur Zeit ein Format, das zwar auch mit dem Modul spazieren geht, aber nicht mit normalem tkinter. Abgespeichert sieht es dann so aus:
Code: Alles auswählen
from spazieren import *
Frame('Frame')
goIn()
Button('Button',text="""QUIT""",fg='red')
Button('Button',text="""Hello""")
widget('Button',0).pack(side='left')
widget('Button',1).pack(side='left')
goOut()
widget('Frame').pack()