DearPyGui:一个简单的 Python GUI 工具箱

Dear PyGui:针对 Python 的无膨胀(Bloat-free)图形用户界面,具有最小的依赖性,托管在 hoffstadt/DearPyGui

Dear PyGui 是一个易于使用(但功能强大)的 Python GUI 框架。Dear PyGui 提供了 Dear ImGui 的包装,该包装模拟了传统的保留(retained)模式 GUI(与 Dear ImGui 的立即(immediate)模式范例相反)。

Dear PyGui 与其他 Python GUI 框架从根本上不同。在后台,Dear PyGui 使用即时模式范例和计算机的 GPU 来实现极为动态的界面。下列平台当前支持 Dear PyGui:

Platform Rendering API
Windows 10 DirectX 11
macOs Metal
Linux OpenGL 3

Dear ImGui 以相同的方式为游戏开发人员提供了一种创建工具的简单方法,Dear PyGui 则提供了一种方便Python 开发人员为脚本创建快速而强大的 GUI 的简单方法。

与其他 Python GUI 库相比,Dear PyGui 具有以下独特之处:

  • GPU 渲染
  • 简单的内置异步功能支持
  • 完整的主题和样式控制
  • 简单的内置日志窗口
  • 70多个小部件具有数百种小部件组合
  • 详细的文档,示例和无与伦比的支持

安装(支持Python3.6 以上):pip install dearpygui。可以在 Github 上的 Examples 文件夹中找到各种演示用法的示例。使用show_documentation() 命令可以在此处找到文档,也可以从库中找到文档。

使用 Dear PyGui 很简单,就像创建下面的 Python 脚本一样:

from dearpygui.core import *
from dearpygui.simple import *

def save_callback(sender, data):
    print("Save Clicked")

with window("Example Window"):
    add_text("Hello, world")
    add_button("Save", callback=save_callback)
    add_input_text("string", default_value="Quick brown fox")
    add_slider_float("float", default_value=0.273, max_value=1)

start_dearpygui()

显示:

接下来,看看如何使用 Dear PyGui ("DPG")。

1 概览

Dear PyGui 由视口(viewport),窗口(windows)和小部件(widgets)组成。视口是程序的主窗口,通过调用函数 start_dearpygui 创建。

下面是视口和一个窗口的示例,其中显示了使用内置文档函数的文档:

from dearpygui.core import *
from dearpygui.simple import *

set_main_window_size(800, 800)
show_about()
show_documentation()

# when running this code please look at the about window and it will report which version of Dear PyGUI is running
start_dearpygui()

效果:

DPG 当前由两个模块 dearpygui.coredearpygui.simple 组成。dearpygui.core 包含 Dear PyGui 的核心功能。其他所有内容都建立在 core 之上(包括 simple)。

dearpygui.simple 包含简单的包装程序和其他从核心创建的实用程序,以提供与 DPG 更为友好的接口。随着代码复杂度的增加,建议在适用时开始使用 simple 模块。

在整个教程中,我们将使用推荐的过程来完成各种任务。这将包括 core 功能和 simple 功能。

2 开发者工具

Dear PyGui 包含几个有用的开发人员工具,我们将在整个教程中使用它们。

from dearpygui.core import *
from dearpygui.simple import *

show_documentation()
show_debug()
show_about()
show_metrics()
show_logger()

start_dearpygui()

3 内置的日志功能

记录器(Logger)是众多强大的内置开发人员工具之一。可以通过命令 show_logger 进行访问。记录器有 6 个日志级别:

  1. Trace
  2. Debug
  3. Info
  4. Warning
  5. Error
  6. Off

看一个例子:

from dearpygui.core import *
from dearpygui.simple import *

show_logger()
set_log_level(mvTRACE)
log("trace message")
log_debug("debug message")
log_info("info message")
log_warning("warning message")
log_error("error message")

start_dearpygui()

4 创建小部件和容器

DPG 项可以细分为:

  • 常规项目(即 inputs, buttons)
  • 容器项目(例如,window, popup, tooltip, child)
  • 布局项(即 group, next_column)

项将使用其各自的 add _***命令添加。

每个项必须具有唯一的名称。默认情况下,名称将成为标签(如果适用)。如果您想更改小部件的标签,可以:

  • 放到名称的尾部的“##”(例如"displayed_name##unique_part")后面的名称将从显示的名称中隐藏。
  • 使用 label 关键字将显示标签而不是项名称。

对于在函数中没有名称参数的项,将自动生成某些项名称。(即 same_line)。但是,它们有一个可选的 name 关键字,如果以后需要引用该项目,则可以填写该关键字。

from dearpygui.core import *
from dearpygui.simple import *

with window("Tutorial"):
    add_button("Apply")
    add_same_line(spacing=10)
    add_button("Apply##1")
    add_same_line(spacing=10, name="sameline1")
    add_button("Apply2", label="Apply")
    add_spacing(count=5, name="spacing1")
    add_button("Apply##3")

start_dearpygui() 

容器项用于容纳其他项,并且可由任一项实现:

  • 使用 add _*** 函数启动容器,然后 end 函数完成。
  • 使用 dearpygui.simple 和相应的容器上下文管理器(推荐方法)。

