DearPyGui:一個(gè)簡(jiǎn)單的 Python GUI 工具箱

Dear PyGui:針對(duì) Python 的無(wú)膨脹(Bloat-free)圖形用戶界面,具有最小的依賴性,托管在 hoffstadt/DearPyGui。

Dear PyGui 是一個(gè)易于使用(但功能強(qiáng)大)的 Python GUI 框架。Dear PyGui 提供了 Dear ImGui 的包裝,該包裝模擬了傳統(tǒng)的保留(retained)模式 GUI(與 Dear ImGui 的立即(immediate)模式范例相反)。

Dear PyGui 與其他 Python GUI 框架從根本上不同。在后臺(tái),Dear PyGui 使用即時(shí)模式范例和計(jì)算機(jī)的 GPU 來(lái)實(shí)現(xiàn)極為動(dòng)態(tài)的界面。下列平臺(tái)當(dāng)前支持 Dear PyGui:

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

Dear ImGui 以相同的方式為游戲開(kāi)發(fā)人員提供了一種創(chuàng)建工具的簡(jiǎn)單方法,Dear PyGui 則提供了一種方便Python 開(kāi)發(fā)人員為腳本創(chuàng)建快速而強(qiáng)大的 GUI 的簡(jiǎn)單方法。

與其他 Python GUI 庫(kù)相比,Dear PyGui 具有以下獨(dú)特之處:

  • GPU 渲染
  • 簡(jiǎn)單的內(nèi)置異步功能支持
  • 完整的主題和樣式控制
  • 簡(jiǎn)單的內(nèi)置日志窗口
  • 70多個(gè)小部件具有數(shù)百種小部件組合
  • 詳細(xì)的文檔,示例和無(wú)與倫比的支持

安裝(支持Python3.6 以上):pip install dearpygui??梢栽?Github 上的 Examples 文件夾中找到各種演示用法的示例。使用show_documentation() 命令可以在此處找到文檔,也可以從庫(kù)中找到文檔。

使用 Dear PyGui 很簡(jiǎn)單,就像創(chuàng)建下面的 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()

顯示:

接下來(lái),看看如何使用 Dear PyGui ("DPG")。

1 概覽

Dear PyGui 由視口(viewport),窗口(windows)和小部件(widgets)組成。視口是程序的主窗口,通過(guò)調(diào)用函數(shù) start_dearpygui 創(chuàng)建。

下面是視口和一個(gè)窗口的示例,其中顯示了使用內(nèi)置文檔函數(shù)的文檔:

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 當(dāng)前由兩個(gè)模塊 dearpygui.coredearpygui.simple 組成。dearpygui.core 包含 Dear PyGui 的核心功能。其他所有內(nèi)容都建立在 core 之上(包括 simple)。

dearpygui.simple 包含簡(jiǎn)單的包裝程序和其他從核心創(chuàng)建的實(shí)用程序,以提供與 DPG 更為友好的接口。隨著代碼復(fù)雜度的增加,建議在適用時(shí)開(kāi)始使用 simple 模塊。

在整個(gè)教程中,我們將使用推薦的過(guò)程來(lái)完成各種任務(wù)。這將包括 core 功能和 simple 功能。

2 開(kāi)發(fā)者工具

Dear PyGui 包含幾個(gè)有用的開(kāi)發(fā)人員工具,我們將在整個(gè)教程中使用它們。

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

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

start_dearpygui()

3 內(nèi)置的日志功能

記錄器(Logger)是眾多強(qiáng)大的內(nèi)置開(kāi)發(fā)人員工具之一??梢酝ㄟ^(guò)命令 show_logger 進(jìn)行訪問(wèn)。記錄器有 6 個(gè)日志級(jí)別:

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

看一個(gè)例子:

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 創(chuàng)建小部件和容器

DPG 項(xiàng)可以細(xì)分為:

  • 常規(guī)項(xiàng)目(即 inputs, buttons)
  • 容器項(xiàng)目(例如,window, popup, tooltip, child)
  • 布局項(xiàng)(即 group, next_column)

項(xiàng)將使用其各自的 add _***命令添加。

每個(gè)項(xiàng)必須具有唯一的名稱。默認(rèn)情況下,名稱將成為標(biāo)簽(如果適用)。如果您想更改小部件的標(biāo)簽,可以:

  • 放到名稱的尾部的“##”(例如"displayed_name##unique_part")后面的名稱將從顯示的名稱中隱藏。
  • 使用 label 關(guān)鍵字將顯示標(biāo)簽而不是項(xiàng)名稱。

