这一次的例子是关于DXUT的UI。下面先翻译文档中的比较重要的说明。
这个例子开始时定义了两个CDXUTDialog对象:g_HUD和g_SampleUI。一个CDXUTDialog是一个装入了一个或多个控件(按钮等)的容器。对话框(CDXUTDialog)位于程序和控件之间。因此程序可以传递信息和渲染命令给对话框,而对话框保证它的所有控件能够正确收到信息和得到渲染。控件是设计成要和对话框一起使用,不可以单独使用。程序可以不限于一个对话框,他们可以一次用多个,正如例子所做的(两个)。
为了初始化对话框,这个例子第一件事就是使用SetCallback方法来设置事件回调函数。当用户和UI控制对象交互的时候,这些控制对象可以通知程序重要的事件,那么程序就可以根据情况作出反应。这一次程序也初始化了它所需要的额外的字体,这是通过SetFont来完成的。
例子下一步需要做的就是创建所需的控件。这是通过调用AddXXX方法来实现的,例如AddButton。在这个例子中,g_HUD包括了4个按钮。在控件添加完毕以后,它的外观可以被修改。在本例中你可以看到被修改过外观的静态控件、组合盒和带有IME功能的编辑框。
接下来,OnResetDevice函数,包括了几个对对话框和控件的SetSize和SetLocation方法。这是因为当用户改变窗口大小的时候,一些对话框和控件需要改变大小和位置。
为了渲染UI,本例子调用两个对话框的OnRender函数,对话框会渲染所包含的控件。
最后所需的一步就是向控件传递消息。在MsgProc函数中,例子调用了对话框的MsgProc方法来向下传递消息,这个方法需要返回TRUE来表示消息已经被处理。
以上就是文档中我认为比较重要的部分。接下来还是阅读代码。
首先让我们来看看相关的全局变量。
CDXUTDialogResourceManager g_DialogResourceManager; // manager for shared resources of dialogs
CD3DSettingsDlg g_SettingsDlg; // Device settings dialog
CDXUTDialog g_HUD; // dialog for standard controls
CDXUTDialog g_SampleUI; // dialog for sample specific controls
对话框资源管理器= =暂时不知道有什么用,下面应该会用到。设置对话框就不说了,默认的一个对话框。下面两个就是上文提到的对话框。重要的是SampleUI,这个对话框每个例子都不同,专门来放置跟例子有关的UI。
//--------------------------------------------------------------------------------------
// UI control IDs
//--------------------------------------------------------------------------------------
#define IDC_TOGGLEFULLSCREEN 1
#define IDC_TOGGLEREF 3
#define IDC_CHANGEDEVICE 4
#define IDC_EDITBOX1 5
#define IDC_EDITBOX2 6
#define IDC_ENABLEIME 7
#define IDC_DISABLEIME 8
#define IDC_COMBOBOX 9
#define IDC_STATIC 10
#define IDC_OUTPUT 12
#define IDC_SLIDER 13
#define IDC_CHECKBOX 14
#define IDC_CLEAREDIT 15
#define IDC_RADIO1A 16
#define IDC_RADIO1B 17
#define IDC_RADIO1C 18
#define IDC_RADIO2A 19
#define IDC_RADIO2B 20
#define IDC_RADIO2C 21
#define IDC_LISTBOX 22
#define IDC_LISTBOXM 23
这大家都懂的= =
g_HUD.Init( &g_DialogResourceManager );
g_SampleUI.Init( &g_DialogResourceManager );
g_HUD.SetCallback( OnGUIEvent ); int iY = 10;
g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22, VK_F2 );
初始化对话框并且加入控件,省略了很多代码,因为控件实在太多了
// IME-enabled edit box
CDXUTIMEEditBox* pIMEEdit;
CDXUTIMEEditBox::InitDefaultElements( &g_SampleUI );
if( SUCCEEDED( CDXUTIMEEditBox::CreateIMEEditBox( &g_SampleUI, IDC_EDITBOX2,
L"IME-capable edit control with custom styles. Type and press Enter", 20, 390, 600, 45, false, &pIMEEdit ) ) )
{
g_SampleUI.AddControl( pIMEEdit );
pIMEEdit->GetElement( 0 )->iFont = 1;
pIMEEdit->GetElement( 1 )->iFont = 1;
pIMEEdit->GetElement( 9 )->iFont = 1;
pIMEEdit->GetElement( 0 )->TextureColor.Init( D3DCOLOR_ARGB( 128, 255, 255, 255 ) ); // Transparent center
pIMEEdit->SetBorderWidth( 7 );
pIMEEdit->SetTextColor( D3DCOLOR_ARGB( 255, 64, 64, 64 ) );
pIMEEdit->SetCaretColor( D3DCOLOR_ARGB( 255, 64, 64, 64 ) );
pIMEEdit->SetSelectedTextColor( D3DCOLOR_ARGB( 255, 255, 255, 255 ) );
pIMEEdit->SetSelectedBackColor( D3DCOLOR_ARGB( 255, 40, 72, 72 ) );
}
上面是IME编辑框,可以看到代码中对外观进行了一定改变。
2
OnResetDevice函数
g_HUD.SetLocation( pBackBufferSurfaceDesc->Width - 170, 0 );
g_HUD.SetSize( 170, 170 );
g_SampleUI.SetLocation( 0, 0 );
g_SampleUI.SetSize( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
g_SampleUI.GetControl( IDC_STATIC )->SetSize( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height * 6 /
10 );
g_SampleUI.GetControl( IDC_OUTPUT )->SetSize( pBackBufferSurfaceDesc->Width - 170, pBackBufferSurfaceDesc->Height /
4 );
g_SampleUI.GetControl( IDC_EDITBOX1 )->SetLocation( 20, pBackBufferSurfaceDesc->Height - 230 );
g_SampleUI.GetControl( IDC_EDITBOX1 )->SetSize( pBackBufferSurfaceDesc->Width - 40, 32 );
设置对话框和控件的大小和位置。
3
MsgProc函数
// Always allow dialog resource manager calls to handle global messages
// so GUI state is updated correctly
*pbNoFurtherProcessing = CDXUTIMEEditBox::StaticMsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;
*pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;
先让资源管理器和IME编辑框处理消息。
*pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;
*pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;
对话框接着处理。可以看到函数返回一个说明是否需要继续处理的变量值。
不过实际上对话框的MsgProc函数是由DXUT提供的,我们不应该更改。我们需要更改的是上面设定的回调函数。在这个例子中,两个对话框都对应OnGUIEvent函数。
4
OnGUIEvent函数
switch( nControlID )
{
case IDC_TOGGLEFULLSCREEN:
DXUTToggleFullScreen(); break;
case IDC_TOGGLEREF:
DXUTToggleREF(); break;
case IDC_CHANGEDEVICE:
g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() ); break;
可以看到,就是一大段switch代码。根据ID执行代码。