← Back to skills
extension
Category: Development & EngineeringAPI key requirement unconfirmed

Wiring UMG List Item Action Buttons

Wire action buttons on UMG list item widgets (FriendListItem, EnemyListItem, etc.) with delegates, UFUNCTION handlers, and list-level event forwarding"

personAuthor: Sxgx123hubOpenAPI

Wiring UMG List Item Action Buttons

Pattern for adding action buttons (传音/造访/屏蔽 etc.) to list item widgets:

1. Item Widget Header (.h)

// Delegate declaration above class
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnXxxActionClicked, const FString&, UserID);

// Public UPROPERTY
UPROPERTY(BlueprintAssignable, Category = "Social|Xxx")
FOnXxxActionClicked OnActionRequested;

// Protected UFUNCTION handler
UFUNCTION()
void HandleActionClicked();

2. Item Widget CPP (.cpp)

// NativeConstruct: bind button
if (ActionBtn)
{
    ActionBtn->OnXxxButtonClicked.AddUniqueDynamic(this, &UWidgetClass::HandleActionClicked);
}

// Handler: broadcast user ID
void UWidgetClass::HandleActionClicked()
{
    OnActionRequested.Broadcast(CachedData.UserID);
}

3. List Widget Header (.h)

UFUNCTION()
void HandleActionRequested(const FString& UserID);

4. List Widget CPP (.cpp) — Subscribe in RebuildRows/FilterChanged

Entry->OnActionRequested.AddDynamic(this, &UListClass::HandleActionRequested);

5. Local-state toggle (BlockBtn pattern)

For buttons that toggle local state (e.g., block/unblock):

void HandleBlockClicked()
{
    CachedData.bIsBlocked = !CachedData.bIsBlocked;
    if (BlockBtn)
    {
        BlockBtn->SetButtonText(FText::FromString(
            CachedData.bIsBlocked ? TEXT("解除屏蔽") : TEXT("屏蔽")));
    }
    OnBlockToggled.Broadcast(CachedData.UserID);
}

Notes

  • Avoid SWAP edit for inserting UPROPERTY blocks — always use INS.POST or rewrite the full section. SWAP eats adjacent declarations.
  • For "暂无功能" buttons, just log and return.

Decoupling UI from gameplay with multicast delegates

An item/widget action button should not call gameplay systems (or the PlayerController) directly. Declare a dynamic multicast delegate on the widget, broadcast it where the action happens, and let the owner subscribe — the widget stays reusable, and the gameplay side stays testable.

// .h — on the widget
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnSettingsClosed);

UCLASS()
class XXX_API UMySettingsUI : public UUserWidget
{
    GENERATED_BODY()
public:
    UPROPERTY(BlueprintAssignable, Category = "Settings")
    FOnSettingsClosed OnSettingsClosed;
};

// .cpp — broadcast at the action site
void UMySettingsUI::CloseSettings()
{
    OnSettingsClosed.Broadcast();
    RemoveFromParent();
}

// owner side — bind after creating the widget
SettingsWidget = CreateWidget<UMySettingsUI>(GetWorld(), SettingsWidgetClass);
if (SettingsWidget)
{
    SettingsWidget->OnSettingsClosed.AddDynamic(this, &AMyPlayerController::OnSettingsUIClosed);
    SettingsWidget->AddToViewport();
}

Notes:

  • AddDynamic requires the handler to be a UFUNCTION(); a plain member function gives a compile error or a runtime crash.
  • BlueprintAssignable keeps the same event usable from Blueprints; drop it if only C++ binds.
  • The same shape works for list items: broadcast per-item events up to the list widget, which re-emits them for the owning screen (see the forwarding pattern above).