[{"data":1,"prerenderedAt":1301},["ShallowReactive",2],{"page-Slate-1":3,"page-count-Slate":255},[4,105,1021,1148],{"id":5,"title":6,"body":7,"date":80,"description":13,"extension":81,"meta":82,"navigation":85,"path":97,"seo":98,"stem":99,"tags":100,"__hash__":104},"blogs\u002F_legacy\u002F2015\u002F2015-09-11-uwidget-wrap-swidget-to-umg.md","UWidget封装SWidget到UMG",{"type":8,"value":9,"toc":76},"minimark",[10,14,17,20,23,26,29,32,43,46,49,55,58,61,64,67,70,73],[11,12,13],"p",{},"为了使用UMG中的一些高级或便利特性，需要将制作好的Slate控件封装到UWidget中去。",[11,15,16],{},"当前UE4版本4.8.3。",[11,18,19],{},"将Slate封装到UMG中去有很多的好处，因为在代码中对需要重用的控件进行不断的重新布局是一件非常繁琐的事情。同时，UMG也有在3D空间中进行显示这样的高级功能。",[11,21,22],{},"由于UMG本身就是对Slate的封装，所以这个过程可以参照UE4的源代码进行研究。",[11,24,25],{},"这里所做的是尝试对上一回所做的文件目录树进行封装。",[11,27,28],{},"直接上代码",[11,30,31],{},"CListViewWidget.h",[33,34,39],"pre",{"className":35,"code":37,"language":38},[36],"language-text","#pragma once\n#include \"CListViewWidget.generated.h\"\nUCLASS()\nclass TEST_MP_API UCListViewWidget : public UWidget\n{\n  GENERATED_UCLASS_BODY()\npublic:\n\n#if WITH_EDITOR\n  \u002F\u002F UWidget interface\n  virtual const FSlateBrush* GetEditorIcon() override;\n  virtual const FText GetPaletteCategory() override;\n  virtual void OnCreationFromPalette() override;\n  \u002F\u002F End UWidget interface\n#endif\n\nprotected:\n  \u002F\u002F UWidget interface\n  virtual TSharedRef\u003CSWidget> RebuildWidget() override;\n  virtual void OnBindingChanged(const FName& Property) override;\n  \u002F\u002F End of UWidget interface\n\nprotected:\n  TSharedPtr\u003Cclass SDDFileTree> MyFileTree;\n};\n","text",[40,41,37],"code",{"__ignoreMap":42},"",[11,44,45],{},"封装类直接继承自UWidget即可，剩下的就是对UWidget中的函数进行实现。",[11,47,48],{},"CListViewWidget.cpp",[33,50,53],{"className":51,"code":52,"language":38},[36],"#include \"Test_mp.h\"\n#include \"SDDFileTree.h\"\n#include \"CListViewWidget.h\"\n\n\u002F** GENERATED_UCLASS_BODY() *\u002F\nUCListViewWidget::UCListViewWidget(const FObjectInitializer& ObjectInitializer)\n: Super(ObjectInitializer)\n{\n  bIsVariable = false;\n}\n\n\u002F** \u003C编辑器属性 *\u002F\n#if WITH_EDITOR\n\n\u002F\u002F \u003C图标\nconst FSlateBrush* UCListViewWidget::GetEditorIcon()\n{\n  return FUMGStyle::Get().GetBrush(\"Widget.TextBlock\");\n}\n\n\u002F\u002F \u003C分类目录\nconst FText UCListViewWidget::GetPaletteCategory()\n{\n  return NSLOCTEXT(\"Testmp\", \"Custom\", \"Ch_Custom\");\n}\n\n\u002F\u002F \u003C创建时的默认值\nvoid UCListViewWidget::OnCreationFromPalette()\n{\n;\n}\n\n#endif\n\nTSharedRef\u003CSWidget> UCListViewWidget::RebuildWidget()\n{\n  MyFileTree = SNew(SDDFileTree).OwnerHUD(nullptr);\n\n  return MyFileTree.ToSharedRef();\n}\n\nvoid UCListViewWidget::OnBindingChanged(const FName& Property)\n{\n  Super::OnBindingChanged(Property);\n\n  if (MyFileTree.IsValid())\n  {\n    ;\n  }\n}\n",[40,54,52],{"__ignoreMap":42},[11,56,57],{},"在所有的函数中，RebuildWidget()是最重要的。",[11,59,60],{},"参看UWidget的源代码可以发现，所有对被封装的SWidget的引用都是通过这个函数获得的，因此在这里面写上SWidget对应的构造生成就可以了。",[11,62,63],{},"OnBindingChanged函数是用于属性代理通知的，这里是简单的封装，没有提供属性代理，因此直接return也是可以的。",[11,65,66],{},"在WITH_EDITOR宏中的是编辑器属性，用于封装后的UWidget在蓝图编辑器中显示。具体每一个函数的含义已经在注释中了。",[11,68,69],{},"将上面的代码编译通过之后，就可以在UMG的编辑器中看到我们添加的控件了：",[11,71,72],{},"将CListViewWidget拖动到控件蓝图上，并在HUD中展示此控件蓝图，就能在项目中与其他UMG控件一样使用了：",[11,74,75],{},"这样以来Slate的使用就会变得方便很多。",{"title":42,"searchDepth":77,"depth":78,"links":79},2,3,[],"2015-09-11","md",{"layout":83,"status":84,"published":85,"author":86,"author_login":87,"author_email":88,"author_url":89,"wordpress_id":90,"wordpress_url":91,"date_gmt":92,"excerpt":93},"post","publish",true,{"display_name":87,"login":87,"email":88,"url":89},"chaoshikari","chaoshikari@gmail.com","\u002F",1457,"\u002F\u002F?p=1457","2015-09-11 11:11:13 +0000",{"type":8,"value":94},[95],[11,96,13],{},"\u002F2015-09-11-uwidget-wrap-swidget-to-umg",{"title":6,"description":13},"_legacy\u002F2015\u002F2015-09-11-uwidget-wrap-swidget-to-umg",[101,102,103],"UE4","UMG","Slate","mPzjKCXtbWWXkWThfinkYHexD0dpoqD6gvqKCUaR4v0",{"id":106,"title":107,"body":108,"date":1003,"description":112,"extension":81,"meta":1004,"navigation":85,"path":1016,"seo":1017,"stem":1018,"tags":1019,"__hash__":1020},"blogs\u002F_legacy\u002F2015\u002F2015-08-19-slate-file-browser-tree-view-simple.md","Slate文件目录树基础实现",{"type":8,"value":109,"toc":998},[110,113,115,118,129,132,136,139,142,145,151,154,158,161,164,167,173,176,182,185,188,191,194,197,200,340,343,991,994],[11,111,112],{},"目前UMG中并没有提供TreeView类，要使用TreeView必须使用Slate。",[11,114,16],{},[11,116,117],{},"TreeView在UE4编辑器中被广泛的使用，但是出于某些不可知的原因无法在UMG中进行直接使用。鉴于制作复杂度较高的界面需要使用到Slate，对Slate进行专门的研究是有必要的。",[11,119,120,121,128],{},"本文参照Unreal官方社区文档",[122,123,127],"a",{"href":124,"rel":125},"https:\u002F\u002Fwiki.unrealengine.com\u002FSlate,_Tree_View_Widget,_Ex:_In-Editor_File_Structure_Explorer",[126],"nofollow","Slate, Tree View Widget","完成。",[11,130,131],{},"请注意：原始文档中并没有给出具体的文件浏览器实现，而是提供了作为其基础的目录树使用方式。",[133,134,135],"h2",{"id":135},"目录树数据结构",[11,137,138],{},"要实现目录树并不需要太复杂的数据结构，实现基本的功能即可。",[11,140,141],{},"TreeView中本身需要的数据是数组型的，这里定义的数据结构是节点使用的。",[11,143,144],{},"DDFileTreeItem.h",[33,146,149],{"className":147,"code":148,"language":38},[36],"#pragma once\n\ntypedef TSharedPtr\u003C class FDDFileTreeItem > FDDFileTreeItemPtr;\n\n\u002F**\n* \u003C目录树节点\n*\u002F\n\nclass FDDFileTreeItem\n{\npublic:\n\n\u002F** @return \u003C返回父节点 *\u002F\nconst FDDFileTreeItemPtr GetParentCategory() const\n{\n  return ParentDir.Pin();\n}\n\n\u002F** @return \u003C返回节点的路径【只读】 *\u002F\nconst FString& GetDirectoryPath() const\n{\n  return DirectoryPath;\n}\n\n\u002F** @return \u003C返回显示名称【只读】 *\u002F\nconst FString& GetDisplayName() const\n{\n  return DisplayName;\n}\n\n\u002F** @return \u003C返回子节点【只读】 *\u002F\nconst TArray\u003C FDDFileTreeItemPtr >& GetSubDirectories() const\n{\n  return SubDirectories;\n}\n\n\u002F** @return \u003C返回可写入的子节点引用 *\u002F\nTArray\u003C FDDFileTreeItemPtr >& AccessSubDirectories()\n{\n  return SubDirectories;\n}\n\n\u002F** \u003C为当前节点添加子目录 *\u002F\nvoid AddSubDirectory(const FDDFileTreeItemPtr NewSubDir)\n{\n  SubDirectories.Add(NewSubDir);\n}\n\npublic:\n\u002F** \u003C构造函数 *\u002F\n\nFDDFileTreeItem(const FDDFileTreeItemPtr IN_ParentDir, const FString& IN_DirectoryPath, const FString& IN_DisplayName)\n: ParentDir(IN_ParentDir)\n, DirectoryPath(IN_DirectoryPath)\n, DisplayName(IN_DisplayName)\n{\n\n}\n\nprivate:\n\n\u002F** \u003C父节点引用; *\u002F\nTWeakPtr\u003C FDDFileTreeItem > ParentDir;\n\n\u002F** \u003C完整路径 *\u002F\nFString DirectoryPath;\n\n\u002F** \u003C显示名称 *\u002F\nFString DisplayName;\n\n\u002F** \u003C子节点数组 *\u002F\nTArray\u003C FDDFileTreeItemPtr > SubDirectories;\n\n};\n",[40,150,148],{"__ignoreMap":42},[11,152,153],{},"节点的数据结构较为简单，直接在头文件中对函数进行了实现。",[133,155,157],{"id":156},"目录树slate控件","目录树Slate控件",[11,159,160],{},"由于原始文档中提供的代码中引用的Engine是不必要的，故而在这里直接替换成了较为通用的HUD引用，这样就不会导致代码有项目相关性了。",[11,162,163],{},"这里先上代码，其他的一些说明放在代码后面。",[11,165,166],{},"SDDFileTree.h",[33,168,171],{"className":169,"code":170,"language":38},[36],"#pragma once\n\n\u002F* \u003C节点数据结构 *\u002F\n\n#include \"DDFileTreeItem.h\"\n\ntypedef STreeView\u003C FDDFileTreeItemPtr > SDDFileTreeView;\n\n\u002F**\n* \u003C目录树Slate\n*\u002F\n\nclass SDDFileTree : public SCompoundWidget\n{\n\npublic:\n\nSLATE_BEGIN_ARGS(SDDFileTree){}\n\nSLATE_ARGUMENT(TWeakObjectPtr\u003Cclass AHUD>, OwnerHUD)\n\nSLATE_END_ARGS()\n\npublic:\n\nTWeakObjectPtr\u003CAHUD> OwnerHUD;\n\n\u002F** \u003C刷新目录 *\u002F\n\n\u002F\u002Fbool DoRefresh;\n\npublic:\n\nvoid Construct(const FArguments& InArgs);\n\n\u002F** Destructor *\u002F\n~SDDFileTree();\n\n\u002F** @return \u003C返回当前被选中的目录 *\u002F\nFDDFileTreeItemPtr GetSelectedDirectory() const;\n\n\u002F** \u003C选择目录 *\u002F\nvoid SelectDirectory(const FDDFileTreeItemPtr& CategoryToSelect);\n\n\u002F** @return \u003C返回节点是否展开 *\u002F\nbool IsItemExpanded(const FDDFileTreeItemPtr Item) const;\n\nprivate:\n\n\u002F** \u003C生成单个节点元素 *\u002F\nTSharedRef\u003CITableRow> DDFileTree_OnGenerateRow(FDDFileTreeItemPtr Item, const TSharedRef\u003CSTableViewBase>& OwnerTable);\n\n\u002F** \u003C获得子节点 *\u002F\nvoid DDFileTree_OnGetChildren(FDDFileTreeItemPtr Item, TArray\u003C FDDFileTreeItemPtr >& OutChildren);\n\n\u002F** \u003C当选中项发生变化时 *\u002F\nvoid DDFileTree_OnSelectionChanged(FDDFileTreeItemPtr Item, ESelectInfo::Type SelectInfo);\n\n\u002F** \u003C构建目录树数据 *\u002F\nvoid RebuildFileTree();\n\n\u002F** \u003C重写Tick方便以后实现目录刷新 *\u002F\nvirtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;\n\nprivate:\n\n\u002F** \u003CTreeView控件 *\u002F\nTSharedPtr\u003C SDDFileTreeView > DDFileTreeView;\n\n\u002F** \u003C目录树的数据 *\u002F\nTArray\u003C FDDFileTreeItemPtr > Directories;\n\n};\n",[40,172,170],{"__ignoreMap":42},[11,174,175],{},"SDDFileTree.cpp",[33,177,180],{"className":178,"code":179,"language":38},[36],"#include \"Test_mp.h\"\n#include \"SDDFileTree.h\"\n#include \"DDFileTreeItem.h\"\n\nvoid SDDFileTree::Construct(const FArguments& InArgs)\n{\n  OwnerHUD = InArgs._OwnerHUD;\n  RebuildFileTree(); \u002F* \u003C构建目录树数据 *\u002F\n\n  \u002F\u002FBuild the tree view of the above core data\n  DDFileTreeView =\n    SNew(SDDFileTreeView)\n    .SelectionMode(ESelectionMode::Single) \u002F\u002F 只允许选中一个项目\n    .ClearSelectionOnClick(false) \u002F\u002F 不允许不选中内容\n    .TreeItemsSource(&Directories)\n    .OnGenerateRow(this, &SDDFileTree::DDFileTree_OnGenerateRow)\n    .OnGetChildren(this, &SDDFileTree::DDFileTree_OnGetChildren)\n    .OnSelectionChanged(this, &SDDFileTree::DDFileTree_OnSelectionChanged)\n;\n\n    \u002F*\n    \u002F\u002F Expand the root  by default\n    for( auto RootDirIt( Directories.CreateConstIterator() ); RootDirIt; ++RootDirIt )\n    {\n      const auto& Dir = *RootDirIt;\n      DDFileTreeView->SetItemExpansion( Dir, true );\n    }\n\n    \u002F\u002F Select the first item by default\n    if( Directories.Num() > 0 )\n    {\n      DDFileTreeView->SetSelection( Directories[ 0 ] );\n    }\n\n    *\u002F\n\n    ChildSlot.AttachWidget(DDFileTreeView.ToSharedRef());\n}\n\nSDDFileTree::~SDDFileTree()\n{\n\n}\n\nvoid SDDFileTree::RebuildFileTree()\n{\n  Directories.Empty();\n  \u002F\u002F~~~~~~~~~~~~~~~~~~~\n  \u002F\u002FRoot Level\n  TSharedRef\u003CFDDFileTreeItem> RootDir = MakeShareable(new FDDFileTreeItem(NULL, TEXT(\"RootDir\"), FString(\"RootDir\")));\n  Directories.Add(RootDir);\n  TSharedRef\u003CFDDFileTreeItem> RootDir2 = MakeShareable(new FDDFileTreeItem(NULL, TEXT(\"RootDir2\"), FString(\"RootDir2\")));\n  Directories.Add(RootDir2);\n  \u002F\u002F~~~~~~~~~~~~~~~~~~~\n\n  \u002F\u002FRoot Category\n  FDDFileTreeItemPtr ParentCategory = RootDir;\n\n  \u002F\u002FAdd\n  FDDFileTreeItemPtr EachSubDir = MakeShareable(new FDDFileTreeItem(ParentCategory, \"Joy\", \"Joy\"));\n  RootDir->AddSubDirectory(EachSubDir);\n\n  \u002F\u002FAdd\n\n  EachSubDir = MakeShareable(new FDDFileTreeItem(ParentCategory, \"Song\", \"Song\"));\n  RootDir->AddSubDirectory(EachSubDir);\n\n  \u002F\u002FAdd\n\n  FDDFileTreeItemPtr SongDir = MakeShareable(new FDDFileTreeItem(ParentCategory, \"Dance\", \"Dance\"));\n  EachSubDir->AddSubDirectory(SongDir);\n\n  \u002F\u002FAdd\n\n  SongDir = MakeShareable(new FDDFileTreeItem(ParentCategory, \"Rainbows\", \"Rainbows\"));\n  EachSubDir->AddSubDirectory(SongDir);\n  \u002F\u002FAdd\n  EachSubDir = MakeShareable(new FDDFileTreeItem(ParentCategory, \"Butterflies\", \"Butterflies\"));\n  RootDir->AddSubDirectory(EachSubDir);\n\n  \u002F\u002FRefresh\n\n  if (DDFileTreeView.IsValid())\n  {\n    DDFileTreeView->RequestTreeRefresh();\n  }\n\n}\n\nTSharedRef\u003CITableRow> SDDFileTree::DDFileTree_OnGenerateRow(FDDFileTreeItemPtr Item, const TSharedRef\u003CSTableViewBase>& OwnerTable)\n{\n  if (!Item.IsValid())\n  {\n    return SNew(STableRow\u003C FDDFileTreeItemPtr >, OwnerTable)\n      [\n        SNew(STextBlock)\n          .Text(NSLOCTEXT(\"Your Namespace\", \"twns\", \"THIS WAS NULL SOMEHOW\"))\n      ];\n\n  }\n\n  return SNew(STableRow\u003C FDDFileTreeItemPtr >, OwnerTable)\n    [\n      SNew(STextBlock)\n        .Text(FText::FromString(Item->GetDisplayName()))\n        .Font(FSlateFontInfo(FPaths::EngineContentDir() \u002F TEXT(\"Slate\u002FFonts\u002FRoboto-Bold.ttf\"), 12))\n        .ColorAndOpacity(FLinearColor(1, 0, 1, 1))\n        .ShadowColorAndOpacity(FLinearColor::Black)\n        .ShadowOffset(FIntPoint(-2, 2))\n    ];\n}\n\nvoid SDDFileTree::DDFileTree_OnGetChildren(FDDFileTreeItemPtr Item, TArray\u003C FDDFileTreeItemPtr >& OutChildren)\n{\n  const auto& SubCategories = Item->GetSubDirectories();\n  OutChildren.Append(SubCategories);\n}\n\n\u002F\u002FKey function for interaction with user!\nvoid SDDFileTree::DDFileTree_OnSelectionChanged(FDDFileTreeItemPtr Item, ESelectInfo::Type SelectInfo)\n{\n  \u002F\u002FSelection Changed!\n  UE_LOG(LogTemp, Warning, TEXT(\"Item Selected: %s\"), *Item->GetDisplayName());\n}\n\nFDDFileTreeItemPtr SDDFileTree::GetSelectedDirectory() const\n{\n  if (DDFileTreeView.IsValid())\n  {\n     auto SelectedItems = DDFileTreeView->GetSelectedItems();\n     if (SelectedItems.Num() > 0)\n     {\n       const auto& SelectedCategoryItem = SelectedItems[0];\n       return SelectedCategoryItem;\n     }\n\n  }\n  return NULL;\n}\n\nvoid SDDFileTree::SelectDirectory(const FDDFileTreeItemPtr& CategoryToSelect)\n{\n  if (ensure(DDFileTreeView.IsValid()))\n  {\n      DDFileTreeView->SetSelection(CategoryToSelect);\n  }\n}\n\n\u002F\u002Fis the tree item expanded to show children?\nbool SDDFileTree::IsItemExpanded(const FDDFileTreeItemPtr Item) const\n{\n  return DDFileTreeView->IsItemExpanded(Item);\n}\n\nvoid SDDFileTree::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)\n{\n  \u002F\u002F Call parent implementation\n  SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);\n  \u002F\u002Fcan do things here every tick\n}\n",[40,181,179],{"__ignoreMap":42},[11,183,184],{},"代码的结构还是比较清晰的，这里需要注意的是，针对TreeView的事件是在控件本身生成的时候注册的。",[11,186,187],{},"其中，OnGenerateRow事件是STreeView和SListView的必须事件。当控件需要进行元素显示时，会对这个函数进行调用，获得需要显示的元素。",[11,189,190],{},"另外，代码中的OnSelectionChanged函数缺乏必要的安全检测，在使用中需要留意。",[11,192,193],{},"用于显示的数据是在Construct中通过调用RebuildFileTree()函数生成的。",[133,195,196],{"id":196},"最终结果",[11,198,199],{},"完成了上面的步骤之后，直接在HUD中对控件进行展示即可。",[33,201,205],{"className":202,"code":203,"language":204,"meta":42,"style":42},"language-cpp shiki shiki-themes github-light-high-contrast github-dark monokai","SAssignNew(DDFileTree, SDDFileTree).OwnerHUD(this);\n\nif (GEngine->IsValidLowLevel())\n{\n  GEngine->GameViewport->AddViewportWidgetContent(SNew(SWeakWidget).PossiblyNullContent(DDFileTree.ToSharedRef()));\n}\n\nif (DDFileTree.IsValid())\n{\n  DDFileTree->SetVisibility(EVisibility::Visible);\n}\n","cpp",[40,206,207,233,238,253,259,288,294,299,312,317,335],{"__ignoreMap":42},[208,209,212,216,220,223,226,230],"span",{"class":210,"line":211},"line",1,[208,213,215],{"class":214},"scAT4","SAssignNew",[208,217,219],{"class":218},"s0idv","(DDFileTree, SDDFileTree).",[208,221,222],{"class":214},"OwnerHUD",[208,224,225],{"class":218},"(",[208,227,229],{"class":228},"s4Wjf","this",[208,231,232],{"class":218},");\n",[208,234,235],{"class":210,"line":77},[208,236,237],{"emptyLinePlaceholder":85},"\n",[208,239,240,244,247,250],{"class":210,"line":78},[208,241,243],{"class":242},"sLXdl","if",[208,245,246],{"class":218}," (GEngine->",[208,248,249],{"class":214},"IsValidLowLevel",[208,251,252],{"class":218},"())\n",[208,254,256],{"class":210,"line":255},4,[208,257,258],{"class":218},"{\n",[208,260,262,265,268,270,273,276,279,282,285],{"class":210,"line":261},5,[208,263,264],{"class":218},"  GEngine->GameViewport->",[208,266,267],{"class":214},"AddViewportWidgetContent",[208,269,225],{"class":218},[208,271,272],{"class":214},"SNew",[208,274,275],{"class":218},"(SWeakWidget).",[208,277,278],{"class":214},"PossiblyNullContent",[208,280,281],{"class":218},"(DDFileTree.",[208,283,284],{"class":214},"ToSharedRef",[208,286,287],{"class":218},"()));\n",[208,289,291],{"class":210,"line":290},6,[208,292,293],{"class":218},"}\n",[208,295,297],{"class":210,"line":296},7,[208,298,237],{"emptyLinePlaceholder":85},[208,300,302,304,307,310],{"class":210,"line":301},8,[208,303,243],{"class":242},[208,305,306],{"class":218}," (DDFileTree.",[208,308,309],{"class":214},"IsValid",[208,311,252],{"class":218},[208,313,315],{"class":210,"line":314},9,[208,316,258],{"class":218},[208,318,320,323,326,328,332],{"class":210,"line":319},10,[208,321,322],{"class":218},"  DDFileTree->",[208,324,325],{"class":214},"SetVisibility",[208,327,225],{"class":218},[208,329,331],{"class":330},"sfUV7","EVisibility",[208,333,334],{"class":218},"::Visible);\n",[208,336,338],{"class":210,"line":337},11,[208,339,293],{"class":218},[11,341,342],{},"启动预览，由于没有进行布局，可以在最上方看到目录树的展示。",[11,344,345,346,990],{},"![U10",[208,347,350,561],{"className":348},[349],"katex",[208,351,354],{"className":352},[353],"katex-mathml",[355,356,358],"math",{"xmlns":357},"http:\u002F\u002Fwww.w3.org\u002F1998\u002FMath\u002FMathML",[359,360,361,556],"semantics",{},[362,363,364,373,376,380,383,386,389,397,400,403,408,411,414,417,419,422,424,426,429,432,434,437,440,443,446,449,452,454,456,458,461,463,466,468,470,473,476,478,481,483,486,488,490,497,499,501,503,505,507,513,515,518,520,522,528,531,533,536,539,542,544,546,549,552,554],"mrow",{},[365,366,367,369],"msub",{},[362,368],{},[370,371,372],"mi",{},"I",[370,374,375],{},"A",[377,378,379],"mn",{},"57",[370,381,382],{},"U",[370,384,385],{},"R",[370,387,388],{},"M",[365,390,391,394],{},[370,392,393],{},"V",[370,395,396],{},"P",[370,398,399],{},"O",[377,401,402],{},"0",[404,405,407],"mo",{"stretchy":406},"false","]",[377,409,410],{},"6",[404,412,413],{"stretchy":406},"[",[370,415,416],{},"J",[370,418,382],{},[370,420,421],{},"C",[404,423,407],{"stretchy":406},[404,425,225],{"stretchy":406},[370,427,89],{"mathvariant":428},"normal",[370,430,431],{},"w",[370,433,11],{},[404,435,436],{},"−",[370,438,439],{},"c",[370,441,442],{},"o",[370,444,445],{},"n",[370,447,448],{},"t",[370,450,451],{},"e",[370,453,445],{},[370,455,448],{},[370,457,89],{"mathvariant":428},[370,459,460],{},"u",[370,462,11],{},[370,464,465],{},"l",[370,467,442],{},[370,469,122],{},[370,471,472],{},"d",[370,474,475],{},"s",[370,477,89],{"mathvariant":428},[377,479,480],{},"2017",[370,482,89],{"mathvariant":428},[377,484,485],{},"03",[370,487,89],{"mathvariant":428},[370,489,382],{},[365,491,492,495],{},[377,493,494],{},"10",[370,496,372],{},[370,498,375],{},[377,500,379],{},[370,502,382],{},[370,504,385],{},[370,506,388],{},[365,508,509,511],{},[370,510,393],{},[370,512,396],{},[370,514,399],{},[377,516,517],{},"06",[370,519,416],{},[370,521,382],{},[365,523,524,526],{},[370,525,421],{},[370,527,448],{},[370,529,530],{},"h",[370,532,460],{},[370,534,535],{},"m",[370,537,538],{},"b",[370,540,541],{"mathvariant":428},".",[370,543,11],{},[370,545,445],{},[370,547,548],{},"g",[370,550,551],{"mathvariant":428},"\"",[370,553,382],{},[377,555,494],{},[557,558,560],"annotation",{"encoding":559},"application\u002Fx-tex","_IA57URMV_PO0]6[JUC](\u002Fwp-content\u002Fuploads\u002F2017\u002F03\u002FU10_IA57URMV_PO06JUC_thumb.png \"U10",[208,562,566,749],{"className":563,"ariaHidden":565},[564],"katex-html","true",[208,567,570,575,633,636,639,643,647,650,693,697,700,704,707,711,715,718,722,725,728,731,735,738,742,746],{"className":568},[569],"base",[208,571],{"className":572,"style":574},[573],"strut","height:1em;vertical-align:-0.25em;",[208,576,579,581],{"className":577},[578],"mord",[208,580],{},[208,582,585],{"className":583},[584],"msupsub",[208,586,590,624],{"className":587},[588,589],"vlist-t","vlist-t2",[208,591,594,619],{"className":592},[593],"vlist-r",[208,595,599],{"className":596,"style":598},[597],"vlist","height:0.3283em;",[208,600,602,607],{"style":601},"top:-2.55em;margin-right:0.05em;",[208,603],{"className":604,"style":606},[605],"pstrut","height:2.7em;",[208,608,614],{"className":609},[610,611,612,613],"sizing","reset-size6","size3","mtight",[208,615,372],{"className":616,"style":618},[578,617,613],"mathnormal","margin-right:0.0785em;",[208,620,623],{"className":621},[622],"vlist-s","​",[208,625,627],{"className":626},[593],[208,628,631],{"className":629,"style":630},[597],"height:0.15em;",[208,632],{},[208,634,375],{"className":635},[578,617],[208,637,379],{"className":638},[578],[208,640,382],{"className":641,"style":642},[578,617],"margin-right:0.109em;",[208,644,385],{"className":645,"style":646},[578,617],"margin-right:0.0077em;",[208,648,388],{"className":649,"style":642},[578,617],[208,651,653,657],{"className":652},[578],[208,654,393],{"className":655,"style":656},[578,617],"margin-right:0.2222em;",[208,658,660],{"className":659},[584],[208,661,663,685],{"className":662},[588,589],[208,664,666,682],{"className":665},[593],[208,667,669],{"className":668,"style":598},[597],[208,670,672,675],{"style":671},"top:-2.55em;margin-left:-0.2222em;margin-right:0.05em;",[208,673],{"className":674,"style":606},[605],[208,676,678],{"className":677},[610,611,612,613],[208,679,396],{"className":680,"style":681},[578,617,613],"margin-right:0.1389em;",[208,683,623],{"className":684},[622],[208,686,688],{"className":687},[593],[208,689,691],{"className":690,"style":630},[597],[208,692],{},[208,694,399],{"className":695,"style":696},[578,617],"margin-right:0.0278em;",[208,698,402],{"className":699},[578],[208,701,407],{"className":702},[703],"mclose",[208,705,410],{"className":706},[578],[208,708,413],{"className":709},[710],"mopen",[208,712,416],{"className":713,"style":714},[578,617],"margin-right:0.0962em;",[208,716,382],{"className":717,"style":642},[578,617],[208,719,421],{"className":720,"style":721},[578,617],"margin-right:0.0715em;",[208,723,407],{"className":724},[703],[208,726,225],{"className":727},[710],[208,729,89],{"className":730},[578],[208,732,431],{"className":733,"style":734},[578,617],"margin-right:0.0269em;",[208,736,11],{"className":737},[578,617],[208,739],{"className":740,"style":656},[741],"mspace",[208,743,436],{"className":744},[745],"mbin",[208,747],{"className":748,"style":656},[741],[208,750,752,755,759,762,765,768,771,774,777,780,785,788,791,794,797,801,804,808,849,852,855,858,861,864,904,907,910,913,916,958,961,964,968,971,974,977,981,984,987],{"className":751},[569],[208,753],{"className":754,"style":574},[573],[208,756,758],{"className":757},[578,617],"co",[208,760,445],{"className":761},[578,617],[208,763,448],{"className":764},[578,617],[208,766,451],{"className":767},[578,617],[208,769,445],{"className":770},[578,617],[208,772,448],{"className":773},[578,617],[208,775,89],{"className":776},[578],[208,778,460],{"className":779},[578,617],[208,781,784],{"className":782,"style":783},[578,617],"margin-right:0.0197em;","pl",[208,786,442],{"className":787},[578,617],[208,789,122],{"className":790},[578,617],[208,792,472],{"className":793},[578,617],[208,795,475],{"className":796},[578,617],[208,798,800],{"className":799},[578],"\u002F2017\u002F03\u002F",[208,802,382],{"className":803,"style":642},[578,617],[208,805,807],{"className":806},[578],"1",[208,809,811,814],{"className":810},[578],[208,812,402],{"className":813},[578],[208,815,817],{"className":816},[584],[208,818,820,841],{"className":819},[588,589],[208,821,823,838],{"className":822},[593],[208,824,826],{"className":825,"style":598},[597],[208,827,829,832],{"style":828},"top:-2.55em;margin-left:0em;margin-right:0.05em;",[208,830],{"className":831,"style":606},[605],[208,833,835],{"className":834},[610,611,612,613],[208,836,372],{"className":837,"style":618},[578,617,613],[208,839,623],{"className":840},[622],[208,842,844],{"className":843},[593],[208,845,847],{"className":846,"style":630},[597],[208,848],{},[208,850,375],{"className":851},[578,617],[208,853,379],{"className":854},[578],[208,856,382],{"className":857,"style":642},[578,617],[208,859,385],{"className":860,"style":646},[578,617],[208,862,388],{"className":863,"style":642},[578,617],[208,865,867,870],{"className":866},[578],[208,868,393],{"className":869,"style":656},[578,617],[208,871,873],{"className":872},[584],[208,874,876,896],{"className":875},[588,589],[208,877,879,893],{"className":878},[593],[208,880,882],{"className":881,"style":598},[597],[208,883,884,887],{"style":671},[208,885],{"className":886,"style":606},[605],[208,888,890],{"className":889},[610,611,612,613],[208,891,396],{"className":892,"style":681},[578,617,613],[208,894,623],{"className":895},[622],[208,897,899],{"className":898},[593],[208,900,902],{"className":901,"style":630},[597],[208,903],{},[208,905,399],{"className":906,"style":696},[578,617],[208,908,517],{"className":909},[578],[208,911,416],{"className":912,"style":714},[578,617],[208,914,382],{"className":915,"style":642},[578,617],[208,917,919,922],{"className":918},[578],[208,920,421],{"className":921,"style":721},[578,617],[208,923,925],{"className":924},[584],[208,926,928,950],{"className":927},[588,589],[208,929,931,947],{"className":930},[593],[208,932,935],{"className":933,"style":934},[597],"height:0.2806em;",[208,936,938,941],{"style":937},"top:-2.55em;margin-left:-0.0715em;margin-right:0.05em;",[208,939],{"className":940,"style":606},[605],[208,942,944],{"className":943},[610,611,612,613],[208,945,448],{"className":946},[578,617,613],[208,948,623],{"className":949},[622],[208,951,953],{"className":952},[593],[208,954,956],{"className":955,"style":630},[597],[208,957],{},[208,959,530],{"className":960},[578,617],[208,962,460],{"className":963},[578,617],[208,965,967],{"className":966},[578,617],"mb",[208,969,541],{"className":970},[578],[208,972,11],{"className":973},[578,617],[208,975,445],{"className":976},[578,617],[208,978,548],{"className":979,"style":980},[578,617],"margin-right:0.0359em;",[208,982,551],{"className":983},[578],[208,985,382],{"className":986,"style":642},[578,617],[208,988,494],{"className":989},[578],"_IA57URMV_PO0]6[JUC\")",[11,992,993],{},"至此，目录树的基本功能已经实现。",[995,996,997],"style",{},"html pre.shiki code .scAT4, html code.shiki .scAT4{--shiki-default:#622CBC;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .s0idv, html code.shiki .s0idv{--shiki-default:#0E1116;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .s4Wjf, html code.shiki .s4Wjf{--shiki-default:#023B95;--shiki-dark:#79B8FF;--shiki-sepia:#FD971F}html pre.shiki code .sLXdl, html code.shiki .sLXdl{--shiki-default:#A0111F;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .sfUV7, html code.shiki .sfUV7{--shiki-default:#702C00;--shiki-default-text-decoration:inherit;--shiki-dark:#B392F0;--shiki-dark-text-decoration:inherit;--shiki-sepia:#A6E22E;--shiki-sepia-text-decoration:underline}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}",{"title":42,"searchDepth":77,"depth":78,"links":999},[1000,1001,1002],{"id":135,"depth":77,"text":135},{"id":156,"depth":77,"text":157},{"id":196,"depth":77,"text":196},"2015-08-19",{"layout":83,"status":84,"published":85,"author":1005,"author_login":1007,"author_email":1008,"wordpress_id":1009,"wordpress_url":1010,"date_gmt":1011,"excerpt":1012},{"display_name":1006,"login":1007,"email":1008,"url":42},"风铃","flinkor","flinkor@foxmail.com",1542,"\u002F\u002F?p=1542","2015-08-19 06:52:43 +0000",{"type":8,"value":1013},[1014],[11,1015,112],{},"\u002F2015-08-19-slate-file-browser-tree-view-simple",{"title":107,"description":112},"_legacy\u002F2015\u002F2015-08-19-slate-file-browser-tree-view-simple",[101,103],"AHchideoQOxz25BWavPLnfqJsUoUsDtNrYhTtEf97xw",{"id":1022,"title":1023,"body":1024,"date":1133,"description":1028,"extension":81,"meta":1134,"navigation":85,"path":1143,"seo":1144,"stem":1145,"tags":1146,"__hash__":1147},"blogs\u002F_legacy\u002F2015\u002F2015-08-18-hello-slate.md","Hello Slate",{"type":8,"value":1025,"toc":1127},[1026,1029,1031,1034,1042,1045,1048,1054,1057,1061,1064,1073,1076,1082,1085,1091,1094,1098,1101,1104,1107,1113,1116,1122,1124],[11,1027,1028],{},"UE4中通常的游戏内逻辑使用UMG就可以了，当需要一些独特的功能时就会需要用到Slate。",[11,1030,16],{},[11,1032,1033],{},"Slate是UE4的用户界面系统，UE4编辑器的大部分界面都是由Slate构建的。同时，在编辑器中使用的UMG也是在Slate的基础上封装的。",[11,1035,1036,1037,128],{},"本文参照官方社区文档",[122,1038,1041],{"href":1039,"rel":1040},"https:\u002F\u002Fwiki.unrealengine.com\u002FSlate,_Hello",[126],"Slate, Hello",[133,1043,1044],{"id":1044},"准备工作",[11,1046,1047],{},"要使用Slate，第一步是将其API开放到项目。在项目对应的Build.cs中将下面的代码的注释去掉即可",[33,1049,1052],{"className":1050,"code":1051,"language":38},[36],"\u002F\u002F Uncomment if you are using Slate UI\n\nPrivateDependencyModuleNames.AddRange(new string[] { \"Slate\", \"SlateCore\" });\n",[40,1053,1051],{"__ignoreMap":42},[11,1055,1056],{},"根据UE4版本的不同如果没有这行的直接加上就好了。",[133,1058,1060],{"id":1059},"slatewidget","SlateWidget",[11,1062,1063],{},"创建用于显示文字的Slate控件。",[11,1065,1066,1067,1072],{},"Slate控件的一些特殊的宏和界面定义方式的详情可以参考官方的",[122,1068,1071],{"href":1069,"rel":1070},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FProgramming\u002FSlate\u002FOverview\u002Findex.html",[126],"Slate概述","。",[11,1074,1075],{},"StandardSlateWidget.h",[33,1077,1080],{"className":1078,"code":1079,"language":38},[36],"#pragma once\n#include \"Test_mp.h\" \u002F* \u003C项目头文件 *\u002F\n\nclass SStandardSlateWidget: public SCompoundWidget\n{\nSLATE_BEGIN_ARGS(SStandardSlateWidget){}\n\n\u002F*\u003C参照下面的OwnerHUD的声明 *\u002F\nSLATE_ARGUMENT(TWeakObjectPtr\u003Cclass AHUD>,OwnerHUD)\n\n\nSLATE_END_ARGS()\n\npublic:\n\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\n\u002F\u002F\u002F\u002F\u002F\u003C每一个控件都必须要有这个函数\n\u002F\u002F\u002F\u002F\u002F\u003C构建控件及其子控件\nvoid Construct(const FArguments& InArgs);\nprivate:\n\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\n\u002F\u002F\u002F\u002F\u002F\u003C指向控件的持有者Hud\n\u002F\u002F\u002F\u002F\u002F\u003C使用弱引用持有HUD的指针，因为HUD是使用强引用来持有Widget的。\n\u002F\u002F\u002F\u002F\u002F\u003C如果双方都为强引用的话将会导致解构时形成循环引用并引发内存泄露\nTWeakObjectPtr\u003Cclass AHUD> OwnerHUD;\n\n};\n",[40,1081,1079],{"__ignoreMap":42},[11,1083,1084],{},"StandardSlateWidget.cpp",[33,1086,1089],{"className":1087,"code":1088,"language":38},[36],"#include \"Test_mp.h\"\n#include \"Plugin\u002FStandardSlateWidget.h\"\n \nvoid SStandardSlateWidget::Construct(const FArguments& InArgs)\n{\n    OwnerHUD = InArgs._OwnerHUD;\n \n    ChildSlot\n        .VAlign(VAlign_Fill)\n        .HAlign(HAlign_Fill)\n        [\n            SNew(SOverlay)\n            + SOverlay::Slot()\n            .VAlign(VAlign_Top)\n            .HAlign(HAlign_Center)\n             [\n                 SNew(STextBlock)\n                 .ShadowColorAndOpacity(FLinearColor::Black)\n                 .ColorAndOpacity(FLinearColor::Red)\n                 .ShadowOffset(FIntPoint(-5, 5))\n                 .Font(FSlateFontInfo(\"Veranda\", 24))\n                 .Text(FText::FromString(\"Hello, Slate!\"))\n             ]\n        ];\n \n}\n",[40,1090,1088],{"__ignoreMap":42},[11,1092,1093],{},"在这里使用OwnerHUD并不是必须的，主要的作用是作为参数传递的示范。",[133,1095,1097],{"id":1096},"hud","HUD",[11,1099,1100],{},"通过自定义一个HUD用于Slate控件的展示。添加HUD代码没有什么特殊的地方。",[11,1102,1103],{},"添加好之后直接在BeginPlay中将Widget输出到屏幕即可。",[11,1105,1106],{},"StandardHud.h",[33,1108,1111],{"className":1109,"code":1110,"language":38},[36],"#pragma once\n#include \"GameFramework\u002FHUD.h\"\n#include \"StandardHUD.generated.h\"\n \nclass SStandardSlateWidget;\n \nUCLASS()\nclass AStandardHUD : public AHUD\n{\n    GENERATED_BODY()\n \npublic:\n    AStandardHUD();\n    TSharedPtr\u003CSStandardSlateWidget> myUIWidget;\n \n    void BeginPlay();\n};\n\n",[40,1112,1110],{"__ignoreMap":42},[11,1114,1115],{},"StandardHud.cpp",[33,1117,1120],{"className":1118,"code":1119,"language":38},[36],"#pragma once\n \u002F\u002F Fill out your copyright notice in the Description page of Project Settings.   \n #include \"Test_mp.h\" \n #include \"Plugin\u002FStandardSlateWidget.h\" \n #include \"Plugin\u002FStandardHUD.h\"   \n \nAStandardHUD::AStandardHUD() \n{   \n\n}\n\nvoid AStandardHUD::BeginPlay() \n{     \n    SAssignNew(myUIWidget, SStandardSlateWidget).OwnerHUD(this);       \n    if (GEngine->IsValidLowLevel())     \n    {         \n        GEngine->GameViewport->AddViewportWidgetContent(SNew(SWeakWidget).PossiblyNullContent(myUIWidget.ToSharedRef()));     \n    }       \n    if (myUIWidget.IsValid())     \n    {         \n        myUIWidget->SetVisibility(EVisibility::Visible);     \n    } \n}\n\n",[40,1121,1119],{"__ignoreMap":42},[133,1123,196],{"id":196},[11,1125,1126],{},"原始的教程中还有自定义GameMode的部分，在这里就不执行了。直接在编辑器中将HUD指定为刚刚定义的StandardHud即可。\n指定完成后，点击运行即可在屏幕上方看到“Hello, Slate!”的文字输出了。",{"title":42,"searchDepth":77,"depth":78,"links":1128},[1129,1130,1131,1132],{"id":1044,"depth":77,"text":1044},{"id":1059,"depth":77,"text":1060},{"id":1096,"depth":77,"text":1097},{"id":196,"depth":77,"text":196},"2015-08-18",{"layout":83,"status":84,"published":85,"author":1135,"author_login":87,"author_email":88,"author_url":89,"wordpress_id":1136,"wordpress_url":1137,"date_gmt":1138,"excerpt":1139},{"display_name":87,"login":87,"email":88,"url":89},1472,"\u002F\u002F?p=1472","2015-08-18 11:56:34 +0000",{"type":8,"value":1140},[1141],[11,1142,1028],{},"\u002F2015-08-18-hello-slate",{"title":1023,"description":1028},"_legacy\u002F2015\u002F2015-08-18-hello-slate",[101,103],"nMQL2MFSDju9LkcCXygpyjn248xCbtlgOGdlwP5Xquk",{"id":1149,"title":1150,"body":1151,"date":1133,"description":1155,"extension":81,"meta":1286,"navigation":85,"path":1295,"seo":1296,"stem":1297,"tags":1298,"__hash__":1300},"blogs\u002F_legacy\u002F2015\u002F2015-08-18-slate-icons.md","Slate中图标的使用",{"type":8,"value":1152,"toc":1281},[1153,1156,1158,1161,1164,1167,1173,1176,1182,1185,1191,1194,1197,1203,1207,1210,1213,1216,1219,1225,1228,1234,1237,1246,1249,1252,1255,1258,1261,1264,1272,1275,1278],[11,1154,1155],{},"在Slate控件中，图标的使用除了直接引用图片外，还是有一些其他便利的方法的。",[11,1157,16],{},[11,1159,1160],{},"目前官方的版本已经到4.9.0了，但是由于FMod并没有更新对应版本的插件，项目无法迁移，故而依然使用4.8.3版本。",[133,1162,1163],{"id":1163},"自带图标",[11,1165,1166],{},"UE4自带的图标在对SWidget进行封装时比较容易遇到。UWidget在编辑器中的显示图标使用的就是自带的图标系统。通常为对如下的函数进行覆盖实现：",[33,1168,1171],{"className":1169,"code":1170,"language":38},[36],"const FSlateBrush* UCListViewWidget::GetEditorIcon() \n{     \n  return FUMGStyle::Get().GetBrush(\"Widget.TextBlock\"); \n}\n",[40,1172,1170],{"__ignoreMap":42},[11,1174,1175],{},"这些图标都是在引擎内部预定义的，通过搜索就能看到这些图标的定义。",[33,1177,1180],{"className":1178,"code":1179,"language":38},[36],"\u002F\u002F UMGStyle.cpp  \n\nStyle->Set(\"Widget.NativeWidgetHost\", new IMAGE_BRUSH(TEXT(\"NativeWidgetHost\"), Icon16x16));\n",[40,1181,1179],{"__ignoreMap":42},[11,1183,1184],{},"其中IMAGE_BRUSH是同一个文件中定义的宏",[33,1186,1189],{"className":1187,"code":1188,"language":38},[36],"#define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( Style->RootToContentDir( RelativePath, TEXT(\".png\") ), __VA_ARGS__ )\n",[40,1190,1188],{"__ignoreMap":42},[11,1192,1193],{},"ICON16x16也同样是宏定义，再次就不赘述了。",[11,1195,1196],{},"自带图标也可以直接在控件中进行使用",[33,1198,1201],{"className":1199,"code":1200,"language":38},[36],"const FSlateBrush *m_Icon = FUMGStyle::Get().GetBrush(\"Palette.Icon\");\n \nreturn SNew(STableRow\u003C FFileListItemPtr >, OwnerTable)\n[\nSNew(SHorizontalBox)\n    + SHorizontalBox::Slot()\n    .HAlign(HAlign_Left)\n    .AutoWidth()\n    [\n        SNew(SImage)\n        .Image(m_Icon)\n    ]\n    + SHorizontalBox::Slot()\n    .HAlign(HAlign_Left)\n    [\n        SNew(STextBlock)\n        .Text(FText::FromString(Item->GetDisplayName()))\n        .Font(FSlateFontInfo(FPaths::EngineContentDir() \u002F TEXT(\"Slate\u002FFonts\u002FRoboto-Bold.ttf\"), 12))\n    ]\n];\n",[40,1202,1200],{"__ignoreMap":42},[133,1204,1206],{"id":1205},"icon-font","Icon Font",[11,1208,1209],{},"Icon Font添加图标确实非常的方便，UE4编辑器中也有使用到Font Awesome作为图标显示。",[11,1211,1212],{},"由于Font Awesome比较有名，项目中使用的也是它。",[11,1214,1215],{},"C++中的使用",[11,1217,1218],{},"要在C++中使用Font Awesome，首先要对UFont对象进行生成。",[33,1220,1223],{"className":1221,"code":1222,"language":38},[36],"FontAwesome = Cast\u003CUFont>(StaticLoadObject(UFont::StaticClass(), NULL, TEXT(\"Font'\u002FGame\u002FResource\u002FFont\u002Ffontawesome-webfont.fontawesome-webfont'\")));\n",[40,1224,1222],{"__ignoreMap":42},[11,1226,1227],{},"其中Font部分为直接对导入的字体进行引用复制所得。接下来只要使用STextBlock来使用相应的图标就可以了",[33,1229,1232],{"className":1230,"code":1231,"language":38},[36],"return SNew(STableRow\u003C FFileListItemPtr >, OwnerTable)\n    [\n        SNew(SHorizontalBox)\n        + SHorizontalBox::Slot()\n        .HAlign(HAlign_Left)\n        .AutoWidth()\n        .Padding(FMargin(0.0f, 3.0f, 1.0f, 0.0f))\n        [\n            SNew(STextBlock)\n            .Font(FSlateFontInfo(FontAwesome, 12))\n            .Text(FText::FromString(FString(Item->IsDirectory ? TEXT(\"\\xf07b\" \u002F*fa-folder*\u002F) : TEXT(\"\\xf15b\" \u002F*fa-file*\u002F))))\n        ]\n        + SHorizontalBox::Slot()\n        .HAlign(HAlign_Left)\n        .Padding(FMargin(3.0f, 3.0f, 0.0f, 0.0f))\n        [\n            SNew(STextBlock)\n            .Text(FText::FromString(Item->GetDisplayName()))\n            .Font(FSlateFontInfo(FPaths::EngineContentDir() \u002F TEXT(\"Slate\u002FFonts\u002FRoboto-Bold.ttf\"), 12))\n        ]\n \n    ];\n",[40,1233,1231],{"__ignoreMap":42},[11,1235,1236],{},"如果要在蓝图中进行使用的话，需要首先将字体的使用制定为对应的Icon Font。",[11,1238,1239,1240,1245],{},"通常Icon Font在提供的时候都会有每一个图标对应的Unicode编码，Font Awesome的编码集在[",[122,1241,1244],{"href":1242,"rel":1243},"https:\u002F\u002Ffortawesome.github.io\u002FFont-Awesome\u002Fcheatsheet\u002F",[126],"这里","]。",[11,1247,1248],{},"Font Awesome的编码集页面是可以直接复制对应的字符的，但是也有只提供了编码集的情况出现。",[11,1250,1251],{},"只要有编码集就可以对Icon进行使用了，要输入对应的Unicode码有很多种方式，这里提供两种。",[11,1253,1254],{},"Win+R输入并运行charmap，在其中选择对应的图标并复制其Unicode码。",[11,1256,1257],{},"在Word中输入对应的Unicode码，选中这些值按Alt+X就可以实现转换。",[11,1259,1260],{},"由于UE4编辑器中使用的字体并非对应的Icon Font，所以会以乱码显示，不过并不影响实际使用。",[133,1262,1263],{"id":1263},"排版",[11,1265,1266,1267,1072],{},"使用到图标的时候有时需要对布局进行控制，布局的具体操作可以参看官方的",[122,1268,1271],{"href":1269,"rel":1270},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FProgramming\u002FSlate\u002FWidgets\u002Findex.html",[126],"Slate控件文档",[11,1273,1274],{},"其中需要注意的是，Padding布局使用的是数据结构FMargin。作用参看FMargin本身的构造函数定义即可，只是Padding参数本身对FMargin进行了封装，光看官方的例子会有一定的迷惑性。",[11,1276,1277],{},"对于FMargin，当参数为4个时分别对应Left, Top, Right, Bottom；为2个时对应Horizontal和Vertical；为1个时则对应所有方向。",[11,1279,1280],{},"另外要注意的是在列表中AutoWidth必须手动指定，并不像文档中所描述的一样是默认启动的。",{"title":42,"searchDepth":77,"depth":78,"links":1282},[1283,1284,1285],{"id":1163,"depth":77,"text":1163},{"id":1205,"depth":77,"text":1206},{"id":1263,"depth":77,"text":1263},{"layout":83,"status":84,"published":85,"author":1287,"author_login":87,"author_email":88,"author_url":89,"wordpress_id":1288,"wordpress_url":1289,"date_gmt":1290,"excerpt":1291},{"display_name":87,"login":87,"email":88,"url":89},1524,"\u002F\u002F?p=1524","2015-08-18 04:53:15 +0000",{"type":8,"value":1292},[1293],[11,1294,1155],{},"\u002F2015-08-18-slate-icons",{"title":1150,"description":1155},"_legacy\u002F2015\u002F2015-08-18-slate-icons",[101,103,1299],"Icon","A8mfQicx3BCg5ItNQMw-s9Z2yH3w34f1SwIYUghvJeE",1788763180488]