Generate multifunctional GUIs from classes

Related tags

magic-class
Overview

magic-class

In magicgui you can make simple GUIs from functions. However, we usually have to create GUIs that are composed of several buttons, and each button is connected with a class method.

Decorate your class with @magicclass and your can use the class both in GUI and from console!

magic-class is work in progress. Feel free to report issues and make suggestions πŸ˜„ .

Installation

  • use pip
pip install git+https://github.com/hanjinliu/magic-class
  • from source
git clone https://github.com/hanjinliu/magic-class

Example

Let's make a simple GUI that can load 1-D data and plot it.

from magicclass import magicclass
from pathlib import Path

@magicclass
class PlotData:
    """
    Load 1D data and plot it.
    """
    def __init__(self, title=None):
        self.title = title
        self.data = None
        self.path = None
        
    def load(self, path:Path):
        """
        Load file.
        """
        self.path = str(path)
        self.data = np.loadtxt(path)
        
    def plot(self):
        """
        Plot data.
        """
        if self.title:
            plt.title(self.title)
        plt.plot(self.data)
        plt.show()

Classes decorated with @magicclass are converted to magicgui's Container widgets. GUI starts with show method.

widget = PlotData(title="Title")
widget.show()

You can continue analysis in console.

widget.plot()

magic-class is also compatible with napari. You can add them to viewers as dock widgets.

import napari
viewer = napari.Viewer()
viewer.window.add_dock_widget(widget)

Other examples are in the "examples" folder.

Issues
  • Input widgets for class attributes  with type declarations as in magicgui?

    Input widgets for class attributes with type declarations as in magicgui?

    Dear @hanjinliu ,

    thanks, this looks great.

    One question: is it also possible to keep input widgets for numbers, data, etc. as in magicgui or is it currently restricted to generating buttons that trigger method calls?

    Maybe these could be class attributes with a magicgu-like wrapper?

    If we can set properties of the class that could be quite useful.

    opened by VolkerH 4
