Updates made to the DesiredFocusWidget property of a widget do not seem to propagate to existing instances of that widget inside other widgets. See the repro steps for details on the issue.
I put a breakpoint inside UUserWidget::NativeOnFocusReceived and noticed that when the issue was happening, DesiredFocusWidget had a ‘None’ WidgetName and an empty WidgetPtr. After reinstancing the widget in the hierarchy, DesiredFocusWidget resolves to the appropriate widget at runtime as expected.
As it stands relying on DesiredFocusWidget for focus forwarding feels risky and error-prone, and probably affects whether the internal button is focused within UCommonButtonBase::Initialize.
Hi Joel,
Thank you for the report and repro steps. I was able to repro this issue here on UE 5.5 up to the latest source version. One thing I noticed is that restarting the editor, or better yet simply reloading the parent widget asset (right click on content browser -- asset actions -- reload) seems to fix the problem. For example, if you change “DesiredFocusWidget” for WidgetB, just reload WidgetA’s asset. Let me know if that works for you!
I’ll now do a preliminary investigation on the problem to see if there is an easy source-code fix, and then file an internal bug report for the engine devs to take a look. I should get back to you soon with a tracking number for the bug report.
Best regards,
Vior
Hi Joel,
After an initial investigation of this issue, I have come up with a source-code change that might serve as a temporary workaround for you. Look for function UUserWidget::PostEditChangeProperty() in file [Engine\Source\Runtime\UMG\Private\UserWidget.cpp]. You’ll find the following lines:
// We cannot use the Widget Ptr as we need to find the widget with the same name in the CDO
UserWidgetCDO->SetDesiredFocusWidget(DesiredFocusWidget.GetFName());
Please try changing that code to the following:
// We cannot use the Widget Ptr as we need to find the widget with the same name in the CDO
UserWidgetCDO->SetDesiredFocusWidget(DesiredFocusWidget.GetFName());
// Manually propagate the change to all instances of the CDO, including those inside the
// WidgetTree of other widgets. This assumes that all instances of the widget have this
// property in sync with the CDO at all times (no overrides).
TArray<UObject*> ArchetypeInstances;
UserWidgetCDO->GetArchetypeInstances(ArchetypeInstances);
for (UObject* ArchetypeInstance : ArchetypeInstances)
{
((UUserWidget*)ArchetypeInstance)->SetDesiredFocusWidget(DesiredFocusWidget.GetFName());
}
The change above is somewhat hacky, but it seems to work in my tests so far. If you try it, please let me know how it goes.
In reality, this propagation should be done in function PropagateDefaultPropertyChange(), which is called by FWidgetBlueprintEditor::MigrateFromChain() in file [Engine\Source\Editor\UMGEditor\Private\WidgetBlueprintEditor.cpp]. However, the current code is not working because it assumes that the CDO has not been changed yet (see comments inside FWidgetBlueprintEditor::MigrateFromChain()). The special handling done in UUserWidget::PostEditChangeProperty(), which intends to cope with the fact that each WidgetTree contains a different instance of the same widget, ends up violating this assumption and de-syncing the property between the CDO and its instances.
In any case, I have filed an internal bug report so that the engine devs that own this system can take a close look. Here’s the tracking number for it: UE-353920. The link should become accessible once the devs mark it as public.
Let me know if you need any further assistance.
Best regards,
Vitor
Hey Vitor! Restarting the editor and reloading the asset didn’t appear to resolve the issue for me, but maybe I was trying it with a weird setup.
That said, the fix you provided seems to work! I’ll have that integrated right away, thank you 