2025, Dec 11 21:01

Как правильно передать user_data в колбэк Dear PyGui

Почему в колбэк Dear PyGui приходит тег sender вместо user_data, и как это исправить. Пояснение сигнатуры (sender, app_data, user_data) и минимальный пример.

Передача данных в UI‑колбэки кажется простым делом, пока ожидаемое значение не оказывается другим. В Dear PyGui частая ловушка — при использовании user_data в вывод попадает тег кнопки вместо вашего полезного объекта. Причина не в том, как вы прикрепляете данные, а в сигнатуре функции‑обработчика.

Минимальный пример, воспроизводящий проблему

В этом фрагменте к каждой кнопке привязывается колбэк и передаётся целочисленный индекс через user_data. В итоге на печать выходит тег кнопки, а не сам индекс.

import dearpygui.dearpygui as dpg
for idx in range(N):
    with dpg.group(horizontal=True):
        dpg.add_button(label="add", tag="btn_add_" + str(idx))
        dpg.set_item_callback(item="btn_add_" + str(idx), callback=on_add_click)
        dpg.set_item_user_data(item="btn_add_" + str(idx), user_data=idx)
def on_add_click(payload):
    print(f"on_add_click: {payload}")

Что на самом деле происходит

Dear PyGui передаёт в колбэк три позиционных аргумента: sender, app_data и user_data. Если функция объявлена с одним параметром, он получает первый аргумент — sender. Для кнопки sender — это её тег. Поэтому в выводе вы видите что-то вроде btn_add_0 вместо целого числа, которое пытались передать.

Такое поведение библиотеки описано в официальном руководстве по колбэкам элементов: https://dearpygui.readthedocs.io/en/latest/documentation/item-callbacks.html.

Как исправить

Объявите обработчик с тремя параметрами, чтобы третий получил переданный вами user_data. Если sender и app_data не нужны, их можно игнорировать.

def on_add_click(sender, app_data, payload):
    print(f"on_add_click: {payload}")

Можно сразу задать callback и user_data при создании элемента, обойдясь без отдельных вызовов сеттеров.

import dearpygui.dearpygui as dpg
def on_add_click(sender, app_data, payload):
    print(f"on_add_click: {payload}")
for idx in range(N):
    with dpg.group(horizontal=True):
        dpg.add_button(
            label="add",
            tag="btn_add_" + str(idx),
            callback=on_add_click,
            user_data=idx,
        )

Почему это важно

Знание точной сигнатуры колбэка экономит время и избавляет от скрытых ошибок, когда по логике незаметно проходит не то значение. Это снижает путаницу при отладке поведения интерфейса и делает обработку событий предсказуемой. Как только сигнатура функции соответствует соглашению вызова Dear PyGui, user_data ведёт себя стабильно — будь то целочисленный индекс или любая другая полезная нагрузка.

Выводы

Если в колбэке Dear PyGui вы собираетесь использовать user_data, объявляйте функцию с тремя позиционными параметрами: sender, app_data и user_data. Печатайте или обрабатывайте только третий, если вам нужен лишь он. Для аккуратности кода callback и user_data удобно передавать прямо в add_button — это равноценно установке через отдельные вызовы.