對(duì)于在函數(shù)中沒(méi)有名稱參數(shù)的項(xiàng),將自動(dòng)生成某些項(xiàng)名稱。(即 same_line)。但是,它們有一個(gè)可選的 name 關(guān)鍵字,如果以后需要引用該項(xiàng)目,則可以填寫該關(guān)鍵字。

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

容器項(xiàng)用于容納其他項(xiàng),并且可由任一項(xiàng)實(shí)現(xiàn):

  • 使用 add _*** 函數(shù)啟動(dòng)容器,然后 end 函數(shù)完成。
  • 使用 dearpygui.simple 和相應(yīng)的容器上下文管理器(推薦方法)。

當(dāng)容器項(xiàng)“added”時(shí),它們被推入父堆棧。之后添加的任何項(xiàng)目都將屬于堆棧頂部的父項(xiàng)。當(dāng)容器項(xiàng)“ended”時(shí),它們將從父堆棧彈出。

dearpygui.simple 的上下文管理器自動(dòng)調(diào)用 end 函數(shù),并允許代碼折疊并在代碼本身中顯示層次結(jié)構(gòu)。

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

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

start_dearpygui()

默認(rèn)情況下,項(xiàng)按提交順序創(chuàng)建。但是,可以通過(guò)指定 parent 容器來(lái)無(wú)序添加項(xiàng)目。使用 parent 關(guān)鍵字會(huì)將小部件插入到父級(jí)的子級(jí)列表的末尾。如果您想將其插入其他位置,請(qǐng)?jiān)谂c parent 關(guān)鍵字組合使用 before 之前,將該項(xiàng)目放在 parent 容器中另一個(gè)項(xiàng)目之前。

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 關(guān)鍵字或使用 set_primary_window 命令將窗口設(shè)置為主窗口(即視口)。

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 使用小部件

每個(gè)輸入窗口小部件都有一個(gè)值,該值可以在運(yùn)行時(shí)通過(guò)命令 set_value 設(shè)置,或創(chuàng)建時(shí)使用 default_value 關(guān)鍵字設(shè)置。

要訪問(wèn)小部件的值,我們可以使用命令 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 小部件和窗口回調(diào)

每個(gè)輸入窗口小部件都有一個(gè)回調(diào),在與窗口小部件交互時(shí)會(huì)運(yùn)行該回調(diào)。

回調(diào)用于為小部件提供功能。回調(diào)可以在創(chuàng)建時(shí)使用 callback 或在創(chuàng)建后使用 set_item_callback 分配給窗口小部件。在 Dear PyGui 中,應(yīng)用于項(xiàng)目的每個(gè)回調(diào)都必須包含一個(gè) senderdata 參數(shù)。

Dear PyGui 使用 sender 參數(shù)通過(guò)發(fā)送名稱來(lái)通知回調(diào)哪個(gè)窗口小部件觸發(fā)了回調(diào)。

各種標(biāo)準(zhǔn)回調(diào)使用 data 參數(shù)通過(guò)指定回調(diào) callback_data 來(lái)發(fā)送其他數(shù)據(jù)。

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

每次與小部件進(jìn)行交互時(shí),我們都可以使用回調(diào)來(lái)更新 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() 

但是通過(guò)使用 sender 會(huì)是更聰明的方法:

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

窗口類型的窗口小部件具有特殊的回調(diào),這些回調(diào)在諸如窗口大小調(diào)整和窗口關(guān)閉之類的事件上觸發(fā)。特定于窗口的回調(diào)可以應(yīng)用于任何窗口類型的小部件。on_close 將在窗口關(guān)閉時(shí)運(yùn)行分配給關(guān)鍵字的回調(diào),set_resize_callback 將在容器的每次調(diào)整大小時(shí)運(yùn)行,并且可以使用 handler 關(guān)鍵字設(shè)置為任何特定窗口,默認(rèn)值為“MainWindow”。

如果您希望每幀都執(zhí)行一次回調(diào),則可以使用 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 運(yùn)行時(shí)添加和刪除小部件

借助 Dear PyGui,您可以在運(yùn)行時(shí)(Run-time)動(dòng)態(tài)添加和刪除任何項(xiàng)。這可以通過(guò)使用回調(diào)來(lái)運(yùn)行所需項(xiàng)的 add _*** 命令并指定該項(xiàng)目所屬的父項(xiàng)來(lái)完成。默認(rèn)情況下,如果未指定父項(xiàng),則將小部件添加到MainWindow