当容器项“added”时,它们被推入父堆栈。之后添加的任何项目都将属于堆栈顶部的父项。当容器项“ended”时,它们将从父堆栈弹出。

dearpygui.simple 的上下文管理器自动调用 end 函数,并允许代码折叠并在代码本身中显示层次结构。

from dearpygui.core import *
from dearpygui.simple import *

with window("Tutorial"):
    add_text("This is some text on window 2")

start_dearpygui()

默认情况下,项按提交顺序创建。但是,可以通过指定 parent 容器来无序添加项目。使用 parent 关键字会将小部件插入到父级的子级列表的末尾。如果您想将其插入其他位置,请在与 parent 关键字组合使用 before 之前,将该项目放在 parent 容器中另一个项目之前。

from dearpygui.core import *
from dearpygui.simple import *

with window("window 1"):
    with child("child 1"):
        # this is a input item added inside of the child
        add_checkbox("Checkbox")

with window("Tutorial"):
    add_text("First created widget")
    # we can even specify the parent before it was created
    add_text("This is some text on window 1", parent="window 1")
    add_text("This is some text on child 1", parent="child 1")

add_checkbox("Last created widget", parent="MainWindow",
             before="First created widget")
add_checkbox("Last created widget 2", parent="child 1", before="Checkbox")

# empty window
with window("window 3"):  # simple
    pass

start_dearpygui()

效果:

5 主窗口

可以使用 start_dearpyguiprimary_window 关键字或使用 set_primary_window 命令将窗口设置为主窗口(即视口)。

from dearpygui.core import *
from dearpygui.simple import *

with window("Tutorial"):
    add_checkbox("Radio Button")
set_main_window_size(800, 600)
start_dearpygui(primary_window="Tutorial")

6 使用小部件

每个输入窗口小部件都有一个值,该值可以在运行时通过命令 set_value 设置,或创建时使用 default_value 关键字设置。

要访问小部件的值,我们可以使用命令 get_value

from dearpygui.core import *
from dearpygui.simple import *

with window("Tutorial"):
    add_checkbox("Check Box", default_value=False)
    print("First value of the Check Box is: ", get_value("Check Box"))
    set_value("Check Box", True)
    print("Value after setting the Check Box is: ", get_value("Check Box"))

start_dearpygui()

7 小部件和窗口回调

每个输入窗口小部件都有一个回调,在与窗口小部件交互时会运行该回调。

回调用于为小部件提供功能。回调可以在创建时使用 callback 或在创建后使用 set_item_callback 分配给窗口小部件。在 Dear PyGui 中,应用于项目的每个回调都必须包含一个 senderdata 参数。

Dear PyGui 使用 sender 参数通过发送名称来通知回调哪个窗口小部件触发了回调。

各种标准回调使用 data 参数通过指定回调 callback_data 来发送其他数据。

from dearpygui.core import *
from dearpygui.simple import *

def button_callback(sender, data):
    log_debug(f"sender is: {sender}")
    log_debug(f"data is: {data}")

show_logger()  # we're going to use the logger here to show the result

with window("Tutorial"):
    add_input_text("Input Text", default_value="Hello World!")
    add_button("Apply", callback=button_callback, callback_data=get_value("Input Text"))
    add_button("Apply##2", tip="callback was set after item was created")
    set_item_callback("Apply##2", callback=button_callback, callback_data=get_value("Input Text"))

start_dearpygui() 

每次与小部件进行交互时,我们都可以使用回调来更新 Python 变量的值。在下面的示例中显示:

from dearpygui.core import *
from dearpygui.simple import *

def update_var(sender, data):
    my_var = get_value("Input Checkbox")
    log_debug(my_var)

show_logger() # were going to use the logger here to show the result

with window("Tutorial"):
    add_checkbox("Input Checkbox", callback=update_var)

start_dearpygui() 

但是通过使用 sender 会是更聪明的方法:

from dearpygui.core import *
from dearpygui.simple import *

def update_var(sender, data):
    my_var = get_value(sender)
    log_debug(my_var)


show_logger() # were going to use the logger here to show the result

with window("Tutorial"):
    add_checkbox("Input Checkbox", callback=update_var)
    add_input_text("Input Text", callback=update_var)
    add_input_int("Input Int", callback=update_var)

start_dearpygui() 

窗口类型的窗口小部件具有特殊的回调,这些回调在诸如窗口大小调整和窗口关闭之类的事件上触发。特定于窗口的回调可以应用于任何窗口类型的小部件。on_close 将在窗口关闭时运行分配给关键字的回调,set_resize_callback 将在容器的每次调整大小时运行,并且可以使用 handler 关键字设置为任何特定窗口,默认值为“MainWindow”。

如果您希望每帧都执行一次回调,则可以使用 set_render_callback

from dearpygui.core import *
from dearpygui.simple import *


def close_me(sender, data):
    log_debug(f"{sender} window has been closed")


def render_me(sender, data):
    log_debug(f"window {sender} has ran a render callback")


