Error trying to implement Rich Text UMG widget

Greetings to everyone. I’m trying to implement rich text UMG widget basing on experimental things in UE 4.11. It works when I’m using default decorator, created as default subobject in widget’s constructor (or when decorators array is cleared and then reset to default):

Decorators.Add(ObjectInitializer.CreateDefaultSubobject<URichTextWidgetDecorator>(this, FName("DefaultDecorator")));

Here is screenshot.

But when I’m trying to change decorators (add new one or change existing), Editor fails to create new instance and I’m getting this error in log:

LogProperty:Warning: Illegal TEXT reference to a private object in external package (RichTextWidgetDecorator /Engine/Transient.World_6:TestWidget_C_5.WidgetTree_25.RichTextWidget_5.DefaultDecorator) from referencer (RichTextWidget /Game/UI/Widgets/TestWidget.TestWidget:WidgetTree.RichTextWidget_5).  Import failed...

I don’t understand why editor says that decorator is private object in external package. Have any clues how to make it work? I’m attaching project in zip archive if someone would like to help.

[Project Source and Content][2]

Have you solved it ?

I did not. Actually, I think that some one else has made something like that, saw a package on the Market.

It seems to a bug of ‘Instanced’ property used with URichTextBlock::Decorators. I don’t know why the error message’s saying ‘external package’, but the error is caused because of Decorators property is not AllowCrossLevel. And AllowCrossLevel is true only on UAssetObjectProperty which is pointing an uasset. So URichTextBlockDecorator doesn’t seem to fit to be an Instanced property.

Anyway, I don’t have a way to resolve the root cause, but have an workaround to avoid this error. You need to modify your engine code like below.


RichTextBlock.h

  • Make Decorators property be only Transient to avoid serializing it.

  • Add another property to store classes of decorator instead of their instance. DecoratorClasses is that one in following code sample.

    UPROPERTY(EditAnywhere, Category = Decorators)
    TArray<TSubclassOf> DecoratorClasses;

    UPROPERTY(Transient)
    TArray<class URichTextBlockDecorator*> Decorators;


RichTextBlock.cpp

  • Remove the line adding a default instance of URichTextBlockDecorator as a subobject in constructor.

  • Add a line to add a default class in DecoratorClasses instead of the line what we removed.

  • Create decorator instances in RebuildWidget with classes contained in DecoratorClasses before iterating Decorators array.

    URichTextBlock::URichTextBlock(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
    {
    // FONT AND COLOR INITIALIZATION…

     //Decorators.Add(ObjectInitializer.CreateOptionalDefaultSubobject<URichTextBlockDecorator>(this, FName("DefaultDecorator")));
     DecoratorClasses.Add(URichTextBlockDecorator::StaticClass());
    

    }

    TSharedRef URichTextBlock::RebuildWidget()
    {
    Decorators.Empty();
    for (auto DecoratorClass : DecoratorClasses)
    {
    Decorators.Add(NewObject(this, DecoratorClass));
    }

     // ORIGINAL CODE THAT ITERATE Decorators ARRAY AND FILLING CreatedDecorators
     // ORIGINAL CODE THAT CREATE A SRichTextBlock INSTANCE.
    

    }

This will work.

Note that there’s a limitation raised by storing classes instead of instances. When storing instances, we could modify decorators property within editor detail panel in-line. But by storing class, it’s not possible. So if you need to modify properties of your own decorators, you need to create a blueprint class that inherits your decorator, and modify it’s default properties in detail panel of the created blueprint. And then, add the blueprint class instead of the decorator class(maybe a c++ class) to URichTextBlock::DecoratorClasses. Don’t forget to make ‘Blueprintable’ your decorator class in this case.

Cheers.