通過(guò)在添加項(xiàng)之前使用關(guān)鍵字,您可以控制新項(xiàng)位于父項(xiàng)中的哪個(gè)項(xiàng)目之前。默認(rèn)將新的小部件放在最后。

在此示例中,我們使用“debug”開(kāi)發(fā)人員工具來(lái)查看小部件的當(dāng)前狀態(tài)。轉(zhuǎn)到調(diào)試窗口小部件上的“App Item Layout”選項(xiàng)卡,此選項(xiàng)卡顯示應(yīng)用程序的狀態(tài)和屬性。單擊“MainWindow”樹(shù)項(xiàng),我們可以看到 MainWindow 當(dāng)前顯示的小部件。嘗試單擊主窗口上的“Add/Delete”按鈕,然后查看樹(shù)的狀態(tài)更改。

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

刪除容器時(shí),默認(rèn)情況下會(huì)刪除容器及其子級(jí),除非關(guān)鍵字 children_only 設(shè)置為 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 值與數(shù)據(jù)存儲(chǔ)

添加新的窗口小部件時(shí),會(huì)將值添加到值存儲(chǔ)系統(tǒng)。默認(rèn)情況下,此值的標(biāo)識(shí)符是小部件的名稱。您可以使用 source 關(guān)鍵字覆蓋標(biāo)識(shí)符。這樣做的好處之一是讓多個(gè)小部件控制相同的值。

使用 get_value 從值系統(tǒng)檢索值。可以使用 set_value 手動(dòng)更改值。

為了使不同值類型的小部件在存儲(chǔ)系統(tǒng)中使用相同的值,必須首先創(chuàng)建較大的值。

例如,創(chuàng)建 input_float3 時(shí),存儲(chǔ)的值類型為 [float, float, float]。稍后創(chuàng)建的 input_float2 可以使用與 input_float3 相同的源。但是,如果先創(chuàng)建了 input_float2,然后嘗試與 input_float3 共享其源,則它將不起作用。為了使 input_float3input_float2 共享同一源,我們可以創(chuàng)建 input_float3,需要首先創(chuàng)建。這是通過(guò) 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 還提供用于數(shù)據(jù)存儲(chǔ)的常規(guī)數(shù)據(jù)。使用 add_data,我們可以傳入任何 Python 項(xiàng)以將其存儲(chǔ)為數(shù)據(jù)項(xiàng),并稍后使用 get_data("name") 進(jìn)行訪問(wèn)。請(qǐng)記住,您可以將任何 Python 對(duì)象存儲(chǔ)在數(shù)據(jù)存儲(chǔ)中,甚至可以存儲(chǔ)自定義數(shù)據(jù)類型。

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 功能的一個(gè)非常重要的小部件是菜單欄(Menu Bar)。菜單欄始終顯示在窗口頂部,并具有3個(gè)主要部分:

  1. 菜單欄:主菜單功能區(qū)
  2. 菜單:下拉菜單“子菜單”
  3. 菜單項(xiàng):可以運(yùn)行回調(diào)的項(xiàng)目(基本上是可選的)

菜單欄從右到左添加項(xiàng)。菜單從上到下添加項(xiàng)。菜單可以根據(jù)需要嵌套。任何小部件都可以添加到菜單中。

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 文件和目錄選擇器對(duì)話框

通過(guò)調(diào)用 select_directory_dialog 使用目錄對(duì)話框,必須為其提供 return 回調(diào)。return 回調(diào)的 data 參數(shù)將用目錄路徑和文件夾路徑作為字符串列表填充。

通常,目錄對(duì)話框由另一個(gè)小部件(例如按鈕)調(diào)用,因此示例中將采用這種方式。

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

通過(guò)調(diào)用 open_file_dialog 使用文件對(duì)話框,必須為其提供 return 回調(diào)。return 回調(diào)的 data 參數(shù)將用目錄路徑和文件路徑填充為字符串列表。擴(kuò)展名是文件對(duì)話框的可選關(guān)鍵字,它將提供選擇以根據(jù)其擴(kuò)展名過(guò)濾對(duì)話框中顯示的文件。