def resize_me(sender, data):
    log_debug(f"window {sender} has ran a resize callback")


# were going to use the logger to display callback replies
show_logger()
with window("Tester", on_close=close_me):
    add_text('resize this window resize callback will occur')
    add_text('close this window using the "x" button and a close callback will occur')

set_render_callback(render_me)
set_resize_callback(resize_me, handler="Tester")

start_dearpygui()

8 运行时添加和删除小部件

借助 Dear PyGui,您可以在运行时(Run-time)动态添加和删除任何项。这可以通过使用回调来运行所需项的 add _*** 命令并指定该项目所属的父项来完成。默认情况下,如果未指定父项,则将小部件添加到MainWindow

通过在添加项之前使用关键字,您可以控制新项位于父项中的哪个项目之前。默认将新的小部件放在最后。

在此示例中,我们使用“debug”开发人员工具来查看小部件的当前状态。转到调试窗口小部件上的“App Item Layout”选项卡,此选项卡显示应用程序的状态和属性。单击“MainWindow”树项,我们可以看到 MainWindow 当前显示的小部件。尝试单击主窗口上的“Add/Delete”按钮,然后查看树的状态更改。

from dearpygui.core import *
from dearpygui.simple import *

def add_buttons(sender, data):
    add_button("New Button", parent="Secondary Window")
    add_button("New Button 2", parent="Secondary Window")

def delete_buttons(sender, data):
    delete_item("New Button")
    delete_item("New Button 2")

show_debug()

with window("Tutorial"):
    add_button("Add Buttons", callback=add_buttons)
    add_button("Delete Buttons", callback=delete_buttons)

with window("Secondary Window"):
    pass

start_dearpygui()

删除容器时,默认情况下会删除容器及其子级,除非关键字 children_only 设置为 True

from dearpygui.core import *
from dearpygui.simple import *


def add_widgets(sender, data):
    with window("Secondary Window"):  # simple
        add_button("New Button 2", parent="Secondary Window")
        add_button("New Button", parent="Secondary Window")
        add_button("New Button 3", parent="Secondary Window")


def delete_widgets(sender, data):
    delete_item("Secondary Window")
    delete_item("New Button")


def delete_children(sender, data):
    delete_item("Secondary Window", children_only=True)


show_debug()

with window("Tutorial"):
    add_button("Add Window and Items", callback=add_widgets)
    add_button("Delete Window and Children", callback=delete_widgets)
    add_button("Delete Window's Children", callback=delete_children)

start_dearpygui()

9 值与数据存储

添加新的窗口小部件时,会将值添加到值存储系统。默认情况下,此值的标识符是小部件的名称。您可以使用 source 关键字覆盖标识符。这样做的好处之一是让多个小部件控制相同的值。

使用 get_value 从值系统检索值。可以使用 set_value 手动更改值。

为了使不同值类型的小部件在存储系统中使用相同的值,必须首先创建较大的值。

例如,创建 input_float3 时,存储的值类型为 [float, float, float]。稍后创建的 input_float2 可以使用与 input_float3 相同的源。但是,如果先创建了 input_float2,然后尝试与 input_float3 共享其源,则它将不起作用。为了使 input_float3input_float2 共享同一源,我们可以创建 input_float3,需要首先创建。这是通过 add_value() 完成的。

from dearpygui.core import *
from dearpygui.simple import *


def print_me(sender, data):
    log_debug(f"checkbox values: {get_value('value_1')}")
    log_debug(f"text values: {get_value('value 2')}")
    log_debug(f"color values: {get_value('color4')}")


def reset(sender, data):
    set_value("value_1", False)
    set_value("value 2", "Hello World!")


show_logger()

with window("Tutorial"):
    add_checkbox("Radio Button1", source="value_1")
    add_checkbox("Radio Button2", source="value_1")
    add_input_text("Text Input 1", source="value 2")
    add_input_text("Text Input 2", source="value 2", password=True,
                   tip="this input text has password applied")
    add_button("Print source values", callback=print_me)
    add_button("Reset source values", callback=reset)

    # special case when linking a smaller input type widget to a larger one create the large value first
    add_value("color4", (0.0, 0.0, 0.0, 0.0))
    add_color_edit3("color edit 3", source="color4")
    add_color_edit4("color edit 4", source="color4")

start_dearpygui()

DPG 还提供用于数据存储的常规数据。使用 add_data,我们可以传入任何 Python 项以将其存储为数据项,并稍后使用 get_data("name") 进行访问。请记住,您可以将任何 Python 对象存储在数据存储中,甚至可以存储自定义数据类型。

from dearpygui.core import *
from dearpygui.simple import *

def store_data(sender, data):
    custom_data = {
        "Radio Button": get_value("Radio Button"),
        "Checkbox": get_value("Checkbox"),
        "Text Input": get_value("Text Input"),
    }
    add_data("stored_data", custom_data)

def print_data(sender, data):
    log_debug(get_data("stored_data"))

show_logger()
show_debug()

with window("Tutorial"):
    add_radio_button("Radio Button", items=["item1", "item2"])
    add_checkbox("Checkbox")
    add_input_text("Text Input")
    add_button("Store Data", callback=store_data)
    add_button("Print Data", callback=print_data)