Releases(v0.4.2)
  • v0.4.2(Oct 16, 2021)

    New Features

    • Lots of new Containers are now available. Use @magicclass(widget_type="scrollable") for scrollable Containers, @magicclass(widget_type="button") for Containers that are hidden in push buttons, @magicclass(widget_type="tabbed") for Containers with many tabs, and so on.
    • When checkable widgets are defined in magicmenu, then it will be converted to a checkable action.
    • Instead of line number recording before v0.4.1, I switched widget ordering to a new way that depends on __dict__. Therefore, you don't have to add some widgets like w = field(LineEdit), but w = LineEdit() also works.
    • With wraps function you can copy signature from a template function to other methods. For example, if you defined a lot of methods that take argument path, you don't have to add annotation Path for every function. Define a template function
      def template(path: Path): pass
      

      and decorate methods.

      @wraps(template)
      def method1(self, path): ...
      

      wraps method of magicclass also support the same wrapping strategy but currently need keyword "template=".

    Changes

    • Docstring of class was converted into Label widget before. But this was usually useless. Now it will be converted into tooltip. If you want a Label widget, create a widget inside magicclass like
      @magicclass
      class Main:
          label = Label(...)
          def func(self): ...
      
    • When a magicclass is docked into napari, all the magicguis and macro windows were opened via add_dock_widget and setFloating. However, it is no general and is not a good way in general. Now parent is set for every magicgui and macro window.

    Bug fixes

    • When magicclass is nested for three times it resulted in wrong macro.
    • When method arguments conflict with any attributes of FunctionGui, magicclass raised error when recording parameter histories.
    • When more than one magicguis were added in a same magicclass, only one of them was shown up.
    Source code(tar.gz)
    Source code(zip)
  • v0.4.1(Oct 9, 2021)

  • v0.4.0(Oct 8, 2021)

    New Features

    • You can make menu bar very easily using @magicmenu decorator. The newly defined class, MenuGui, has almost the same API with ClassGui, supports macro recording and interactive with its parent class. See "examples/use_menubar.py" as an example.
    • New widgets that are useful for better UI.
      • TupleEdit, ListEdit: Container widgets that composed of same widgets. These widgets are useful for input such as list[int].
      • CheckButton: Checkable button widget.
      • ListWidget: Python list like widget that can contain any Python objects, with simple API for defining different callbacks, context menus and/or delegates.

    Improvements

    • If a method takes only one argument that will be converted to FileEdit, it will not create FunctionGui but launch file dialog directly.
    • click wrapper accepts method object, as well as str.
    • wraps method can take FunctionGui as the input.
    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Sep 17, 2021)

    Highlight

    Class method ClassGui.wraps can make parent namespace discoverable from its children. When you try to make a nice GUI, you usually have to make many magic-classes inside the main one, while keep their attributes visible from each other. It was very hard to achieve in previous versions.

    @magicclass
    class Main:
        x = field(int) # "global" attribute of GUI
    
        @magicclass
        class A:
            a1 = field(int) # "inner" attribute
            def main_func(self): ... # pre-define here to make sure widgets will be aligned in the correct order in class A.
    
        @A.wraps
        def main_func(self): ... # self is always Main object but this function will be a method of class A.
    

    Value changed event can be connected to functions much easier now, using MagicField.connect method.

    @magicclass
    class Main:
        x = field(int)
    
        @x.connect
        def _callback(self):
            # This function will be called on value change of x.
            # To avoid being converted into push button, add "_".
    

    Changes

    • When magic-classes is nested, parent magic-classes are accessible from their children via __magicclass_parent__ attribute.
    • ⚠️ field now always returns Widget. self.i = field(int) used to return integer which is connected to its corresponding widget value changes. This is because I thought it should be convenient to be able to get the value via self.i. However, this design turned out to restrict the value like a read-only property since it is usually hard to set value to the widget. Now you always need to use self.i.value to get the value.
    • click wrapper can change properties of buttons in other nested magic-class. If class A and B are nested in class Main, then A.xx is accessible from class Main by click("A.xx"), and is also accessible from class B by click(".A.xx").

    Bug fixes

    • Method wrappers in "wrapper.py" were not working correctly when more than one wrapper is called on the same method.
    • @magicclass decorator received wrong line number if nested.
    • Macro was not correctly recorded if child magic-classes are constructed inside their parent.
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Sep 15, 2021)

    Highlights

    Now you can add non-button widgets easily with field function, in a way similar to @dataclass. Following code:

    @magicclass
    class C:
        i = field(int)
        s = field("some string")
    

    will create a Slider widget, whose value is connected to self.i, and a LineEdit widget, whose value is connected to self.s. Since field function can remember the line number of itself, all the widgets are sorted in the same order as in the source code. (In the previous version you had to call @magicgui inside __post_init__ and append the widget to the magic-class)

    Also, macro recording is working! Inspired by Julia language, I implemented Expr class to make function calls and value setting programmable. Executable Python scripts will be automatically recorded and you can see it by calling create_macro() method of magic-class.

    Changes

    • Updated API for magicgui==0.2.11
    • Confirmed compatibility of @magicgui inside a magic-class.
    • Confirmed compatibility of nested magic-class.
    • Make @dataclass as compatible as possible.
    • Do not add too many labels.
    • Renamed BaseGui to ClassGui for consistency with FunctionGui.
    • Simple logger is available, but still work in progress. With debug() context manager you can open a logger window.
    • Result widget, like FunctionGui.

    Bug Fixes

    • Parameter history was not correctly recorded if magic-class is used in napari.
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Sep 10, 2021)

    This is the first minor release. It's much easier to customize buttons and their actions.

    New Features

    • Wrapper functions that can set attributes to push buttons itself.
      • @set_options can change parameter options of method arguments just like magicgui.
      • @click can set button properties related to clicking, or connect special behaviors to button click event, such as disabling or hiding buttons.
      • @button_design can change the design of push buttons. Currently support button size including min/max, font size, font family, text color, background color, icon and icon size.
    • __post_init__ method can be called after __init__.
      • This is useful when you want to append other widgets after all the methods are converted to buttons (If self.append is called inside __init__ then the widget will appear on the top of the main widget).
    • Custom widgets (Figure and Separator) are available in magicclass.widgets.
      • Figure is a matplotlib figure canvas widget. You can directly append it to Container widgets.
      • Separator is a simple separator.
    • You can suppress popup by the option @magicclass(popup=False).

    Improvements

    • Methods are sorted in the same order as the order in the source code.
    • Each method remembers the last input and will be recalled on the next function call.
    • napari.Viewer was imported in a weird timing. Now it's fixed.

    Bug fixes

    • Jupyter froze when GUI is build for the second time.
    • Could not add multiple dock widgets to napari.
    Source code(tar.gz)
    Source code(zip)
  • v0.0.1(Sep 7, 2021)