通常,文件對(duì)話框是由另一個(gè)小部件(例如按鈕)調(diào)用的,因此示例中將采用這種方式。

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,它們都具有動(dòng)態(tài)能力。simple plots 將獲取列表,并針對(duì)列表中的項(xiàng)目數(shù)繪制 y 軸數(shù)據(jù)。這些可以是折線圖或直方圖,如下所示。

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 同時(shí)使用 x 和y坐標(biāo)。必須使用 add_plot 命令創(chuàng)建圖,然后可以將數(shù)據(jù)作為線系列或散布系列添加。plots 的特點(diǎn)是:

  • 單擊并拖動(dòng):平移圖
  • 單擊并拖動(dòng)Axis:在一個(gè)方向上平移圖
  • 雙擊:將圖縮放為數(shù)據(jù)
  • 右鍵單擊并拖動(dòng):縮放到某個(gè)區(qū)域
  • 雙擊右鍵:打開(kāi)設(shè)置
  • Shift +右鍵單擊并拖動(dòng):放大到填充當(dāng)前軸的區(qū)域
  • 滾動(dòng)鼠標(biāo)滾輪:縮放
  • 在軸上滾動(dòng)鼠標(biāo)滾輪:僅縮放該軸
  • 切換圖例上的數(shù)據(jù)集以隱藏它們

另外,可以使用文本點(diǎn)將浮動(dòng)文本放置在繪圖上。

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

通過(guò)使用 set_value 更改繪圖調(diào)用的值,可以使 Simple plots 變得動(dòng)態(tài)。如下所示。

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 也可以是動(dòng)態(tài)的。可以使用動(dòng)態(tài)功能,就像清除圖并使用回調(diào)(例如渲染或項(xiàng)目的回調(diào))添加新數(shù)據(jù)一樣容易。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 有一個(gè)低級(jí)繪圖 API,非常適合原始繪圖,自定義小部件甚至動(dòng)態(tài)繪圖。通過(guò)調(diào)用 add_drawing 開(kāi)始繪制,然后可以通過(guò)調(diào)用其各自的繪制命令來(lái)添加項(xiàng)目。畫布的原點(diǎn)在左上方,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 繪制圖像。使用關(guān)鍵字“pmin”和“pmax”,我們可以定義將圖像繪制到畫布上的矩形的左上和右下區(qū)域。圖像將縮放以適合指定區(qū)域。使用關(guān)鍵字“uv_min”和“uv_max”,我們可以定義應(yīng)在畫布上繪制圖像的哪個(gè)區(qū)域的標(biāo)量。uv_min = [0,0]uv_max = [1,1] 的默認(rèn)值將顯示整個(gè)圖像,而 uv_min = [0,0] uv_max = [0.5,0.5] 的默認(rèn)值僅顯示圖形的第一部分。

為了演示這些功能,您必須將目錄更新為計(jì)算機(jī)上圖像的目錄,例如 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()

盡管可以通過(guò)清除和重繪整個(gè)圖來(lái)使圖形動(dòng)態(tài)化,但仍提供了一種更有效的方法。

為了使繪圖動(dòng)態(tài),我們應(yīng)該使用 tag 關(guān)鍵字標(biāo)記要重繪的項(xiàng)目。然后,只需使用相同的標(biāo)簽調(diào)用繪制命令即可。這將僅刪除該一項(xiàng),并使用新命令將其重新繪制。

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 增量時(shí)間和內(nèi)部時(shí)鐘

Dear PyGui 有一個(gè)內(nèi)置時(shí)鐘,用于檢查總運(yùn)行時(shí)間 get_total_time,該時(shí)間以秒為單位返回總運(yùn)行時(shí)間。同樣使用命令 get_delta_time(),我們可以檢查渲染幀之間的時(shí)間(以秒為單位)。

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 和回調(diào)在渲染時(shí)運(yùn)行,我們可以創(chuàng)建一個(gè)精靈字符(sprite character)。對(duì)于此示例,我們需要從 GitHub 上的 examples 文件夾下載 SpriteMapExample.png 并將其放置在工作目錄中的 Python 文件旁邊。

通過(guò)調(diào)用 add_drawing 開(kāi)始繪制,然后可以通過(guò)調(diào)用其各自的繪制命令來(lái)添加項(xiàng)目。畫布的原點(diǎn)在左下方。

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 有一個(gè)簡(jiǎn)單的表格 API,非常適合靜態(tài)和動(dòng)態(tài)表格。表小部件通過(guò)調(diào)用 add_table() 啟動(dòng)。要編輯表窗口小部件,我們可以使用方法 add_row(),add_column() 將行/列追加到表的最后一個(gè)插槽中。

