為了結合UE系統以及寫碼方便,UEd繼承wxWidgets的類別進行擴充。原本wxWidgets的類別前綴小寫的wx,UEd繼承後變成首字大寫的Wx,所以可以依此區分是否為原wxWidget內建的型別。
以下列出幾個撰寫編輯器主視窗時常用的類別。當然編輯器不是只有主視窗而已,只是篇幅已經太長,其他像顯示3D物件的部份就另外再寫一篇好了。
WxTrackableFrame
撰寫編輯器會使用到很多類別,主視窗類別需要繼承WxTrackableFrame,這樣按Ctrl+Tab時才會出現在視窗列表裡。因為UEd會使用靜態函式WxTrackableWindow::GetTrackableWindows()取得目前開啓的編輯器,要繼承WxTrackableFrame才能正常支援此機制。
WxPropertyWindowHost
通常編輯器會使用屬性視窗顯示物件屬性,就是在關卡編輯器中點選任一物件後按F4會出現的子視窗。它的類別叫WxPropertyWindowHost,一般編輯器會建立一個WxPropertyWindowHost物件,然後呼叫成員函式SetObject()或SetObjectArray()指定要顯示的UObject。
FNotifyHook
WxPropertyWindowHost視窗在建立時可以指定一個FNotifyHook物件,當使用者修改屬性時會去通知指定的FNotifyHook,所以主視窗類別通常也會繼承FNotifyHook來取得屬性變更通知。雖然UObject也有PostEditChangeProperty()虛擬函式可以覆載,不過要在覆載函式內存取編輯器的話還是用FNotifyHook比較方便。
FDockingParent
有一個以上子視窗的編輯器通常會需要dock功能,讓主視窗類別繼承FDockingParent就可以很方便的支援dock功能。它甚至還會在主選單上自動列出子視窗,可用選單方便地開關子視窗。
以下列出重要的FDockingParent函式:
- GetDockingParentName():用來指定排版設定檔的名稱。子類別必須覆載此純虛擬函式。
- GetDockingParentVersion():用來指定排版設定檔的版號,當增減子視窗時需要遞增版號。子類別必須覆載此純虛擬函式。
- SaveDockingLayout():儲存排版設定檔,可以在專案的config目錄裡找到這個檔案。
- LoadDockingLayout():載入排版設定檔。
- AddDockingWindow(ClientWindow, DockHost, ...):加入要dock的子視窗。DockHost參數可指定dock的方向,如果要讓某個子視窗常駐,可以設為FDockingParent::DH_None。
FSerializableObject
由於UObject的垃圾回收機制是用序列化確認是否要回收,編輯器產生的物件若沒有被其他UObject參照就會被回收掉。所以主視窗類別通常也會繼承FSerializableObject,並且在Serialize()裡序列化需要保留的UObject以免被回收。
當地化
UEd有專用的當地化組態檔,檔名叫UnrealEd,放在Localization目錄各語言版本的子目錄裡。例如國際語言版的路徑是Localization\INT\UnrealEd.int。自訂編輯器如果有需要增加當地化字串,可以在專案目錄下對支援的語言目錄加入對應的UnrealEd檔,然後新增對應的字串設定。
範例
以下程式碼展示一個典型的編輯器主視窗:
class WxMyAssetEditor :
public WxTrackableFrame,
public FDockingParent,
public FNotifyHook,
public FSerializableObject
{
public:
WxMyAssetEditor( wxWindow* Parent, wxWindowID ID, UMyAsset* MyAsset );
~WxMyAssetEditor();
// FDockingParent interfaces
virtual const TCHAR* GetDockingParentName() const ( return TEXT("MyAssetEditor"); )
virtual INT GetDockingParentVersion() const ( return 0; )
// FNotifyHook interface
virtual void NotifyPostChange( void* Src, UProperty* PropertyChanged );
// FSerializableObject interface
virtual void Serialize(FArchive& Ar);
...
private:
DECLARE_EVENT_TABLE()
UMyAsset* m_Asset;
WxPropertyWindowHost* m_PropertyWindowHost;
...
};
主視窗類別的建構子/解構子:
WxMyAssetEditor::WxMyAssetEditor( wxWindow* Parent, wxWindowID ID, UMyAsset* MyAsset ) :
WxTrackableFrame( Parent, ID, TEXT(""), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_sTYLE | wxFRAME_FLOAT_ON_PARENT | wxFRAME_NO_TASKBAR ),
FDockingParent(this),
m_Asset(MyAsset),
m_PropertyWindowHost(NULL)
{
SetTitle( *FString::Printf(LocalizeSecure(LocalizeUnreaEd("MyAssetEditor_F"), *m_MyAsset->GetPathName())) );
SetSize(800, 600);
FWindowUtil::LoadPosSize( TEXT("MyAssetEditor"), this, 256, 256, 800, 600);
m_PropertyWindowHost = new WxPropertyWindowHost;
m_PropertyWindowHost->Create( this, this );
m_PropertyWindowHost->SetObject( m_Asset, EPropertyWindowFlags::ExpandCategories );
AddDockingWindow( m_PropertyWindowHost, FDockingParent::DH_Bottom, *FString::Printf(LocalizeSecure(LocalizeUnreaEd("PropertiesCaption_F"), *m_MyAsset->GetPathName())), *LocalizeUnreadEd("Properties") );
LoadDockingLayout();
...
}
WxMyAssetEditor::~WxMyAssetEditor()
{
SaveDockingLayout();
FWindowUtil::SavePosSize( TEXT("MyAssetEditor"), this );
...
}
要讓內容瀏覽器使用自訂編輯器開啟自訂資源,需要撰寫一個自訂的GenericBrowserType。UDN上已有詳細解說,就不在此贅述。大致如下列程式碼: UBOOL UGenericBrowserType_MyAsset::ShowObjectEditor(UObject* InObject)
{
WxMyAssetEditor* Editor = new WxMyAssetEditor( GApp->EditorFrame, -1, CastChecked<UMyAsset>(InObject), FALSE );
Editor->Show(TRUE);
return TRUE;
}
沒有留言:
張貼留言