When I close my game in PIE while a SListView is visible on screen., the editor freezes for a second or two then crashes.
UE4Editor-CoreUObject.dll!UObjectBase::IsValidLowLevelFast(bool bRecursive) Line 306 C++
UE4Editor-CoreUObject.dll!UObjectBase::IsValidLowLevelFast(bool bRecursive) Line 320 C++
UE4Editor-CoreUObject.dll!FGCCollector::HandleObjectReference(UObject * & Object, const UObject * ReferencingObject, const UObject * ReferencingProperty) Line 268 C++
UE4Editor-Flare.dll!TListTypeTraits<IFlareShipInterface * __ptr64>::AddReferencedObjects(FReferenceCollector & Collector, TArray<IFlareShipInterface *,FDefaultAllocator> & ItemsWithGeneratedWidgets, TSet<IFlareShipInterface *,DefaultKeyFuncs<IFlareShipInterface *,0>,FDefaultSetAllocator> & SelectedItems) Line 214 C++
UE4Editor-CoreUObject.dll!UGCObjectReferencer::AddReferencedObjects(UObject * InThis, FReferenceCollector & Collector) Line 17 C++
UE4Editor-CoreUObject.dll!FArchiveRealtimeGC::ProcessObjectArray(TArray<UObject *,FDefaultAllocator> & InObjectsToSerializeArray, TRefCountPtr<FGraphEvent> & MyCompletionGraphEvent) Line 706 C++
UE4Editor-CoreUObject.dll!TGraphTask<FArchiveRealtimeGC::FGCTask>::ExecuteTask(TArray<FBaseGraphTask *,FDefaultAllocator> & NewTasks, ENamedThreads::Type CurrentThread) Line 671 C++
UE4Editor-Core.dll!FTaskThread::ProcessTasks(int QueueIndex, bool bAllowStall) Line 428 C++
UE4Editor-Core.dll!FTaskThread::ProcessTasksUntilQuit(int QueueIndex) Line 271 C++
UE4Editor-Core.dll!FTaskThread::Run() Line 562 C++
UE4Editor-Core.dll!FRunnableThreadWin::Run() Line 73 C++
UE4Editor-Core.dll!FRunnableThreadWin::GuardedRun() Line 48 C++
[External Code]
Here is the code.
// Ship list
TSharedPtr< SListView<IFlareShipInterface*> > ShipList;
TArray<IFlareShipInterface*> ShipListData;
// Create the list
SAssignNew(ShipList, SListView<IFlareShipInterface*>)
.ListItemsSource(&ShipListData)
.SelectionMode(ESelectionMode::Single)
.OnGenerateRow(this, &SFlareSectorMenu::GenerateShipInfo)
// Fill the list
ShipListData.AddUnique(GetShipPawn());
ShipList->RequestListRefresh();
// Display callback
TSharedRef<ITableRow> SFlareSectorMenu::GenerateShipInfo(IFlareShipInterface* Item, const TSharedRef<STableViewBase>& OwnerTable)
{
AFlarePlayerController* PC = Cast<AFlarePlayerController>(OwnerHUD->GetOwner());
return SNew(STableRow<IFlareShipInterface*>, OwnerTable)
.Content()
[
SNew(STextBlock).Text(FText::FromString("Test"))
];
}
I believe something is wrong at low level with this code. The list itself is fine, it works and shows up as expected.
/**
* A ListView widget observes an array of data items and creates visual representations of these items.
* ListView relies on the property that holding a reference to a value ensures its existence. In other words,
* neither SListView<FString> nor SListView<FString*> are valid, while SListView< TSharedPtr<FString> > and
* SListView< UObject* > are valid.
*
* A trivial use case appear below:
*
* Given: TArray< FString* > Items;
*
* SNew( SListView< FString* > )
* .ItemHeight(24)
* .ListItemsSource( &Items )
* .OnGenerateRow( SListView< TSharedPtr<FString> >::MakeOnGenerateWidget( this, &MyClass::OnGenerateRowForList ) )
*
* In the example we make all our widgets be 24 screen units tall. The ListView will create widgets based on data items
* in the Items TArray. When the ListView needs to generate an item, it will do so using the OnGenerateWidgetForList method.
*
* A sample implementation of OnGenerateWidgetForList would simply return a TextBlock with the corresponding text:
*
* TSharedRef<ITableRow> OnGenerateWidgetForList( FString* InItem, const TSharedRef<STableViewBase>& OwnerTable )
* {
* return SNew(STextBlock).Text( (*InItem) )
* }
*
*/
So you must use TSharedPtr as list item or use different OnGenerateRow method.
I don’t understand. It says “SListView< UObject* > are valid” which is exactly what I’m doing. It also says that “SListView< FString* >” is not valid, but that’s what the sample code does.
Since I’m holding a TArray of UObjects (specifically AActor) and TArray keeps the object from being GC, why does this not work ?
is IFlareShipInterface an UObject? If not then you do not store UObject pointers in your array and it has to be a shared pointer.
You can either change your SListView < IFlareShipInterface* > to SListView < TSharedPtr < IFlareShipInterface > > or, like in example above, define OnGenerateRow method like this: SListView< TSharedPtr < IFlareShipInterface > >::MakeOnGenerateWidget( this, &SFlareSectorMenu::GenerateShipInfo )
So the reason why FString* in the exmaple works is because OnGenerateRow is defined differently than regular one.
I’ve never used this method of defining SListView but it should work if it’s in example;B
Edit:
Something is wrong with code brackets… cant use // <
So, it looks like MakeOnGenerateWidget doesn’t exist. The only search hit in the engine source is the documentation snipped you quoted before.
I tried using TSharedPtr instead of pointers, but now the engine crashes as soon as the list is displayed, inside STableRow::GetBorder(). It looks like “OwnerWidget” is NULL.
I’m now using TSharedPtr< IFlareShipInterface > > as my table type. The error above was caused by not having the proper definition for my table row widget.
Now I have a much simpler error. Since I made a TSharedPtr from my ship pawn (using an interface), now, deleting my table apparently tries to delete my pawn. And I can’t fix this, since TSharedPtr doesn’t work with UObjects.
I just want to put Pawns in a list. Why is that so hard ?
I assume you want to store a pointer to an actor/interface/uobject/whatever in your list. So what I would do is create a class/structure that holds this pointer and use this class/structure as a list item.
class FMyItem
{
public:
static TSharedPtr< FMyItem> New(IFlareShipInterface* InObject)
{
return MakeShareable(new FMyItem(InObject));
}
private:
FMyItem(IFlareShipInterface* InPtr) : InterfacePtr(InPtr){}
IFlareShipInterface* InterfacePtr;
}
// just for shorter name
typedef TSharedPtr< FMyItem> FItemPtr;
// here goes your list source
TArray< FItemPtr> ListSource;
// list declaration
TSharedPtr< SListView<FItemPtr> > ListView;
// OnGenerateRow that you will plug during SListView creation
TSharedRef< ITableRow> OnGenerateRow(FItemPtr Item, const TSharedRef< STableViewBase>& OwnerTable)
{
return SNew( STableRow< FItemPtr >, OwnerTable )
[
...
];
}
// and this is how you make new item and add it to the list
ListSource.Add(FMyItem::New(GetSomethingThatImplementsDesiredInterface()));
Hope this helps you somehow or will get you on the right track