L'autre jour
J'ai écrit un wrapper Tkinter comme IPython Notebook [Python]
J'ai écrit ça. Cette fois, comme je l'ai mentionné, je vais présenter la même chose portée sur Gtk. Veuillez vous référer à l'article ci-dessus pour savoir comment appeler. Je ne vois pas vraiment les tutoriels japonais de Gtk, donc j'espère que vous comprenez qu'il est étonnamment facile à utiliser.
Cette fois, il est entièrement compatible avec Python3. J'ai apporté la fonction d'impression de \ _ \ _ future \ _ \ _ au début du code, mais je n'en ai pas besoin lorsque je l'appelle en tant que module. Même dans le test, cela ne fonctionne qu'avec 3 systèmes.
Le dernier changement majeur par rapport au notebook IPython est le troisième argument lors de l'appel de la barre d'échelle. Jusqu'à présent, la taille du pas était définie par vous-même (exemple: x = (0., 10., 0.5) crée une barre d'échelle avec 0.5 pas de 0.0 à 10.0), mais en fonction de Gtk Il y a quelque chose appelé set_digits, et nous l'utilisons. En d'autres termes, cette partie a été modifiée en un format qui spécifie le nombre de chiffres après la virgule décimale à prendre. Bien sûr, cette partie peut être omise comme précédemment, et si une valeur entière est donnée comme premier argument, elle peut être spécifiée comme un entier, et si une fraction est donnée à cela, elle devrait prendre jusqu'à 2 décimales. Il y a. Concernant l'arrondi des valeurs ici, vous pouvez voir que vous pouvez le régler plus finement en lisant la référence, mais je ne l'ai pas falsifié cette fois.
Par conséquent, le contenu de l'argument mot-clé donné à interactive est converti en un widget comme suit.
Keyword argument | Widget |
`True` or `False` | SwitchWiget |
`value` or `(min,max)` or `(min,max,digit)` if integers are passed | IntSliderWidget |
`value` or `(min,max)` or `(min,max,digit)` if floats are passed | FloatSliderWidget |
`('orange','apple')` or `{'one':1,'two':2}` | ComboBoxWidget |
J'ai pris une capture d'écran de la façon dont je l'ai déplacé, donc je vais en présenter quelques-uns. Après tout, il est bien plus beau que Tk. Je suis également heureux que le thème Gtk ait été appliqué.
Lorsqu'il est affiché dans Gtk à l'aide de tk_wrapper,
Le widget est généré comme ceci.
Lorsque vous déplacez le curseur ou activez et désactivez le commutateur, le contenu de la fonction est exécuté. (Maintenant, affichez simplement le contenu de la variable) En appuyant sur le bouton, vous pouvez exécuter une autre fonction à ce moment, et vous pouvez vous référer à la valeur de la variable à ce moment.
Enfin, exposez tout le code. Je suis désolé qu'il y ait encore quelques commentaires, mais j'espère que cela aide.
gtk_wrapper.py
#! /usr/bin/env python
# -*- coding:utf-8 -*-
#
# written by ssh0, October 2014.
from __future__ import print_function
__doc__ = '''IPython-like Gtk wrapper class.
You can create Scalebar, Switch, ComboBox via simple interface.
usage example:
>>> from gtk_wrapper import interactive
>>> def f(a,b=20):
... return a + b
...
>>> w = interactive(f, a=(0, 20), b=20)
(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}
'''
from gi.repository import Gtk
import inspect
class interactive(Gtk.Window):
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))
Gtk.Window.__init__(self, title=title)
hbox = Gtk.Box(spacing=6)
self.add(hbox)
self.listbox = Gtk.ListBox()
self.listbox.set_selection_mode(Gtk.SelectionMode.NONE)
hbox.pack_start(self.listbox, True, True, 0)
self.status = Gtk.Label()
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.combobox_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.switch(kw, arg)
elif arg_type == str:
self.label(arg)
self.kwargs[kw] = arg
elif arg_type == dict:
self.combobox_dict(kw, arg)
else:
raise TypeError
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
hbox.pack_start(self.status, True, True, 10)
self.status.set_text(str(self.kwargs))
self.listbox.add(row)
def display(self):
self.connect("delete-event", Gtk.main_quit)
self.show_all()
Gtk.main()
def status_change(self):
self.status.set_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, kw, new_value):
# if argument is already given in func, use it for a default one
if kw in self.kwdefaults:
self.kwargs[kw] = self.kwdefaults[kw]
return self.kwdefaults[kw]
else:
self.kwargs[kw] = new_value
return 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 : Combobox""")
return argtype
def add_label(self, kw, parent):
label = Gtk.Label(kw, xalign=0)
parent.pack_start(label, True, True, 10)
def scale_bar(self, kw, arg, argtype):
def scale_interact(scale, _type):
if _type == int:
self.kwargs[kw] = int(scale.get_value())
else:
self.kwargs[kw] = float(scale.get_value())
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:
scale_digit = 0
elif argtype == float:
scale_digit = 2
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_digit = arg[2]
elif len_arg == 2:
scale_from = arg[0]
scale_to = arg[1]
else:
scale_from = arg[0] * (-1)
scale_to = arg[0] * 3
# create scale widget in listbox
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
self.add_label(kw, hbox)
scale = Gtk.Scale()
scale.set_range(scale_from, scale_to)
scale.set_digits(scale_digit)
scale.set_value(self.set_value(kw, arg[0]))
scale.set_draw_value(True)
scale.connect('value-changed', scale_interact, argtype)
hbox.pack_start(scale, True, True, 10)
self.listbox.add(row)
def switch(self, kw, arg):
def on_switch_activated(switch, gparam):
self.kwargs[kw] = switch.get_active()
self.status_change()
# create switch widget in listbox
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
self.add_label(kw, hbox)
switch = Gtk.Switch()
switch.connect("notify::active", on_switch_activated)
switch.set_active(self.set_value(kw, arg))
hbox.pack_start(switch, False, False, 10)
self.listbox.add(row)
def combobox_str(self, kw, arg):
def on_combo_changed(combo):
tree_iter = combo.get_active()
if tree_iter is not None:
self.kwargs[kw] = arg[tree_iter]
self.status_change()
argstore = Gtk.ListStore(str)
for a in arg:
argstore.append([a])
# create combobox widget in listbox
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
self.add_label(kw, hbox)
combo = Gtk.ComboBox.new_with_model(argstore)
combo.connect("changed", on_combo_changed)
renderer_text = Gtk.CellRendererText()
combo.pack_start(renderer_text, True)
combo.add_attribute(renderer_text, "text", 0)
combo.set_active(arg.index(self.set_value(kw, arg)))
hbox.pack_start(combo, False, False, True)
self.listbox.add(row)
def combobox_dict(self, kw, arg):
def on_combo_changed(combo):
tree_iter = combo.get_active()
if tree_iter is not None:
self.kwargs[kw] = values[tree_iter]
self.status_change()
argstore = Gtk.ListStore(str)
keys = list(arg.keys())
values = list(arg.values())
for a in keys:
argstore.append([a])
# create combobox widget in listbox
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
self.add_label(kw, hbox)
combo = Gtk.ComboBox.new_with_model(argstore)
combo.connect("changed", on_combo_changed)
renderer_text = Gtk.CellRendererText()
combo.pack_start(renderer_text, True)
combo.add_attribute(renderer_text, "text", 0)
combo.set_active(values.index(self.set_value(kw, arg)))
hbox.pack_start(combo, False, False, True)
self.listbox.add(row)
if __name__ == '__main__':
from gi.repository import Gtk
def f(x=12, y=20, z='III', o=False, i=20):
print("x: {0}, y: {1}, z: {2}, o: {3}, i: {4}".format(x, y, z, o, i))
def b1(button):
print(w.kwargs)
buttons = [('b1', b1), ('exit', Gtk.main_quit)]
w = interactive(f, x=10, y=(1., 100.),
z=("ZZZ", "III", "foo", "bar"),
i={'0': 0, '10': 10, '20': 20},
o=True
)
row = Gtk.ListBoxRow()
hbox = Gtk.HBox(spacing=10)
row.add(hbox)
for b in buttons:
button = Gtk.Button(b[0])
button.connect('clicked', b[1])
hbox.pack_start(button, True, True, 0)
w.listbox.add(row)
w.display()
Je voulais utiliser Gtk pour l'essentiel, c'est donc un paragraphe. Cependant, la fonction est toujours exécutée autant de fois que le nombre de glissières (c'est-à-dire que ce n'est pas un problème uniquement pour Tk), et l'ordre d'affichage est également dans le désordre. Les points à améliorer à l'avenir sont les points ci-dessus et l'amélioration de la barre de menus. Je pense que vous pouvez facilement lire les fichiers. Qt est en attente car je n'ai pas beaucoup de chance de l'utiliser personnellement (Ubuntu ...).
Recommended Posts