1.UI文件保存的設(shè)計(jì)缺陷
我們生成.UI文件來保存我們生成的控件數(shù)據(jù),下面是UI結(jié)構(gòu)設(shè)計(jì)圖

這樣的設(shè)計(jì)有缺陷:
以前UI控件最大數(shù)量定CONTROLS_COUNT_MAX= 64,因?yàn)閙_ControlsType為固定數(shù)組,一旦控件數(shù)量超出64,我們就需要將以前的.UI文件轉(zhuǎn)換為現(xiàn)在的UI文件進(jìn)行版本兼容,而我們又不能具體確定好我們的控件上限是多少,每次版本兼容進(jìn)行的轉(zhuǎn)換相當(dāng)麻煩...
改進(jìn):設(shè)為容器,根據(jù)控件數(shù)量,動(dòng)態(tài)讀取保存到.UI文件中
struct S_UIData


{
struct S_UIHead

{
S_UIHead()

{
memset( m_szVer, 0, sizeof(m_szVer) );
m_nControlsType.resize( CONTROLS_COUNT_MAX );
memset( &m_nControlsType[0], 0, sizeof(m_nControlsType) );
strcpy( m_szVer, UI_VER);
m_nControlsCount = 0;
m_dwCreatedDate = 0;
}
~S_UIHead()

{
m_nControlsType.clear();
}

char m_szVer[10];
DWORD m_dwCreatedDate;
S_FrameData m_stFrameData;
int m_nControlsCount;
//int m_nControlsType[CONTROLS_COUNT_MAX];
vector<int> m_nControlsType;
};

S_UIData();
~S_UIData();
void Release();
DWORD LoadOldFile( const char* pszFileName );
DWORD LoadFile( const char* pszFileName );
DWORD SaveFile( const char* pszFileName );
static S_BaseData* NewData( int nType );

S_UIHead m_stHead;
//S_BaseData *m_pstControlData[CONTROLS_COUNT_MAX];
vector< S_BaseData* > m_pstControlData;
};
這個(gè)樣子,以后我們即使控件不夠用了,只需要更改一下上限CONTROLS_COUNT_MAX就OK,但是.UI文件我們卻不需要做版本轉(zhuǎn)換,因?yàn)?UI中的數(shù)據(jù)都是根據(jù)控件數(shù)量來讀取保存的 eg.10個(gè)控件,讀取10個(gè)類型和控件數(shù)據(jù)。
DWORD S_UIData::LoadFile( const char* pszFileName )


{
guard(S_UIData::LoadFile);
assert( pszFileName );
assert( pszFileName[0] != 0 );

FILE *fp = fopen(pszFileName, "rb" );
if ( fp )

{
for( int n=0; n<CONTROLS_COUNT_MAX; n++ )

{
if ( m_pstControlData[n] )

{
delete m_pstControlData[n];
m_pstControlData[n] = NULL;
}
}

fread( &m_stHead.m_szVer, sizeof(m_stHead.m_szVer), 1, fp );
fread( &m_stHead.m_dwCreatedDate, sizeof( DWORD ) , 1, fp );
fread( &m_stHead.m_stFrameData, sizeof( S_FrameData ) , 1, fp );
fread( &m_stHead.m_nControlsCount, sizeof( int ) , 1, fp );
fread( &m_stHead.m_nControlsType[0],sizeof(int)*m_stHead.m_nControlsCount,1,fp);
//fread( &m_stHead, sizeof(m_stHead), 1, fp );

if ( strcmp( m_stHead.m_szVer, UI_VER ) != 0 )

{
fclose(fp);
MessageBox( NULL, "讀取的*.UI文件版本不一樣!", "失敗", MB_OK );
return 0;
}

assert( m_stHead.m_nControlsCount < CONTROLS_COUNT_MAX );

for( int n=0; n<m_stHead.m_nControlsCount; n++ )

{
m_pstControlData[n] = NewData( m_stHead.m_nControlsType[n] );
switch( m_stHead.m_nControlsType[n] )

{
case Type_Button:
fread( m_pstControlData[n], sizeof(S_ButtonData), 1, fp );
break;
case Type_CheckBox:
fread( m_pstControlData[n], sizeof(S_CheckBoxData), 1, fp );
break;
case Type_Edit:
fread( m_pstControlData[n], sizeof(S_EditData), 1, fp );
break;
case Type_Text:
fread( m_pstControlData[n], sizeof(S_TextData), 1, fp );
break;
case Type_List:
fread( m_pstControlData[n], sizeof(S_ListData), 1, fp );
break;
case Type_ListImg:
fread( m_pstControlData[n], sizeof(S_ListImgData), 1, fp );
break;
case Type_ScrollBar:
fread( m_pstControlData[n], sizeof(S_ScrollBarData), 1, fp );
break;
case Type_ScrollBarEx:
fread( m_pstControlData[n], sizeof(S_ScrollBarExData), 1, fp );
break;
case Type_ComboBox:
fread( m_pstControlData[n], sizeof(S_ComboBoxData), 1, fp );
break;
case Type_Picture:
fread( m_pstControlData[n], sizeof(S_PictureData), 1, fp );
break;
case Type_Progress:
fread( m_pstControlData[n], sizeof(S_ProgressData), 1, fp );
break;
case Type_Tab:
fread( m_pstControlData[n], sizeof(S_TabData), 1, fp );
break;
case Type_ListEx:
fread( m_pstControlData[n], sizeof(S_ListExData), 1, fp );
break;
default:
assert( false );
break;
}
}

fclose(fp);
return m_stHead.m_dwCreatedDate;
}
return 0;
unguard;
}

