Ich habe einen IPython Notebook-ähnlichen Gtk-Wrapper geschrieben [Python]

Neulich

Ich habe einen Tkinter-Wrapper wie IPython Notebook [Python] geschrieben

Das habe ich geschrieben. Dieses Mal werde ich, wie bereits erwähnt, dasselbe vorstellen, das auf Gtk portiert wurde. Informationen zum Anrufen finden Sie im obigen Artikel. Ich sehe die japanischen Tutorials von Gtk nicht wirklich, daher hoffe ich, dass Sie verstehen, dass die Verwendung überraschend einfach ist.

gtk_wrapper.png

Spezifikation

Dieses Mal ist es vollständig kompatibel mit Python3. Ich habe die print_function aus \ _ \ _ future \ _ \ _ am Anfang des Codes gebracht, aber ich brauche sie nicht, wenn ich sie als Modul aufrufe. Selbst im Test funktioniert es nur mit 3 Systemen.

Die letzte wichtige Änderung gegenüber dem IPython Notebook ist das dritte Argument beim Aufrufen der Skalierungsleiste. In der Vergangenheit war es eine Form, die Schrittgröße selbst festzulegen (Beispiel: x = (0., 10., 0.5) erstellt einen Skalierungsbalken in Schritten von 0,5 von 0,0 bis 10,0), jedoch in Abhängigkeit von Gtk Es gibt so etwas wie set_digits, und wir verwenden dies. Mit anderen Worten, dieser Teil wurde in ein Format geändert, das angibt, wie viele Stellen nach dem Dezimalpunkt verwendet werden sollen. Natürlich kann dieser Teil wie zuvor weggelassen werden, und wenn ein ganzzahliger Wert als erstes Argument angegeben wird, kann er als Ganzzahl angegeben werden, und wenn ein Bruchteil angegeben wird, sollte er bis zu 2 Stellen dauern. Es gibt. In Bezug auf die Rundung der Werte hier können Sie sehen, dass sie durch Lesen der Referenz feiner eingestellt wird, aber ich habe sie diesmal nicht manipuliert.

Daher wird der Inhalt des Schlüsselwortarguments für interaktiv wie folgt in ein Widget konvertiert.

Keyword argumentWidget
`True` or `False`SwitchWiget
`value` or `(min,max)` or `(min,max,digit)` if integers are passedIntSliderWidget
`value` or `(min,max)` or `(min,max,digit)` if floats are passedFloatSliderWidget
`('orange','apple')` or `{'one':1,'two':2}`ComboBoxWidget

Benutzerfreundlichkeit

Ich habe einen Screenshot davon gemacht, wie ich ihn tatsächlich verschoben habe, daher werde ich einige vorstellen. Immerhin wird es viel schöner angezeigt als Tk. Ich bin auch froh, dass das Gtk-Thema angewendet wurde.

Bei Anzeige in Gtk mit tk_wrapper

Selection_014.png

Das Widget wird so generiert.

Wenn Sie den Schieberegler bewegen oder den Schalter ein- und ausschalten, wird der Inhalt der Funktion ausgeführt. (Zeigen Sie jetzt nur den Inhalt der Variablen an.) Durch Drücken der Taste können Sie zu diesem Zeitpunkt eine andere Funktion ausführen und sich auf den Wert der Variablen zu diesem Zeitpunkt beziehen.

Selection_015.png

Ganzer Code

Stellen Sie schließlich den gesamten Code bereit. Es tut mir leid, dass es noch wenige Kommentare gibt, aber ich hoffe, es hilft.

gist

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()

Herausforderungen und Perspektiven

Ich wollte hauptsächlich Gtk verwenden, daher ist dies ein Absatz. Die Funktion wird jedoch immer noch so oft ausgeführt wie die Anzahl der Schieberegler (das heißt, dies ist nicht nur für Tk ein Problem), und die Anzeigereihenfolge ist ebenfalls nicht in Ordnung. Die Punkte, die in Zukunft verbessert werden sollen, sind die oben genannten Punkte und die Verbesserung der Menüleiste. Ich denke, Sie können Dateien leicht lesen. Qt ist in der Warteschleife, weil ich nicht viel Gelegenheit habe, es persönlich zu verwenden (Ubuntu ...).

Recommended Posts

Ich habe einen IPython Notebook-ähnlichen Gtk-Wrapper geschrieben [Python]
Ich habe einen IPython Notebook-ähnlichen Tkinter-Wrapper geschrieben [Python]
Ich habe Python auf Japanisch geschrieben
Ich habe ein Skript zur automatischen Erstellung eines leeren Verzeichnisses in Python geschrieben
Ich habe eine SMS mit Python gesendet
Ich habe Fizz Buzz in Python geschrieben
Ich habe die Warteschlange in Python geschrieben
Ich habe den Stack in Python geschrieben
[Python-Anfänger] Ich habe die Artikel gesammelt, die ich geschrieben habe
Ein Memo, das ich schnell in Python geschrieben habe
Geschrieben "Einführung in die Effektüberprüfung" in Python
Ich habe versucht, eine E-Mail mit SendGrid + Python zu senden
Python Qiita API Wrapper "qiipy" gemacht
Ich habe Python gestartet
Ich habe matplotlib geschrieben
Ich habe eine Fehlermeldung erhalten, dass Python die Datei settings.ini nicht lesen konnte
Ich habe ein automatisches Kitskript für OpenBlocks IoT geschrieben
Ich erhalte einen Importfehler mit Python Beautiful Soup
Ich habe versucht, künstliches Perzeptron mit Python zu implementieren
Python: Ich habe es mit Lügner und Ehrlichkeit versucht
[Basic Information Engineer Examination] Ich habe einen Algorithmus zur Bestimmung des Jahres der Schwellung in Python geschrieben.