start_dearpygui()

10 菜单栏

用于 GUI 功能的一个非常重要的小部件是菜单栏(Menu Bar)。菜单栏始终显示在窗口顶部,并具有3个主要部分:

  1. 菜单栏:主菜单功能区
  2. 菜单:下拉菜单“子菜单”
  3. 菜单项:可以运行回调的项目(基本上是可选的)

菜单栏从右到左添加项。菜单从上到下添加项。菜单可以根据需要嵌套。任何小部件都可以添加到菜单中。

from dearpygui.core import *
from dearpygui.simple import *


def print_me(sender, data):
    log_debug(f"Menu Item: {sender}")


show_logger()

with window("Tutorial"):
    with menu_bar("Main Menu Bar"):
        with menu("File"):
            add_menu_item("Save", callback=print_me)
            add_menu_item("Save As", callback=print_me)

            with menu("Settings"):
                add_menu_item("Setting 1", callback=print_me)
                add_menu_item("Setting 2", callback=print_me)

        add_menu_item("Help", callback=print_me)

        with menu("Widget Items"):
            add_checkbox("Pick Me", callback=print_me)
            add_button("Press Me", callback=print_me)
            add_color_picker4("Color Me", callback=print_me)

start_dearpygui()

11 文件和目录选择器对话框

通过调用 select_directory_dialog 使用目录对话框,必须为其提供 return 回调。return 回调的 data 参数将用目录路径和文件夹路径作为字符串列表填充。

通常,目录对话框由另一个小部件(例如按钮)调用,因此示例中将采用这种方式。

from dearpygui.core import *
from dearpygui.simple import *


def directory_picker(sender, data):
    select_directory_dialog(callback=apply_selected_directory)


def apply_selected_directory(sender, data):
    log_debug(data)  # so we can see what is inside of data
    directory = data[0]
    folder = data[1]
    set_value("directory", directory)
    set_value("folder", folder)
    set_value("folder_path", f"{directory}\\{folder}")


show_logger()

with window("Tutorial"):
    add_button("Directory Selector", callback=directory_picker)
    add_text("Directory Path: ")
    add_same_line()
    add_label_text("##dir", source="directory", color=[255, 0, 0])
    add_text("Folder: ")
    add_same_line()
    add_label_text("##folder", source="folder", color=[255, 0, 0])
    add_text("Folder Path: ")
    add_same_line()
    add_label_text("##folderpath", source="folder_path", color=[255, 0, 0])

start_dearpygui()

通过调用 open_file_dialog 使用文件对话框,必须为其提供 return 回调。return 回调的 data 参数将用目录路径和文件路径填充为字符串列表。扩展名是文件对话框的可选关键字,它将提供选择以根据其扩展名过滤对话框中显示的文件。

通常,文件对话框是由另一个小部件(例如按钮)调用的,因此示例中将采用这种方式。

from dearpygui.core import *
from dearpygui.simple import *

def file_picker(sender, data):
    open_file_dialog(callback=apply_selected_file, extensions=".*,.py")


def apply_selected_file(sender, data):
    log_debug(data)  # so we can see what is inside of data
    directory = data[0]
    file = data[1]
    set_value("directory", directory)
    set_value("file", file)
    set_value("file_path", f"{directory}\\{file}")

show_logger()

with window("Tutorial"):
    add_button("Directory Selector", callback=file_picker)
    add_text("Directory Path: ")
    add_same_line()
    add_label_text("##filedir", source="directory", color=[255, 0, 0])
    add_text("File: ")
    add_same_line()
    add_label_text("##file", source="file", color=[255, 0, 0])
    add_text("File Path: ")
    add_same_line()
    add_label_text("##filepath", source="file_path", color=[255, 0, 0])

start_dearpygui()

12 Plotting

Dear PyGui 具有 simple plots 和 plots,它们都具有动态能力。simple plots 将获取列表,并针对列表中的项目数绘制 y 轴数据。这些可以是折线图或直方图,如下所示。

from dearpygui.core import *
from dearpygui.simple import *

with window("Tutorial"):
    add_simple_plot("Simpleplot1", value=[0.3, 0.9, 0.5, 0.3], height=300)
    add_simple_plot("Simpleplot2", value=[0.3, 0.9, 2.5, 8.9], overlay="Overlaying", height=180, histogram=True)

start_dearpygui()

plots 比 simple plots 具有更多的功能。plots 同时使用 x 和y坐标。必须使用 add_plot 命令创建图,然后可以将数据作为线系列或散布系列添加。plots 的特点是:

  • 单击并拖动:平移图
  • 单击并拖动Axis:在一个方向上平移图
  • 双击:将图缩放为数据
  • 右键单击并拖动:缩放到某个区域
  • 双击右键:打开设置
  • Shift +右键单击并拖动:放大到填充当前轴的区域
  • 滚动鼠标滚轮:缩放
  • 在轴上滚动鼠标滚轮:仅缩放该轴
  • 切换图例上的数据集以隐藏它们