DWORD S_UIData::SaveFile( const char* pszFileName )


{
//time_t osBinaryTime; // C run-time time (defined in <time.h>)
//time( &osBinaryTime );
//m_stHead.m_dwCreatedDate = (DWORD)osBinaryTime;
assert( pszFileName );
//
DWORD dwVer = 0;
for( int n=0; n<m_stHead.m_nControlsCount; n++ )

{
int nIdLength = strlen(m_pstControlData[n]->m_szID);
assert( nIdLength > 0 );
for( int i=0; i<nIdLength; i++ )

{
dwVer += m_pstControlData[n]->m_szID[i];
}
}
dwVer = dwVer*m_stHead.m_nControlsCount + 1;
m_stHead.m_dwCreatedDate = dwVer;

FILE *fp = fopen( pszFileName, "w+b" );
if ( fp )

{
fwrite( &m_stHead.m_szVer, sizeof(m_stHead.m_szVer), 1, fp );
fwrite( &m_stHead.m_dwCreatedDate, sizeof( m_stHead.m_dwCreatedDate ) , 1, fp );
fwrite( &m_stHead.m_stFrameData, sizeof( m_stHead.m_stFrameData ) , 1, fp );
fwrite( &m_stHead.m_nControlsCount, sizeof( m_stHead.m_nControlsCount ) , 1, fp );

//fwrite( &m_stHead,
// sizeof(m_stHead.m_szVer)+sizeof(m_stHead.m_dwCreatedDate)+sizeof(m_stHead.m_stFrameData)+sizeof(m_stHead.m_nControlsCount),
// 1, fp );
//按容器中的空間數(shù)量進(jìn)行讀取
fwrite( &m_stHead.m_nControlsType[0],sizeof(int)*m_stHead.m_nControlsCount, 1, fp );

for( int n=0; n<m_stHead.m_nControlsCount; n++ )

{
switch( m_stHead.m_nControlsType[n] )

{
case Type_Button:
SAVE_CONTROL( S_ButtonData );
break;
case Type_CheckBox:
SAVE_CONTROL( S_CheckBoxData );
break;
case Type_Edit:
SAVE_CONTROL( S_EditData );
break;
case Type_Text:
SAVE_CONTROL( S_TextData );
break;
case Type_List:
SAVE_CONTROL( S_ListData );
break;
case Type_ListImg:
SAVE_CONTROL( S_ListImgData );
break;
case Type_ScrollBar:
SAVE_CONTROL( S_ScrollBarData );
break;
case Type_ScrollBarEx:
SAVE_CONTROL( S_ScrollBarExData );
break;
case Type_ComboBox:
SAVE_CONTROL( S_ComboBoxData );
break;
case Type_Picture:
SAVE_CONTROL( S_PictureData );
break;
case Type_Progress:
SAVE_CONTROL( S_ProgressData );
break;
case Type_Tab:
SAVE_CONTROL( S_TabData );
break;
case Type_ListEx:
SAVE_CONTROL( S_ListExData );
break;
default:
assert(false);
break;
}
}
fclose(fp);
return dwVer;
}
return 0;
}
最后需要注意的就是 字節(jié)對(duì)齊 問題
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2.UI整體設(shè)計(jì)思路
設(shè)計(jì)思路:我們游戲中的UI常劃分為常見UI模塊,如Friend面板,Property面板,Pack面板,Pet面板等等.
每個(gè)模塊中的單個(gè)UI也處理消息,渲染...
我們創(chuàng)建一個(gè)UIMgr來管理這些大的UI模塊(即UIFrame),每個(gè)UIFrame來管理大模塊中的單個(gè)小UI控件
然后在應(yīng)用程序中分別調(diào)用UIMgr來處理
一句話:app管理UIMgr,UIMgr管理UIFrame, UIFrame管理單個(gè)UI控件(UI_Object)
我們的應(yīng)用程序擁有主要函數(shù):
virtual HRESULT FrameMove(); //更新
virtual HRESULT Render(); //渲染
virtual LRESULT MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
分別調(diào)用 theUIMgr.FrameMove(), theUIMgr.Render(), theUIMgr().MsgProc(...)
theUIMgr是一個(gè)UIFrame的容器 vector<UIFrame*> vecFrame;
內(nèi)部調(diào)用UIFrame的消息處理
for( int i = 0; i < vecFrame.size(); i++ )
vecFrame[i]->FrameMove();
vecFrame[i]->Render();
vecFrame[i]->OnMouseMove(...);
vecFrame[i]->OnLButtonDown(...);
vecFrame[i]->MsgProc(...);
UIFrame是單個(gè)UI控件的容器 vector<UI_Object*> m_vecChild;
for( int i = 0; i < m_vecChild.size(); i++ )
m_vecChild[i]->FrameMove();
....
m_vecChild[i]->Render();
....
m_vecChild[i]->OnMouseMove(...);
所有的UI消息都能夠處理了,所有處理要依據(jù)先后關(guān)系,如一個(gè)面板消息被一個(gè)UI處理后,那么要返回true,
其他的UI將不會(huì)重復(fù)處理
問題是我們會(huì)將我們的UI做成一個(gè)UI 靜態(tài)庫,那么我們按鈕按下觸發(fā)的功能,無法提前設(shè)置好,
解決方法: 設(shè)置回調(diào)函數(shù)
eg:
CHR_UI_Frame下的回調(diào)函數(shù)接口
typedef bool (*funOnClick)( OUT CHR_UI_Object* pSender );
typedef bool (*funOnRBtnDown)( OUT CHR_UI_Object* pSender );
typedef bool (*funRun)(void);
typedef bool (*funRender)(void);
CHR_UI_Edit下的回調(diào)函數(shù)指針
typedef void (*funOnEnter)( OUT CHR_UI_Object* pSender, OUT const char *szData );
typedef void (*funOnTab)( OUT CHR_UI_Object* pSender, OUT const char* szData);
CHR_UI_Button下的函數(shù)接口
typedef bool (*funOnButtonClick)( OUT CHR_UI_Object* pSender );
...
在WM_LBUTTONUP中調(diào)用觸發(fā)
if ( m_pFunOnButtonClick ) //函數(shù)指針
{
if ( m_pFunOnButtonClick( this ) == false )
{
if ( m_pFather && strcmp( m_pstData->m_szID, "ID_BUTTON_CLOSE" ) == 0 )
{
m_pFather->SetVisable( false );
}
}
}
m_pID_BUTTON_SelectRole.SetButtonClickFunc( ID_BUTTON_SELECTROLEOnButtonDown );
posted on 2010-09-03 14:14
風(fēng)輕云淡 閱讀(564)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
UI