或者,我們可以使用 insert_row insert_column 插入行/列。列和行根據(jù)其索引參數(shù)插入。如果指定的索引已經(jīng)存在,則退出的列/行將被顛簸,新的行/列將被插入到指定的索引處。

默認(rèn)情況下,添加或插入的行/列也將用空單元格填充未指定的單元格。

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

此外,標(biāo)題和單元格可以重命名,其值也可以更改。

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

表格單元是可選的。這意味著我們可以對(duì)表應(yīng)用回調(diào),并檢索通過(guò)發(fā)送方選擇的單元格,甚至獲取單元格內(nèi)的文本。

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 是通過(guò)在函數(shù)中調(diào)用所需的 polling 命令來(lái)完成的。該函數(shù)必須設(shè)置為 Windows 渲染回調(diào),以便在該窗口處于活動(dòng)狀態(tài)時(shí)進(jìn)行 polling。因?yàn)殇秩净卣{(diào)在每幀都運(yùn)行,所以如果執(zhí)行指定的輸入,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()

有關(guān)特定命令的信息,請(qǐng)參閱 API Reference

可以根據(jù)需要組合任意數(shù)量的輪詢以實(shí)現(xiàn)所需的功能。

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 多線程和異步功能

對(duì)于需要較長(zhǎng)時(shí)間的計(jì)算和回調(diào),實(shí)現(xiàn)異步功能或在單獨(dú)線程上運(yùn)行的功能可能很有用。為此,只需調(diào)用 run_async_function。

重要的是要注意,用 async 命令運(yùn)行的函數(shù)只能調(diào)用某些 Dear PyGui 命令(get_value,set_value,add_data,get_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()

異步函數(shù)無(wú)法訪問(wèn) add_dataget_data。因此,當(dāng)有必要將數(shù)據(jù)傳遞給異步函數(shù)時(shí),必須使用數(shù)據(jù)并返回帶有關(guān)鍵字的處理程序參數(shù)。通過(guò)“data”關(guān)鍵字將任何 Python 對(duì)象發(fā)送到該函數(shù)中,即可使其可以通過(guò) async 函數(shù)訪問(wèn)。此外,可以通過(guò)指定的返回回調(diào)的“data”輸入來(lái)訪問(wèn) Async 函數(shù)返回的任何數(shù)據(jù)。

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

當(dāng)調(diào)用異步函數(shù)方法時(shí),將創(chuàng)建一個(gè)線程池??梢耘渲玫木€程池的方面是線程數(shù)和超時(shí)時(shí)間。

使用 set_thread_count 我們可以設(shè)置線程池中的線程數(shù)。同樣,我們可以使用 set_threadpool_high_performance 來(lái)告訴線程池最大化每個(gè)用戶計(jì)算機(jī)的線程數(shù)。請(qǐng)注意,調(diào)用異步函數(shù)時(shí),這將使 CPU 以 100% 的速度運(yùn)行。

可以使用 set_threadpool_timeout 設(shè)置線程池的超時(shí)時(shí)間。在設(shè)定的時(shí)間后,這將破壞線程池并釋放資源。

19 主題和風(fēng)格

有關(guān)更完整的示例,請(qǐng)參見(jiàn) show_demo。主題和窗口小部件樣式可以應(yīng)用于單個(gè)窗口小部件或整個(gè)應(yīng)用程序??梢栽O(shè)置的樣式屬性的一些示例是:

  • 字體大小
  • 應(yīng)用配色方案
  • 圓角圓度

請(qǐng)參見(jiàn)以下示例:

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 與其他框架集成

如果你對(duì)這款框架現(xiàn)有的功能還不滿足。那么,它集成了其他 Python GUI 框架,你可以把它與其他框架結(jié)合在一起使用,例如:

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

在這個(gè)示例中,就把DearPyGui與tkinter結(jié)合在一起進(jìn)行GUI開(kāi)發(fā)。

總結(jié)

DearPyGui 是一款簡(jiǎn)單、開(kāi)放、靈活的Python GUI框架,無(wú)論你是專業(yè)的開(kāi)發(fā)人員,或者是滿足日常工作的輕度使用用戶,DearPyGui 都可以讓你圍繞它開(kāi)發(fā)并構(gòu)建一款簡(jiǎn)單、提升效率的系統(tǒng)。目前這款框架剛開(kāi)源不久,但是,我個(gè)人認(rèn)為非常值得嘗試一下這款框架。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容