另外,可以使用文本点将浮动文本放置在绘图上。

from dearpygui.core import *
from dearpygui.simple import *
from math import cos, sin


def plot_callback(sender, data):
    clear_plot("Plot")

    data1x = []
    data1y = []
    for i in range(0, 100):
        data1x.append(3.14 * i / 180)
        data1y.append(cos(3 * 3.14 * i / 180))

    data2x = []
    data2y = []
    for i in range(0, 100):
        data2x.append(3.14 * i / 180)
        data2y.append(sin(2 * 3.14 * i / 180))

    add_line_series("Plot", "Cos", data1x, data1y,
                    weight=2, color=[0, 0, 255, 100])
    add_shade_series("Plot", "Cos", data1x, data1y,
                     weight=2, fill=[255, 0, 0, 100])
    add_scatter_series("Plot", "Sin", data2x, data2y, outline=[0, 255, 0, 100])


with window("Tutorial"):
    add_button("Plot data", callback=plot_callback)
    add_plot("Plot", height=-1)

start_dearpygui()

通过使用 set_value 更改绘图调用的值,可以使 Simple plots 变得动态。如下所示。

from dearpygui.core import *
from dearpygui.simple import *
from math import sin

def on_render(sender, data):
    frame_count = get_data("frame_count")
    frame_count += 1
    add_data("frame_count", frame_count)
    plot_data = get_value("plot_data")
    if len(plot_data) > 100:
        plot_data.pop(0)
    plot_data.append(sin(frame_count/30))
    set_value("plot_data", plot_data)

with window("Tutorial"):
    add_simple_plot("Simple Plot", source="plot_data", minscale=-1.0, maxscale=1.0, height=300)
    add_data("frame_count", 0)
    set_render_callback(on_render)

start_dearpygui()

Plots 也可以是动态的。可以使用动态功能,就像清除图并使用回调(例如渲染或项目的回调)添加新数据一样容易。set_value。 如下所示。

from dearpygui.core import *
from dearpygui.simple import *
from math import cos

def plot_callback(sender, data):
    # keeping track of frames
    frame_count = get_data("frame_count")
    frame_count += 1
    add_data("frame_count", frame_count)

    # updating plot data
    plot_datax = get_data("plot_datax")
    plot_datay = get_data("plot_datay")
    if len(plot_datax) > 2000:
        frame_count = 0
        plot_datax.clear()
        plot_datay.clear()
    plot_datax.append(3.14 * frame_count / 180)
    plot_datay.append(cos(3 * 3.14 * frame_count / 180))
    add_data("plot_datax", plot_datax)
    add_data("plot_datay", plot_datay)

    # plotting new data
    clear_plot("Plot")
    add_line_series("Plot", "Cos", plot_datax, plot_datay, weight=2)

with window("Tutorial"):
    add_plot("Plot", height=-1)
    add_data("plot_datax", [])
    add_data("plot_datay", [])
    add_data("frame_count", 0)
    set_render_callback(plot_callback)

start_dearpygui()

13 Drawing/Canvas

Dear PyGui 有一个低级绘图 API,非常适合原始绘图,自定义小部件甚至动态绘图。通过调用 add_drawing 开始绘制,然后可以通过调用其各自的绘制命令来添加项目。画布的原点在左上方,y 轴指向下方。

from dearpygui.core import *
from dearpygui.simple import *

with window("Tutorial"):
    add_drawing("Drawing_1", width=300, height=300)

draw_line("Drawing_1", [10, 10], [100, 100], [255, 0, 0, 255], 1)
draw_text("Drawing_1", [0, 0], "Origin", color=[250, 250, 250, 255], size=15)
draw_arrow("Drawing_1", [50, 70], [100, 65], [0, 200, 255], 1, 10)

start_dearpygui()

Drawings 可以显示 PNG,JPEG 或 BMP类型的图像。使用 draw_image 绘制图像。使用关键字“pmin”和“pmax”,我们可以定义将图像绘制到画布上的矩形的左上和右下区域。图像将缩放以适合指定区域。使用关键字“uv_min”和“uv_max”,我们可以定义应在画布上绘制图像的哪个区域的标量。uv_min = [0,0]uv_max = [1,1] 的默认值将显示整个图像,而 uv_min = [0,0] uv_max = [0.5,0.5] 的默认值仅显示图形的第一部分。

为了演示这些功能,您必须将目录更新为计算机上图像的目录,例如 SpriteMapExample.png

from dearpygui.core import *
from dearpygui.simple import *

# please update the image directory argument with a path to an image on your computer for this example
with window("Tutorial"):
    add_drawing("Drawing_1", width=700, height=700)

draw_image("Drawing_1", 'SpriteMapExample.png', [0, 700], pmax=[200, 500], uv_min=[0, 0], uv_max=[1, 1], tag="image")
draw_image("Drawing_1", 'SpriteMapExample.png', [0, 600], pmax=[200, 300], uv_min=[0, 0], uv_max=[1, 1])
draw_image("Drawing_1", 'SpriteMapExample.png', [0, 500], pmax=[200, 100], uv_min=[0, 0], uv_max=[1, 1])
draw_image("Drawing_1", 'SpriteMapExample.png', [400, 600], pmax=[600, 400], uv_min=[0, 0], uv_max=[0.5, 0.5])
draw_image("Drawing_1", 'SpriteMapExample.png', [400, 400], pmax=[700, 50], uv_min=[0, 0], uv_max=[3.5, 2.5])