Owner
Department of Biological Sciences, School of Science, The University of Tokyo. My major is biophysics, especially microtubule and motor proteins.
null
guietta - a tool for making simple Python GUIs

guietta - a tool for making simple Python GUIs

Alfio Puglisi 1.8k Oct 20, 2021
Tkinter Designer - Create Beautiful Tkinter GUIs by Drag and Drop.

Tkinter Designer is created to speed up and beautify Python GUI Experience. It uses well know design software called Figma. Which makes creating Tkinter GUI in Python a piece of cake.

Parth Jadhav 2.7k Oct 24, 2021
Declarative User Interfaces for Python

Welcome to Enaml Enaml is a programming language and framework for creating professional-quality user interfaces with minimal effort. What you get A d

null 1.1k Oct 15, 2021
Tukaan is the new framework that aims to replace Tkinter

Tukaan is the new, pythonic and colorful (like a keel-billed toucan) framework that aims to replace Tkinter. It has everything (on my computer, not at GitHub) that you need to develop cross-platform GUIs.

Tukaan 11 Oct 16, 2021
Dear PyGui: A fast and powerful Graphical User Interface Toolkit for Python with minimal dependencies

(This library is available under a free and permissive license however, if you Enjoy Dear PyGui please consider becoming a Sponsor) Dear PyGui is a si

Jonathan Hoffstadt 6.2k Oct 22, 2021
Dear PyGui: A fast and powerful Graphical User Interface Toolkit for Python with minimal dependencies

(This library is available under a free and permissive license however, if you Enjoy Dear PyGui please consider becoming a Sponsor) Dear PyGui is a si

Jonathan Hoffstadt 6.2k Oct 23, 2021
System Tray Icon for PySimpleGUI (the tkinter version). Adds a system tray icon by using pystray and PIL

psgtray Add a System Tray Icon to your tkinter port of PySimpleGUI. Installation via pip Installation is via pip: python -m pip install psgtray or if

PySimpleGUI 9 Oct 14, 2021
A hotkey manager that runs in the system tray. Uses PySimpleGUI for the GUI and the system tray.

PySimpleHotkey PySimpleHotkey A hotkey manager that runs in the system tray. Uses PySimpleGUI for the GUI and the system tray. Packages Used This proj

PySimpleGUI 15 Oct 17, 2021
πŸ† A ranked list of awesome python libraries for web development. Updated weekly.

Best-of Web Development with Python ?? A ranked list of awesome python libraries for web development. Updated weekly. This curated list contains 540 a

Machine Learning Tooling 1.4k Oct 22, 2021
PyCG: Practical Python Call Graphs

PyCG - Practical Python Call Graphs PyCG generates call graphs for Python code using static analysis. It efficiently supports Higher order functions T

Vitalis Salis 92 Oct 18, 2021
A library for building modern declarative desktop applications in WX.

re-wx is a library for building modern declarative desktop applications. It's built as a management layer on top of WXPython, which means you get all the goodness of a mature, native, cross-platform UI kit, wrapped up in a modern, React inspired API.

Chris 92 Oct 12, 2021
A keyboard-driven, vim-like browser based on PyQt5.

qutebrowser is a keyboard-focused browser with a minimal GUI. It’s based on Python and PyQt5 and free software, licensed under the GPL.

qutebrowser 7.3k Oct 23, 2021