為了結合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; }
沒有留言:
張貼留言