start_dearpygui()

尽管可以通过清除和重绘整个图来使图形动态化,但仍提供了一种更有效的方法。

为了使绘图动态,我们应该使用 tag 关键字标记要重绘的项目。然后,只需使用相同的标签调用绘制命令即可。这将仅删除该一项,并使用新命令将其重新绘制。

from dearpygui.core import *
from dearpygui.simple import *

def on_render(sender, data):
    counter = get_data("counter")
    counter += 1
    modifier = get_data("modifier")
    if counter < 300:
        modifier += 1
    elif counter < 600:
        modifier -= 1
    else:
        counter = 0
        modifier = 2

    xpos = 15 + modifier*1.25
    ypos = 15 + modifier*1.25
    color1 = 255 - modifier*.8
    color3 = 255 - modifier*.3
    color2 = 255 - modifier*.8
    radius = 15 + modifier/2
    segments = round(35-modifier/10)
    draw_circle("Drawing_1", [xpos, ypos], radius, [color1, color3, color2, 255], segments=segments, tag="circle##dynamic")
    add_data("counter", counter)
    add_data("modifier", modifier)

add_data("counter", 0)
add_data("modifier", 2)

with window("Tutorial"):
    add_drawing("Drawing_1", width=700, height=700)

set_render_callback(on_render)

start_dearpygui()

14 增量时间和内部时钟

Dear PyGui 有一个内置时钟,用于检查总运行时间 get_total_time,该时间以秒为单位返回总运行时间。同样使用命令 get_delta_time(),我们可以检查渲染帧之间的时间(以秒为单位)。

from dearpygui.core import *
from dearpygui.simple import *

def on_render(sender, data):
    delta_time = str(round(get_delta_time(), 4))
    total_time = str(round(get_total_time(), 4))
    set_value("delta_time", delta_time)
    set_value("total_time", total_time)

with window("Tutorial"):
    add_text("Total Time: ")
    add_same_line()
    add_label_text("##total_time_text", source="total_time")
    add_text("Delta Time: ")
    add_same_line()
    add_label_text("##delta_time_text", source="delta_time")

set_render_callback(callback=on_render)

start_dearpygui()

15 Sprites

使用带有 tags 的图形,get_delta_time 和回调在渲染时运行,我们可以创建一个精灵字符(sprite character)。对于此示例,我们需要从 GitHub 上的 examples 文件夹下载 SpriteMapExample.png 并将其放置在工作目录中的 Python 文件旁边。

通过调用 add_drawing 开始绘制,然后可以通过调用其各自的绘制命令来添加项目。画布的原点在左下方。

from dearpygui.core import *
from dearpygui.simple import *


def on_render(sender, data):
    delta_draw_time = get_data("delta_draw_time")
    draw_speed = get_value("Draw Pause")

    if delta_draw_time > draw_speed:
        if get_value("Fly Mode") == 0:
            if get_data("sprite1"):
                draw_image("Drawing_1", 'SpriteMapExample.png', top_left, pmax=bottom_right, uv_min=[.7690, 0],
                           uv_max=[.8074, .10], tag="sprite")
                add_data("sprite1", False)
            else:
                draw_image("Drawing_1", 'SpriteMapExample.png', top_left, pmax=bottom_right, uv_min=[.8074, 0],
                           uv_max=[.8461, .10], tag="sprite")
                add_data("sprite1", True)
        else:
            if get_data("sprite1"):
                draw_image("Drawing_1", 'SpriteMapExample.png', top_left, pmax=bottom_right, uv_min=[.8464, 0],
                           uv_max=[.8848, .10], tag="sprite")
                add_data("sprite1", False)
            else:
                draw_image("Drawing_1", 'SpriteMapExample.png', top_left, pmax=bottom_right, uv_min=[.8851, 0],
                           uv_max=[.9235, .10], tag="sprite")
                add_data("sprite1", True)
        add_data("delta_draw_time", 0)
    else:
        add_data("delta_draw_time", delta_draw_time + get_delta_time())


set_main_window_size(650, 800)

with window("Tutorial"):
    add_drawing("Drawing_1", width=500, height=500)
    top_left = [250, 250]
    bottom_right = [300, 300]
    draw_image("Drawing_1", 'SpriteMapExample.png', top_left,
               pmax=bottom_right, uv_min=[.7687, 0], uv_max=[1, .10], tag="sprite")
    add_text("Fly Mode:")
    add_radio_button("Fly Mode", items=["Disable", "Enable"], default_value=0)
    add_slider_float("Draw Pause", default_value=0.1, min_value=0.0, max_value=0.5,
                     tip="slows down draws by waiting until the elapsed time", format="%.4f")
    set_render_callback(on_render)
    add_data("delta_draw_time", 0.0)
    add_data("sprite1", True)

