Skip to content

mwerezak/DearPyGui-Obj

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DearPyGui-Obj

An object-oriented interface for Dear PyGui.

Dear PyGui is an excellent Python GUI framework built on top of the Dear ImGui immediate-mode lightweight graphical interface library for C++. Dear PyGui itself is mostly a C++/CPython library with a thin scripting layer as it's primary interface.

This project aims to implement a pure-Python interface to Dear PyGui that takes full advantage of the Python language to provide a concise and ergonomic API.

Documentation

Documentation (on ReadTheDocs) can be found here.

Features and Examples

DearPyGui-Obj makes using DPG more concise and intuitive by allowing you to get and set widget properties using attributes. Setting the callback for a widget is easy using the callback decorator.

Basic Usage

If you've used Dear PyGui, using the object library should be familiar.

from dearpygui_obj import start_gui
from dearpygui_obj import colors
from dearpygui_obj.widgets import *

with Window('Example'):
    text = Text('Edit me using the controls below!', color=colors.salmon)

    Separator()

    text_input = InputText('text content', text.value)
    text_color = ColorEdit('text color', text.color)

@text_input.callback
def callback():
    text.value = text_input.value

@text_color.callback
def callback():
    text.color = text_color.value

start_gui()

Plots and Data Series

from dearpygui_obj import start_gui
from dearpygui_obj.widgets import *
from dearpygui_obj.plots.dataseries import *

with Window('Example') as win:
    data = [ (-1, -9), (1, -4), (3, 11), (4, 5), (9, 7) ]
    lineseries = LineSeries('example', data)

    ## plot data series support indexing and all other MutableSequence methods
    p1, p2 = lineseries[-2], lineseries[-1]
    print('slope:', (p2.y - p1.y)/(p2.x - p1.x))  # elements are named tuples
    lineseries.append((10, 2))  # but methods will accept any compatible sequence

    ## you can also access and modify data as individual 1D sequences,
    ## as long as the length does not change
    print(*lineseries.y[0:3])  # prints -9 -4 11
    lineseries.y[3] += 1
    lineseries.y[0:3] = (-4, 7, -2)
    lineseries.x[:] = [1, 2, 3, 4, 5, 6]
    #lineseries.x = [1, 2, 3]  # TypeError: cannot change length of individual DataSeries field

    plot = Plot()
    plot.add_dataseries(lineseries)

start_gui()

Manipulate Tables using Slices

from dearpygui_obj import start_gui
from dearpygui_obj.widgets import *

with Window('Example') as win:
    table = Table(['col 1', 'col 2', 'col 3', 'col 4'])
    table[:, :] = [
        ['a', 'b', 'c', 'd'],
        ['e', 'f', 'g', 'h'],
        ['i', 'j', 'k', 'l'],
        ['m', 'n', 'o', 'p'],
    ]

    btn = Button('Select Checkerboard')
    @btn.callback
    def callback():
        table.selected[::2, ::2] = True
        table.selected[1::2, 1::2] = True

start_gui()

Defining Custom Widgets

from dataclasses import dataclass
from dearpygui_obj import start_gui
from dearpygui_obj.widgets import *

@dataclass
class Person:
    firstname: str
    lastname: str

class PersonInfo(UserWidget):
    def __setup_content__(self, person: Person):
        Separator()
        with group_horizontal():
            self.selected_chk = Checkbox()
            Button(arrow=ButtonArrow.Up, callback=self.move_up)
            Button(arrow=ButtonArrow.Down, callback=self.move_down)
            Text(f'First name: {person.firstname}')
            Text(f'Last name: {person.lastname}')

    @property
    def selected(self) -> bool:
        return self.selected_chk.value

with Window('Person List Example'):
    with Group() as container:
        pass

    Separator()

    remove_btn = Button('Remove Selected')
    add_btn = Button('Add Person')
    fname_inp = InputText('First name')
    lname_inp = InputText('Last name')

@remove_btn.callback
def callback():
    for child in container.iter_children():
        if child.selected:
            child.delete()

@add_btn.callback
def callback():
    person = Person(fname_inp.value, lname_inp.value)
    PersonInfo.add_to(container, person)
    fname_inp.value = ''
    lname_inp.value = ''

start_gui()

Drawing API

This is the same dynamic drawing example given in the DPG Wiki. You can compare it with the original code.

from dearpygui_obj import start_gui
from dearpygui_obj import colors
from dearpygui_obj.widgets import *

counter = 0
modifier = 2

with Window("Tutorial", size=(800, 800)):
    canvas = Drawing(size=(700, 700))
    circle = canvas.draw_circle((0, 0), 5, colors.from_rgba8(255, 255, 255))

@dearpygui_obj.set_render_callback
def on_render():
    global counter, modifier

    counter += 1
    if counter < 300:
        modifier += 1
    elif counter < 600:
        modifier -= 1
    else:
        counter = 0
        modifier = 2

    circle.center = (15 + modifier*1.25, 15 + modifier*1.25)
    circle.color = colors.from_rgba8(
        255 - modifier*.8, 255 - modifier*.8, 255 - modifier*.3,
    )
    circle.radius = 15 + modifier/2
    circle.segments = round(35-modifier/10)

start_gui()

Other Features

from dearpygui_obj import start_gui
from dearpygui_obj import colors
from dearpygui_obj.widgets import *

with Window('Example') as win:
    ## See what config properties a widget has in the REPL
    Button.get_config_properties() # Returns ['arrow', 'enabled', 'height', ...]

    ## There are many small ergonomic improvements to the API of various widgets
    ## For example, setting arrow buttons is just an Enum instead of two
    ## separate properties
    btn = Button(arrow=ButtonArrow.Right)

    @btn.callback
    def callback():
        if btn.arrow:
            btn.arrow = None
            btn.label = 'Not an arrow button anymore!'

    ## Colors
    red = Text('This text is red.', color=colors.red) # preset HTML colors
    green = Text('This text is green.', color=colors.from_hex('#00FF00'))

    ## Radio buttons, combo boxes, and list widgets are mutable sequences
    radio = RadioButtons(['Apple', 'Orange'])
    radio[0] = 'Banana'
    radio.remove('Orange')
    radio.extend(['Pear', 'Grape'])
    del radio[-1]

## You can add widgets after creating the GUI using methods instead of keywords
add_text = Button.add_to(win, 'Add Label')  # add to the end of a container

@add_text.callback
def callback():
    Text.insert_before(add_text, 'Insert before.')  # insert before a widget

start_gui()

Using DearPyGui-Obj With Existing Dear PyGui Code

DearPyGui-Obj aims to be fully backwards compatible with Dear PyGui. This means that you can freely mix code that uses both DearPyGui and DearPyGui-Obj without issues. Wherever possible, widget classes are designed to draw all of their state from DPG so that there is no possibility of invalidation. You can even create object instances for existing widgets that were created in vanilla DearPyGui.

Installation

This project is currently in the early implementation stage, and a lot of features still need to be implemented. Even the current name for the project is provisional and may change.

Requirements

  • Python 3.8 64-bit
  • dearpygui 0.6.x

You can install from TestPyPI:

pip install -i https://test.pypi.org/simple/ dearpygui-obj

Or you can simply copy the dearpygui_obj package somewhere where Python can find it. DearPyGui-Obj will be available on PyPI proper once it has reached a fuller level of feature-completeness.

License

DearPyGui-Obj is licensed under the MIT License.