Как привязать к OnItemSelectionChanged представления списка - PullRequest
0 голосов
/ 03 июня 2019

В Unreal Engine 4 я хочу привязать событие к UListView::OnItemSelectionChanged.Это событие FOnItemSelectionChanged требует NullableItemType, поэтому я передаю указатель на класс записи списка представления списка (мой пользовательский класс, полученный из IUserObjectListEntry) в качестве параметра.

UCLASS()
class PROJECT_API UMyListViewEntry : public UUserWidget, public IUserObjectListEntry
{
    GENERATED_BODY()
    // Members and functions don't matter here.
};

UCLASS()
class PROJECT_API UMyUserWidget : public UUserWidget
{
    GENERATED_BODY()
    void NativeConstruct() final
    {
        MyList->OnItemSelectionChanged.AddDynamic(this, &UMyUserWidget::MyEventCallback);
    }
    void MyEventCallback(UMyListViewEntry* e)
    {
        // implementation details
    }
private:
    UPROPERTY(meta = (BindWidget))
    UListView* MyList;
};

Однаковызов AddDynamic() вызывает ошибку

C2228: Слева от ".__ Internal_AddDynamic" должен быть класс / структура / объединение

, поэтому, я полагаю,подпись функции обратного вызова, которую я хочу связать (MyEventCallback()), неверна.

Какая будет правильная подпись для функции, которая должна быть связана с UListView::OnItemSelectionChanged?

1 Ответ

0 голосов
/ 07 июня 2019

Речь идет не только о подписи обратного вызова, но и о том, как добавить обратный вызов.

Опция # 1: Использовать возвращаемое значение OnItemSelectionChanged (обратный вызов будет ограничен UObject)

В UListView его член OnItemSelectionChanged реализован с помощью макроса IMPLEMENT_TYPED_UMG_LIST, который выполняет

virtual FOnItemSelectionChanged& OnItemSelectionChanged() const override { return OnItemSelectionChangedEvent; }

Таким образом, чтобы добавить функцию обратного вызова к делегату, используйте возвращаемое значение:

UCLASS()
class PROJECT_API UMyUserWidget : public UUserWidget
{
    GENERATED_BODY()
    void NativeConstruct() final
    {
        auto event = MyList->OnItemSelectionChanged();
        event.AddUObject(this, &UMyUserWidget::MyEventCallback);
    }
    void MyEventCallback(UObject* e)
    {
        // implementation details, cast e to UMyListViewEntry*
    }
    // ...
};

Вы можете использовать только обратные вызовы, имеющие UObject* в качестве параметра (UListView - это специализация базовых классов с использованием UObject в качестве типа записи).

Невозможно использовать делегата, который доступен в светокопии (BP_OnItemSelectionChanged), поскольку он является личным.

Опция № 2: Определить пользовательский делегат

Если вы хотите использовать свой собственный тип записи непосредственно в качестве параметра в обратном вызове, вы можете либо

  1. реализовать свой собственный вид списка или
  2. происходит от UListView и вызывает пользовательский делегат в virtual void OnSelectionChangedInternal(UObject* FirstSelectedItem)

Хотя первый подход аналогичен реализации UListView, второй подход очень короткий и может выглядеть как BP_OnItemSelectionChanged:

DECLARE_MULTICAST_DELEGATE_TwoParams(FOnMyListItemSelectionChanged, UMyListViewEntry*, bool);
UCLASS(meta = (EntryInterface = UserObjectListEntry, EntryClass = UMyListViewEntry))
class PROJECT_API UMyListView : public UListView
{
    GENERATED_BODY()
public:
    FOnMyListItemSelectionChanged OnMyListItemSelectionChanged;
private:
    void OnSelectionChangedInternal(UObject* FirstSelectedItem) override
    {
        Super::OnSelectionChangedInternal(FirstSelectedItem);
        auto entry = Cast<UMyListViewEntry>(FirstSelectedItem);
        OnMyListItemSelectionChanged.Broadcast(entry, entry != nullptr);
    }
};
UCLASS()
class PROJECT_API UMyUserWidget : public UUserWidget
{
    GENERATED_BODY()
    void NativeConstruct() final
    {
        MyList->OnMyListItemSelectionChanged.AddUObject(this, &UMyUserWidget::MyEventCallback);
    }
    void MyEventCallback(UMyListViewEntry* e, bool isSelected)
    {
        // implementation details
    }
private:
    UPROPERTY(meta = (BindWidget), meta = (EntryClass = UMyListViewEntry))
    UMyListView* MyList;
};
...