start_dearpygui()

16 Tables

Dear PyGui 有一个简单的表格 API,非常适合静态和动态表格。表小部件通过调用 add_table() 启动。要编辑表窗口小部件,我们可以使用方法 add_row()add_column() 将行/列追加到表的最后一个插槽中。

或者,我们可以使用 insert_row insert_column 插入行/列。列和行根据其索引参数插入。如果指定的索引已经存在,则退出的列/行将被颠簸,新的行/列将被插入到指定的索引处。

默认情况下,添加或插入的行/列也将用空单元格填充未指定的单元格。

from dearpygui.core import *
from dearpygui.simple import *

with window("Tutorial"):
    add_table("Table Example", ["Header 0", "Header 1"])
    add_row("Table Example", ["row 0", "text"])
    add_row("Table Example", ["row 2", "text"])
    add_column("Table Example", "Header 3", ["data","data"])
    insert_row("Table Example", 1, ["row 1", "inserted row", "inserted row"])
    insert_column("Table Example", 2, "Header 2", ["inserted with column", "inserted column", "inserted column"])

start_dearpygui()

此外,标题和单元格可以重命名,其值也可以更改。

from dearpygui.core import *
from dearpygui.simple import *

def modify_tables(sender, data):
    log_debug(f"Table Called: {sender}")
    coord_list = get_table_selections("Table Example")
    log_debug(f"Selected Cells (coordinates): {coord_list}")
    for coordinates in coord_list:
        set_table_item("Table Example", coordinates[0], coordinates[1], "New Value")
    set_headers("Table Example", ["New Header 0", "New Header 1", "New Header 2"])


show_logger()

with window("Tutorial"):
    add_spacing(count=5)
    add_button("Modify Selected Table Values", callback=modify_tables)
    add_spacing(count=5)
    add_table("Table Example", ["Header 0", "Header 1"])
    add_row("Table Example", ["awesome row", "text"])
    add_row("Table Example", ["super unique", "unique text"])
    add_column("Table Example", "Header 2", ["text from column", "text from column"])
    add_row("Table Example", ["boring row"])

start_dearpygui()

表格单元是可选的。这意味着我们可以对表应用回调,并检索通过发送方选择的单元格,甚至获取单元格内的文本。

from dearpygui.core import *
from dearpygui.simple import *

def table_printer(sender, data):
    log_debug(f"Table Called: {sender}")
    coord_list = get_table_selections("Table Example")
    log_debug(f"Selected Cells (coordinates): {coord_list}")
    names = []
    for coordinates in coord_list:
        names.append(get_table_item("Table Example", coordinates[0], coordinates[1]))
    log_debug(names)


show_logger()

with window("Tutorial"):
    add_table("Table Example", ["Header 0", "Header 1"], callback=table_printer)
    add_row("Table Example", ["awesome row", "text"])
    add_row("Table Example", ["super unique", "unique text"])
    add_column("Table Example", "Header 3", ["text from column", "text from column"])
    add_row("Table Example", ["boring row"])

start_dearpygui()

17 Input Polling

Dear PyGui 中的 Input Polling 是通过在函数中调用所需的 polling 命令来完成的。该函数必须设置为 Windows 渲染回调,以便在该窗口处于活动状态时进行 polling。因为渲染回调在每帧都运行,所以如果执行指定的输入,Dear PyGui 可以在帧之间 polling。

所有 polling 的列表如下:

  • get_mouse_drag_delta()
  • get_mouse_pos()
  • is_key_down()
  • is_key_pressed()
  • is_key_released()
  • is_mouse_button_clicked()
  • is_mouse_button_double_clicked()
  • is_mouse_button_down()
  • is_mouse_button_dragging()
  • is_mouse_button_released()
  • set_key_down_callback()
  • set_key_press_callback()
  • set_key_release_callback()
  • set_mouse_click_callback()
  • set_mouse_double_click_callback()
  • set_mouse_down_callback()
  • set_mouse_drag_callback()
  • set_mouse_wheel_callback()
  • set_render_callback()
  • set_resize_callback()

有关特定命令的信息,请参阅 API Reference

可以根据需要组合任意数量的轮询以实现所需的功能。

from dearpygui.core import *
from dearpygui.simple import *

def main_callback(sender, data):
    set_value("Mouse Position", str(get_mouse_pos()))
    set_value("A key Down", is_key_down(mvKey_A))
    set_value("A key Pressed", is_key_pressed(mvKey_A))
    set_value("A key Released", is_key_released(mvKey_A))
    set_value("Left Mouse Dragging", is_mouse_button_dragging(mvMouseButton_Left, 10))
    set_value("Left Mouse Clicked", is_mouse_button_clicked(mvMouseButton_Left))
    set_value("Left Mouse Double Clicked", is_mouse_button_double_clicked(mvMouseButton_Left))
    set_value("Shift + Left Mouse Clicked", is_key_down(mvKey_Shift) and is_mouse_button_clicked(mvMouseButton_Left))

