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:
AddDynamicrequires the handler to be aUFUNCTION(); a plain member function gives a compile error or a runtime crash.BlueprintAssignablekeeps 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).
Scan to join WeChat group