Wie der Titel schon sagt, habe ich einen Wrapper für Tkinter geschrieben, der die GUI wie das interaktive Widget von IPython Notebook einfach aufrufen kann, also werde ich ihn aufgeben. Ich mache mir Sorgen, weil es sich etwas unerwartet verhält, deshalb möchte ich Sie um Ihren Unterricht bitten. Abgesehen davon denke ich, dass es viel einfacher zu bedienen ist, also denke ich darüber nach, es das nächste Mal auf Qt oder Gtk zu portieren.
Nachtrag: Portiert auf Gtk (Link)
Ich habe in diesen Tagen häufig IPython-Notebooks verwendet, aber wenn ich darüber nachdenke, welche Funktionen mich interessieren, kann ich Variablen interaktiv ändern und Funktionen wie Interaktiv und Interaktiv ausführen. Ich denke, es hängt weitgehend von der Existenz ab. Der Rest erstellt Folien. Ich habe meinen eigenen Wrapper in Tkinter geschrieben, war aber beeindruckt von der Benutzerfreundlichkeit des interaktiven Widgets in IPython Notebook. Daher habe ich beschlossen, etwas zu erstellen, das das Tk-Widget auf ähnliche Weise anzeigen kann. .. Daher, wie man verwendet
Es ist fast das gleiche wie das in. Aufgrund der Benutzerfreundlichkeit des Tkinter-Moduls wurde die Dropdown-Liste in ein Optionsfeld geändert. Einige Leute erstellen jedoch Dropdowns mit Tk,
Es scheint, dass es nichts gibt, was Sie nicht tun können, wenn Sie etwas einbauen, aber diesmal habe ich es aufgegeben. (Ich werde Gtk als Haupt verwenden ...)
Der aufzurufende Typ ist der gleiche wie [Interact verwenden] Interact, wie bereits erwähnt. Es ist als interaktive Klasse gruppiert. Wenn es aus einem Skript aufgerufen wird, muss w.display () für die Anzeige ausgeführt werden.
>>> from tk_wrapper import interactive
>>> def f(a,b=20):
... return a + b
...
>>> w = interactive(f, a=(0, 20, 2), b=20)
(in console, tk widget appear here)
(you can add buttons and label here manually)
(then, you should add the next line)
>>> w.display()
(and you can get the result for f(a,b) by)
>>> w.result
32
(or get the arguments with a dictionary)
>>> w.kwargs
{'a':8, 'b':24}
Außerdem tritt in der ursprünglichen Startseite beim Angeben von Argumenten mit interaktiv ein Fehler auf, wenn nicht dieselben Argumente wie die Argumente der zu verknüpfenden Funktion f enthalten sind. Sie müssen eine feste Klasse wie c = fixed (10) für die Argumente angeben, die Sie nicht ändern möchten. Da es diesmal schwierig war, sie zu implementieren, und ich nicht viel Gelegenheit hatte, sie zu verwenden, kann sie mit diesem Wert ausgeführt werden, wenn der Standardwert im Argument der Funktion f festgelegt ist, die mit einer Variablen verknüpft ist, die nicht durch Interactive angegeben wurde Ja (wenn Sie es nicht angeben, wird natürlich ein Tippfehler mit der Meldung "Es gibt nicht genügend Argumente" angezeigt).
Es ist lang (obwohl es viel einfacher als das Original ist), aber bitte schauen Sie, wenn Sie möchten. Es wurde bestätigt, dass es mit Python 2.7.6 funktioniert. Bitte versuchen Sie es. Wenn Sie in Python3.4.0 "Tkinter" in "tkinter" ändern, machen Sie die print-Anweisung zu einer Funktionsnotation und nehmen Sie den Wörterbuchwert im 3. System heraus
>>> a = {"d": 1, "c":4, "b":5}
>>> a.values()
dict_values([4, 5, 1])
Weil es so wird
>>> list(a.values())
[4, 5, 1]
Ich konnte es einfach ausführen, indem ich den Teil von arg.value () (Zeilen 97, 116) durch list (arg.value ()) ersetzte, wie in gezeigt.
tk_wrapper.py
#! /usr/bin/env python
# -*- coding:utf-8 -*-
#
# written by ssh0, October 2014.
__doc__ = '''IPython-like Tkinter wrapper class.
You can create Scalebar, Checkbutton, Radiobutton via simple interface.
usage example:
>>> from tk_wrapper import interactive
>>> def f(a,b=20):
... return a + b
...
>>> w = interactive(f, a=(0, 20, 2), b=20)
(in console, tk widget appear here)
(you can add buttons and label here manually)
(then, you should add the next line)
>>> w.display()
(and you can get the result for f(a,b) by)
>>> w.result
32
(or get the arguments with a dictionary)
>>> w.kwargs
{'a':8, 'b':24}
'''
import Tkinter
import inspect
class interactive(object):
def __init__(self, func, title='title', **kwargs):
self.__doc__ = __doc__
self.func = func
self.kwargs = dict()
args, varargs, keywords, defaults = inspect.getargspec(self.func)
d = []
for default in defaults:
d.append(default)
self.kwdefaults = dict(zip(args[len(args)-len(defaults):], d))
self.root = Tkinter.Tk()
self.root.title(title)
self.f = Tkinter.Frame(self.root)
for kw, arg in kwargs.items():
kw = str(kw)
arg_type = type(arg)
if arg_type == tuple:
# type check for elements in tuple
argtype = self.type_check(arg)
if argtype == str:
self.radiobuttons_str(kw, arg)
else:
self.scale_bar(kw, arg, argtype)
elif arg_type == int or arg_type == float:
self.scale_bar(kw, [arg], arg_type)
elif arg_type == bool:
self.checkbutton(kw, arg)
elif arg_type == str:
self.label(arg)
self.kwargs[kw] = arg
elif arg_type == dict:
self.radiobuttons_dict(kw, arg)
else:
raise TypeError
self.f.pack()
self.status = Tkinter.Label(self.root, text=str(self.kwargs))
self.status.pack()
def display(self):
self.root.mainloop()
def status_change(self):
self.status.config(text=str(self.kwargs))
self.kwargs_for_function = self.kwdefaults
for k, v in self.kwargs.items():
self.kwargs_for_function[k] = v
self.result = self.func(**self.kwargs_for_function)
def set_value(self, var, kw, new_value):
# if argument is already given in func, use it for a default one
if kw in self.kwdefaults:
var.set(self.kwdefaults[kw])
self.kwargs[kw] = self.kwdefaults[kw]
else:
var.set(new_value)
self.kwargs[kw] = new_value
def type_check(self, arg):
argtype = type(arg[0])
if not all([type(a) == argtype for a in arg]):
raise TypeError("""types in a tuple must be the same.
int or float: Scalebar
str : Radiobuttons""")
return argtype
def scale_bar(self, kw, arg, argtype):
def scale_interact(new):
self.kwargs[kw] = var.get()
self.status_change()
# length check for tuple
len_arg = len(arg)
if len_arg > 3 or len_arg == 0:
raise IndexError("tuple must be 1 or 2 or 3 element(s)")
if argtype == int:
var = Tkinter.IntVar()
scale_resolution = 1
elif argtype == float:
var = Tkinter.DoubleVar()
scale_resolution = 0.1
else:
raise TypeError("arg must be int or float")
# set the values
if len_arg == 3:
scale_from = arg[0]
scale_to = arg[1]
scale_resolution = arg[2]
elif len_arg == 2:
scale_from = arg[0]
scale_to = arg[1]
else:
scale_from = arg[0]*(-1)
scale_to = arg[0]*2
self.set_value(var, kw, arg[0])
# create scale widget in frame
scale = Tkinter.Scale(self.f, label=kw, from_=scale_from, to=scale_to,
resolution=scale_resolution, variable=var,
orient='h', width=10, length=200,
command=scale_interact)
scale.pack()
def checkbutton(self, kw, arg):
def check_interact():
self.kwargs[kw] = var.get()
self.status_change()
var = Tkinter.BooleanVar()
self.set_value(var, kw, arg)
checkbutton = Tkinter.Checkbutton(self.f, text=kw, variable=var,
command=check_interact)
checkbutton.pack()
def radiobuttons_str(self, kw, arg):
def select():
self.kwargs[kw] = var.get()
self.status_change()
var = Tkinter.StringVar()
label = Tkinter.Label(self.f, text='select one for '+kw)
label.pack()
self.set_value(var, kw, arg[0])
for x in arg:
R = Tkinter.Radiobutton(self.f, text=x, variable=var,
value=x, command=select)
R.pack()
def radiobuttons_dict(self, kw, arg):
def select():
self.kwargs[kw] = var.get()
self.status_change()
vtype = self.type_check(arg.values())
if vtype == str:
var = Tkinter.StringVar()
elif vtype == int:
var = Tkinter.IntVar()
elif vtype == float:
var = Tkinter.DoubleVar()
else:
raise TypeError("arg must be int or float or str.")
label = Tkinter.Label(self.f, text='select one for '+kw)
label.pack()
self.set_value(var, kw, arg.values()[0])
for k, d in arg.items():
R = Tkinter.Radiobutton(self.f, text=k, variable=var,
value=d, command=select)
R.pack()
if __name__ == '__main__':
import sys
import Tkinter
def f(x, y, z, o=True, i=0):
print x, y, z, o, i
def b1():
print w.kwargs
buttons = [('b1', b1), ('exit', sys.exit)]
w = interactive(f, x=(0, 10), y=(1, 100, 10),
z=("ZZZ", "III", "foo", "bar"),
i={'0':0, '10':10, '20':20},
o=True
)
for button in buttons:
button = Tkinter.Button(w.root, text=button[0], command=button[1])
button.pack()
w.display()
Das Problem ist, dass, wie Sie sehen können, die Reihenfolge, in der die Variablen angezeigt werden, nicht in der richtigen Reihenfolge ist. Ich denke, das liegt an der Tatsache, dass im Wörterbuchformat darauf verwiesen wird, aber ich weiß nicht, wie ich es lösen soll, also lasse ich es vorerst so, wie es ist. Hier möchte ich etwas dagegen tun. Vielleicht können Sie Ordered Dict verwenden.
Wie Sie aus dem GIF-Bild und dem obigen Bild sehen können, wurde der Inhalt der Funktion f mit der Anzahl der Argumente ausgeführt, die zu Beginn in der Skalierungsleiste angegeben wurden. Möglicherweise ist dies die Skalenspezifikation von Tkinter, und der Wert wird in der Phase der Anzeige festgelegt. Selbst wenn ich scale_change in der Zeile unmittelbar vor self.root.mainloop () der Funktionsanzeige aktiviert habe, hat es nicht funktioniert. Wenn beim Portieren auf Gtk dasselbe Problem auftritt, kann die Ursache unterschiedlich sein. Daher sollte die referenzierte Funktion, wie beim IPython Notebook, eine leichte Funktion (oder eine vollständig Dummy-Funktion) sein, und ich bin der Meinung, dass es stabiler ist, schwere Berechnungen durchzuführen, wenn die Taste gedrückt wird.
Die Zukunftsaussichten möchte ich vorerst auf Gtk ausweiten. In diesem Fall möchte ich Dropdowns, Registerkarten und Fortschrittsbalken einbinden.
Recommended Posts