with window("Tutorial"):
    add_label_text("A key Down", color=[0, 200, 255])
    add_label_text("A key Pressed", color=[0, 200, 255])
    add_label_text("A key Released", color=[0, 200, 255])
    add_spacing()
    add_label_text("Mouse Position", color=[0, 200, 255])
    add_label_text("Left Mouse Clicked", color=[0, 200, 255])
    add_label_text("Left Mouse Dragging", color=[0, 200, 255])
    add_label_text("Left Mouse Double Clicked", color=[0, 200, 255])
    add_label_text("Shift + Left Mouse Clicked", color=[0, 200, 255])

set_render_callback(main_callback)

start_dearpygui()

18 多线程和异步功能

对于需要较长时间的计算和回调,实现异步功能或在单独线程上运行的功能可能很有用。为此,只需调用 run_async_function

重要的是要注意,用 async 命令运行的函数只能调用某些 Dear PyGui 命令(get_valueset_valueadd_dataget_data)。

from dearpygui.core import *
from dearpygui.simple import *
from time import sleep

def long_async_callback(data, sender):
    run_async_function(long_callback, None)

def long_callback(sender, data):
    sleep(3)

show_logger()
show_metrics()

with window("Tutorial"):
    add_button("long function", callback=long_callback, tip="This will cause a 3 second freeze")
    add_button("long Asynchronous Function", callback=long_async_callback, tip="This will not freeze")

start_dearpygui()

异步函数无法访问 add_dataget_data。因此,当有必要将数据传递给异步函数时,必须使用数据并返回带有关键字的处理程序参数。通过“data”关键字将任何 Python 对象发送到该函数中,即可使其可以通过 async 函数访问。此外,可以通过指定的返回回调的“data”输入来访问 Async 函数返回的任何数据。

from dearpygui.core import *
from dearpygui.simple import *
from time import sleep

def long_async_preparer(data, sender):
    floaty = get_value("Async Input Data")
    run_async_function(long_callback, floaty, return_handler=long_async_return)

def long_callback(sender, data):
    sleep(3)
    return data * 2

def long_async_return(sender, data):
    log_debug(data)

def long_callback2(sender, data):
    sleep(3)
    log_debug(data * 2)

show_logger()

with window("Tutorial"):
    add_text("Input a number and see the logger window for the output of the long callback that would normally freeze the GUI")
    add_input_float("Async Input Data", default_value=1.0)
    add_button("long Function", callback=long_callback2, callback_data=get_value("Async Input Data"), tip="This is the long callback that will freeze the GUI")
    add_button("long Asynchronous Function", callback=long_async_preparer, tip="This will not freeze the GUI")

start_dearpygui()

当调用异步函数方法时,将创建一个线程池。可以配置的线程池的方面是线程数和超时时间。

使用 set_thread_count 我们可以设置线程池中的线程数。同样,我们可以使用 set_threadpool_high_performance 来告诉线程池最大化每个用户计算机的线程数。请注意,调用异步函数时,这将使 CPU 以 100% 的速度运行。

可以使用 set_threadpool_timeout 设置线程池的超时时间。在设定的时间后,这将破坏线程池并释放资源。

19 主题和风格

有关更完整的示例,请参见 show_demo。主题和窗口小部件样式可以应用于单个窗口小部件或整个应用程序。可以设置的样式属性的一些示例是:

  • 字体大小
  • 应用配色方案
  • 圆角圆度

请参见以下示例:

from dearpygui.core import *
from dearpygui.simple import *

def apply_text_multiplier(sender, data):
    font_multiplier = get_value("Font Size Multiplier")
    set_global_font_scale(font_multiplier)

def apply_theme(sender, data):
    theme = get_value("Themes")
    set_theme(theme)

themes = ["Dark", "Light", "Classic", "Dark 2", "Grey", "Dark Grey", "Cherry", "Purple", "Gold", "Red"]

with window("Tutorial"):
    add_combo("Themes", items=themes, default_value="Dark", callback=apply_theme)

    add_slider_float("Font Size Multiplier", default_value=1.0, min_value=0.0, max_value=2.0,
                     callback=apply_text_multiplier)

start_dearpygui()

20 与其他框架集成

如果你对这款框架现有的功能还不满足。那么,它集成了其他 Python GUI 框架,你可以把它与其他框架结合在一起使用,例如:

from dearpygui.dearpygui import *
from tkinter import Tk, Label, Button

# tkinter
root = Tk()
root.title("A simple GUI")
root.button = Button(root, text="Press me")
root.button.pack()

# DearPyGui
add_slider_float("Slider")
add_button("Get Value", callback="button_callback")

setup_dearpygui()
whileTrue:
    render_dearpygui_frame()
    root.update()

cleanup_dearpygui()

在这个示例中,就把DearPyGui与tkinter结合在一起进行GUI开发。

总结

DearPyGui 是一款简单、开放、灵活的Python GUI框架,无论你是专业的开发人员,或者是满足日常工作的轻度使用用户,DearPyGui 都可以让你围绕它开发并构建一款简单、提升效率的系统。目前这款框架刚开源不久,但是,我个人认为非常值得尝试一下这款框架。

推荐阅读更多精彩内容