在hge中实现自己的滚动条
关于hge gui的资料似乎很少,刚好我又想用到hge的滚动条,于是就来就随便扯一下hge的滚动条。
让我们先来分析一下它的实现代码吧。
/*
**以下为声明
** hgeGUISlider
*/
BARRELATIVE
//这些是滚动条的三种模式,顾名思义咯。
//bar,类似安装程序的进度槽,直接让你拉
//barrelative和bar差不多,但是只能从中间开始拉到左边或右边尽头
//以上两个bar都是用拉伸纹理实现的,所以效果很多时候不好....
//slider就是滚动条游标啦
#define HGESLIDER_BAR 0
#define HGESLIDER_BARRELATIVE 1
#define HGESLIDER_SLIDER 2
class hgeGUISlider : public hgeGUIObject
{
public :
hgeGUISlider( int id, float x, float y, float w, float h, HTEXTURE tex, float tx, float ty, float sw, float sh, bool vertical = false );
virtual ~ hgeGUISlider();
void SetMode( float _fMin, float _fMax, int _mode) { fMin = _fMin; fMax = _fMax; mode = _mode; }
void SetValue( float _fVal);
float GetValue() const { return fVal; }//获取滚动条的数值
virtual void Render();
virtual bool MouseMove( float x, float y);
virtual bool MouseLButton( bool bDown);
private ://此处源代码被声明为private,如果想要用于被继承,应该改成protected
bool bPressed;
bool bVertical;
int mode;
float fMin, fMax, fVal;
float sl_w, sl_h;
hgeSprite * sprSlider;
};
/*
**以下为实现
** hgeGUISlider
*/
hgeGUISlider::hgeGUISlider( int _id, float x, float y, float w, float h, HTEXTURE tex, float tx, float ty, float sw, float sh, bool vertical)
{
//初始化一些父类的数据
id = _id;
bStatic = false ;
bVisible = true ;
bEnabled = true ;
bPressed = false ;
bVertical = vertical;//该滚动条是否垂直,不是则以水平方式表示
rect.Set(x, y, x + w, y + h);//该rect既为控件在窗口内的响应范围。
mode = HGESLIDER_BAR;
fMin = 0 ; fMax = 100 ; fVal = 50 //定义滚动条最低时,最高时,初始化时的数值 ;
sl_w = sw; sl_h = sh;//只在slider模式中有用,表示滚动条游标的宽和高
sprSlider = new hgeSprite(tex, tx, ty, sw, sh);//如果是在slider模式,这就是代表游标的精灵,如果在另两个bar模式,就是代表进度的精灵
}
hgeGUISlider:: ~ hgeGUISlider()
{
if (sprSlider) delete sprSlider;
}
void hgeGUISlider::SetValue( float _fVal)//设置滚动条的数值
{
if (_fVal < fMin) fVal = fMin;
else if (_fVal > fMax) fVal = fMax;
else fVal = _fVal;
}
void hgeGUISlider::Render()
{
//没什么好说,就是根据进度条(fval)的值和控件响应区域(rect)来画出不同的sprSlider
float
xx, yy;
float x1,y1,x2,y2;
xx = rect.x1 + (rect.x2 - rect.x1) * (fVal - fMin) / (fMax - fMin);
yy = rect.y1 + (rect.y2 - rect.y1) * (fVal - fMin) / (fMax - fMin);
if (bVertical)
switch (mode)
{
case HGESLIDER_BAR: x1 = rect.x1; y1 = rect.y1; x2 = rect.x2; y2 = yy; break ;
case HGESLIDER_BARRELATIVE: x1 = rect.x1; y1 = (rect.y1 + rect.y2) / 2 ; x2 = rect.x2; y2 = yy; break ;
case HGESLIDER_SLIDER: x1 = (rect.x1 + rect.x2 - sl_w) / 2 ; y1 = yy - sl_h / 2 ; x2 = (rect.x1 + rect.x2 + sl_w) / 2 ; y2 = yy + sl_h / 2 ; break ;
}
else
switch (mode)
{
case HGESLIDER_BAR: x1 = rect.x1; y1 = rect.y1; x2 = xx; y2 = rect.y2; break ;
case HGESLIDER_BARRELATIVE: x1 = (rect.x1 + rect.x2) / 2 ; y1 = rect.y1; x2 = xx; y2 = rect.y2; break ;
case HGESLIDER_SLIDER: x1 = xx - sl_w / 2 ; y1 = (rect.y1 + rect.y2 - sl_h) / 2 ; x2 = xx + sl_w / 2 ; y2 = (rect.y1 + rect.y2 + sl_h) / 2 ; break ;
}
sprSlider -> RenderStretch(x1, y1, x2, y2);
}
bool hgeGUISlider::MouseLButton( bool bDown)
{
//如果控件响应区域内有被摁住,做下标记
bPressed = bDown;
return false ;
}
bool hgeGUISlider::MouseMove( float x, float y)
{
//这个就是实现游标/进度条移动的代码了,只有鼠标摁下时移动才会执行。
if (bPressed)
{
if (bVertical)
{
if (y > rect.y2 - rect.y1) y = rect.y2 - rect.y1;
if (y < 0 ) y = 0 ;
fVal = fMin + (fMax - fMin) * y / (rect.y2 - rect.y1);
}
else
{
if (x > rect.x2 - rect.x1) x = rect.x2 - rect.x1;
if (x < 0 ) x = 0 ;
fVal = fMin + (fMax - fMin) * x / (rect.x2 - rect.x1);
}
return true ;
}
return false ;
}
**以下为声明
** hgeGUISlider
*/
BARRELATIVE
//这些是滚动条的三种模式,顾名思义咯。
//bar,类似安装程序的进度槽,直接让你拉
//barrelative和bar差不多,但是只能从中间开始拉到左边或右边尽头
//以上两个bar都是用拉伸纹理实现的,所以效果很多时候不好....
//slider就是滚动条游标啦
#define HGESLIDER_BAR 0
#define HGESLIDER_BARRELATIVE 1
#define HGESLIDER_SLIDER 2
class hgeGUISlider : public hgeGUIObject
{
public :
hgeGUISlider( int id, float x, float y, float w, float h, HTEXTURE tex, float tx, float ty, float sw, float sh, bool vertical = false );
virtual ~ hgeGUISlider();
void SetMode( float _fMin, float _fMax, int _mode) { fMin = _fMin; fMax = _fMax; mode = _mode; }
void SetValue( float _fVal);
float GetValue() const { return fVal; }//获取滚动条的数值
virtual void Render();
virtual bool MouseMove( float x, float y);
virtual bool MouseLButton( bool bDown);
private ://此处源代码被声明为private,如果想要用于被继承,应该改成protected
bool bPressed;
bool bVertical;
int mode;
float fMin, fMax, fVal;
float sl_w, sl_h;
hgeSprite * sprSlider;
};
/*
**以下为实现
** hgeGUISlider
*/
hgeGUISlider::hgeGUISlider( int _id, float x, float y, float w, float h, HTEXTURE tex, float tx, float ty, float sw, float sh, bool vertical)
{
//初始化一些父类的数据
id = _id;
bStatic = false ;
bVisible = true ;
bEnabled = true ;
bPressed = false ;
bVertical = vertical;//该滚动条是否垂直,不是则以水平方式表示
rect.Set(x, y, x + w, y + h);//该rect既为控件在窗口内的响应范围。
mode = HGESLIDER_BAR;
fMin = 0 ; fMax = 100 ; fVal = 50 //定义滚动条最低时,最高时,初始化时的数值 ;
sl_w = sw; sl_h = sh;//只在slider模式中有用,表示滚动条游标的宽和高
sprSlider = new hgeSprite(tex, tx, ty, sw, sh);//如果是在slider模式,这就是代表游标的精灵,如果在另两个bar模式,就是代表进度的精灵
}
hgeGUISlider:: ~ hgeGUISlider()
{
if (sprSlider) delete sprSlider;
}
void hgeGUISlider::SetValue( float _fVal)//设置滚动条的数值
{
if (_fVal < fMin) fVal = fMin;
else if (_fVal > fMax) fVal = fMax;
else fVal = _fVal;
}
void hgeGUISlider::Render()
{
//没什么好说,就是根据进度条(fval)的值和控件响应区域(rect)来画出不同的sprSlider
float x1,y1,x2,y2;
xx = rect.x1 + (rect.x2 - rect.x1) * (fVal - fMin) / (fMax - fMin);
yy = rect.y1 + (rect.y2 - rect.y1) * (fVal - fMin) / (fMax - fMin);
if (bVertical)
switch (mode)
{
case HGESLIDER_BAR: x1 = rect.x1; y1 = rect.y1; x2 = rect.x2; y2 = yy; break ;
case HGESLIDER_BARRELATIVE: x1 = rect.x1; y1 = (rect.y1 + rect.y2) / 2 ; x2 = rect.x2; y2 = yy; break ;
case HGESLIDER_SLIDER: x1 = (rect.x1 + rect.x2 - sl_w) / 2 ; y1 = yy - sl_h / 2 ; x2 = (rect.x1 + rect.x2 + sl_w) / 2 ; y2 = yy + sl_h / 2 ; break ;
}
else
switch (mode)
{
case HGESLIDER_BAR: x1 = rect.x1; y1 = rect.y1; x2 = xx; y2 = rect.y2; break ;
case HGESLIDER_BARRELATIVE: x1 = (rect.x1 + rect.x2) / 2 ; y1 = rect.y1; x2 = xx; y2 = rect.y2; break ;
case HGESLIDER_SLIDER: x1 = xx - sl_w / 2 ; y1 = (rect.y1 + rect.y2 - sl_h) / 2 ; x2 = xx + sl_w / 2 ; y2 = (rect.y1 + rect.y2 + sl_h) / 2 ; break ;
}
sprSlider -> RenderStretch(x1, y1, x2, y2);
}
bool hgeGUISlider::MouseLButton( bool bDown)
{
//如果控件响应区域内有被摁住,做下标记
bPressed = bDown;
return false ;
}
bool hgeGUISlider::MouseMove( float x, float y)
{
//这个就是实现游标/进度条移动的代码了,只有鼠标摁下时移动才会执行。
if (bPressed)
{
if (bVertical)
{
if (y > rect.y2 - rect.y1) y = rect.y2 - rect.y1;
if (y < 0 ) y = 0 ;
fVal = fMin + (fMax - fMin) * y / (rect.y2 - rect.y1);
}
else
{
if (x > rect.x2 - rect.x1) x = rect.x2 - rect.x1;
if (x < 0 ) x = 0 ;
fVal = fMin + (fMax - fMin) * x / (rect.x2 - rect.x1);
}
return true ;
}
return false ;
}
怎么样,代码很简单吧?但是因为太简单了,所以很多场合并不适用,比如silder模式。我还想要鼠标覆盖游标后,游标图片改变啊,我还想游标的后面有个进度条来提示我游标的移动范围啊!
如果你想重用这份代码,那么你可以通过继承hgeGUISlider来实现。可是这货竟然用private保护了几个关键的数据,那么只好霸王硬上弓,把private改成protected了,至少这只是修改一下头文件,不用重新编译hge的代码,下面给出这么做的一个实例,你可以通过鼠标,键盘的方向键来移动游标。
PS:这次使用到的贴图资源我也顺便给出吧:)
/*
** base on hge_tut01 - Minimal HGE application
*/
#include " ..\..\include\hge.h "
#include " ..\..\include\hgefont.h "
#include " ..\..\include\hgeguictrls.h "
HGE * hge = 0 ;
//////////////////////////////////////////////////////////////////////// /
class MySlider: public hgeGUISlider
{
public :
MySlider( int id, float x, float y):
hgeGUISlider(id,x,y, 0 , 0 , 0 , 0 , 0 , 0 , 0 )
{
m_tex_usl = hge -> Texture_Load( " Dummy.png " );
m_tex_ovr = hge -> Texture_Load( " Dummy_over.png " );
m_tex_clk = hge -> Texture_Load( " Dummy_click.png " );
m_tex_bak = hge -> Texture_Load( " Back.png " );
int w = hge -> Texture_GetWidth(m_tex_bak);
int h = hge -> Texture_GetHeight(m_tex_bak);
rect.Set(x, y, x + w, y + h);
sl_w = hge -> Texture_GetWidth(m_tex_usl);
sl_h = hge -> Texture_GetHeight(m_tex_usl);
sprSlider -> SetTexture(m_tex_usl);
sprSlider -> SetTextureRect( 0 , 0 , sl_w, sl_h);
m_sprBack = new hgeSprite(m_tex_bak, 0 , 0 ,
hge -> Texture_GetWidth(m_tex_bak),
hge -> Texture_GetHeight(m_tex_bak));
hgeGUISlider::SetMode( 0 , 100.0f , HGESLIDER_SLIDER);
hgeGUISlider::SetValue( 50.0f );
}
~ MySlider()
{
hge -> Texture_Free(m_tex_usl);
hge -> Texture_Free(m_tex_ovr);
hge -> Texture_Free(m_tex_clk);
hge -> Texture_Free(m_tex_bak);
delete m_sprBack;
}
virtual void Render()
{
m_sprBack -> Render(rect.x1, rect.y1);
hgeGUISlider::Render();
}
virtual void MouseOver( bool bOver)
{
bOver ?
sprSlider -> SetTexture(m_tex_ovr):
sprSlider -> SetTexture(m_tex_usl);
}
virtual bool MouseLButton( bool bDown)
{
if (bDown)
sprSlider -> SetTexture(m_tex_clk);
return hgeGUISlider::MouseLButton(bDown);
}
private :
HTEXTURE m_tex_usl;
HTEXTURE m_tex_ovr;
HTEXTURE m_tex_clk;
HTEXTURE m_tex_bak;
hgeSprite * m_sprBack;
};
//////////////////////////////////////////////////////////////////////// /
hgeGUISlider * slider = 0 ;
hgeGUI * gui = 0 ;
hgeFont * fnt = 0 ;
int slider_id = 100 ;
float slider_value = 0 ;
bool FrameFunc()
{
float dt = hge -> Timer_GetDelta();
if (hge -> Input_KeyDown(HGEK_ESCAPE))
return true ;
if (hge -> Input_GetKeyState(HGEK_LEFT))
{
slider_value -= 10.0f * dt;
((hgeGUISlider * )gui -> GetCtrl(slider_id)) -> SetValue(slider_value);
}
else if (hge -> Input_GetKeyState(HGEK_LEFT))
{
slider_value += 10.0f * dt;
((hgeGUISlider * )gui -> GetCtrl(slider_id)) -> SetValue(slider_value);
}
if (hge -> Input_GetKeyState(HGEK_ESCAPE)) return true ;
if (gui)
{
int id = gui -> Update(hge -> Timer_GetDelta());
if (id == slider_id)
slider_value = ((hgeGUISlider * )gui -> GetCtrl(id)) -> GetValue();
}
return false ;
}
bool RenderFunc()
{
hge -> Gfx_Clear( 0 );
hge -> Gfx_BeginScene();
if (gui)
gui -> Render();
if (fnt)
fnt -> printf( 22 , 130 , HGETEXT_LEFT, " the value of the slider is: %.4f. " , slider_value);
hge -> Gfx_EndScene();
return false ;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int )
{
hge = hgeCreate(HGE_VERSION);
hge -> System_SetState(HGE_FRAMEFUNC, FrameFunc);
hge -> System_SetState(HGE_RENDERFUNC, RenderFunc);
hge -> System_SetState(HGE_TITLE, " HGE GUI SLIDER DEMO " );
hge -> System_SetState(HGE_WINDOWED, true );
hge -> System_SetState(HGE_SCREENWIDTH, 400 );
hge -> System_SetState(HGE_SCREENHEIGHT, 300 );
hge -> System_SetState(HGE_HIDEMOUSE, false );
if (hge -> System_Initiate())
{
gui = new hgeGUI();
slider = new MySlider(slider_id, 20 , 50 );
slider_value = slider -> GetValue();
fnt = new hgeFont( " font1.fnt " );
fnt -> SetColor( 0xFFFFFFFF );
gui -> AddCtrl(slider);
hge -> System_Start();
gui -> DelCtrl(slider_id);
delete gui;
delete fnt;
}
else
MessageBox(NULL, hge -> System_GetErrorMessage(), " Error " , MB_OK | MB_ICONERROR | MB_APPLMODAL);
hge -> System_Shutdown();
hge -> Release();
return 0 ;
}
** base on hge_tut01 - Minimal HGE application
*/
#include " ..\..\include\hge.h "
#include " ..\..\include\hgefont.h "
#include " ..\..\include\hgeguictrls.h "
HGE * hge = 0 ;
//////////////////////////////////////////////////////////////////////// /
class MySlider: public hgeGUISlider
{
public :
MySlider( int id, float x, float y):
hgeGUISlider(id,x,y, 0 , 0 , 0 , 0 , 0 , 0 , 0 )
{
m_tex_usl = hge -> Texture_Load( " Dummy.png " );
m_tex_ovr = hge -> Texture_Load( " Dummy_over.png " );
m_tex_clk = hge -> Texture_Load( " Dummy_click.png " );
m_tex_bak = hge -> Texture_Load( " Back.png " );
int w = hge -> Texture_GetWidth(m_tex_bak);
int h = hge -> Texture_GetHeight(m_tex_bak);
rect.Set(x, y, x + w, y + h);
sl_w = hge -> Texture_GetWidth(m_tex_usl);
sl_h = hge -> Texture_GetHeight(m_tex_usl);
sprSlider -> SetTexture(m_tex_usl);
sprSlider -> SetTextureRect( 0 , 0 , sl_w, sl_h);
m_sprBack = new hgeSprite(m_tex_bak, 0 , 0 ,
hge -> Texture_GetWidth(m_tex_bak),
hge -> Texture_GetHeight(m_tex_bak));
hgeGUISlider::SetMode( 0 , 100.0f , HGESLIDER_SLIDER);
hgeGUISlider::SetValue( 50.0f );
}
~ MySlider()
{
hge -> Texture_Free(m_tex_usl);
hge -> Texture_Free(m_tex_ovr);
hge -> Texture_Free(m_tex_clk);
hge -> Texture_Free(m_tex_bak);
delete m_sprBack;
}
virtual void Render()
{
m_sprBack -> Render(rect.x1, rect.y1);
hgeGUISlider::Render();
}
virtual void MouseOver( bool bOver)
{
bOver ?
sprSlider -> SetTexture(m_tex_ovr):
sprSlider -> SetTexture(m_tex_usl);
}
virtual bool MouseLButton( bool bDown)
{
if (bDown)
sprSlider -> SetTexture(m_tex_clk);
return hgeGUISlider::MouseLButton(bDown);
}
private :
HTEXTURE m_tex_usl;
HTEXTURE m_tex_ovr;
HTEXTURE m_tex_clk;
HTEXTURE m_tex_bak;
hgeSprite * m_sprBack;
};
//////////////////////////////////////////////////////////////////////// /
hgeGUISlider * slider = 0 ;
hgeGUI * gui = 0 ;
hgeFont * fnt = 0 ;
int slider_id = 100 ;
float slider_value = 0 ;
bool FrameFunc()
{
float dt = hge -> Timer_GetDelta();
if (hge -> Input_KeyDown(HGEK_ESCAPE))
return true ;
if (hge -> Input_GetKeyState(HGEK_LEFT))
{
slider_value -= 10.0f * dt;
((hgeGUISlider * )gui -> GetCtrl(slider_id)) -> SetValue(slider_value);
}
else if (hge -> Input_GetKeyState(HGEK_LEFT))
{
slider_value += 10.0f * dt;
((hgeGUISlider * )gui -> GetCtrl(slider_id)) -> SetValue(slider_value);
}
if (hge -> Input_GetKeyState(HGEK_ESCAPE)) return true ;
if (gui)
{
int id = gui -> Update(hge -> Timer_GetDelta());
if (id == slider_id)
slider_value = ((hgeGUISlider * )gui -> GetCtrl(id)) -> GetValue();
}
return false ;
}
bool RenderFunc()
{
hge -> Gfx_Clear( 0 );
hge -> Gfx_BeginScene();
if (gui)
gui -> Render();
if (fnt)
fnt -> printf( 22 , 130 , HGETEXT_LEFT, " the value of the slider is: %.4f. " , slider_value);
hge -> Gfx_EndScene();
return false ;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int )
{
hge = hgeCreate(HGE_VERSION);
hge -> System_SetState(HGE_FRAMEFUNC, FrameFunc);
hge -> System_SetState(HGE_RENDERFUNC, RenderFunc);
hge -> System_SetState(HGE_TITLE, " HGE GUI SLIDER DEMO " );
hge -> System_SetState(HGE_WINDOWED, true );
hge -> System_SetState(HGE_SCREENWIDTH, 400 );
hge -> System_SetState(HGE_SCREENHEIGHT, 300 );
hge -> System_SetState(HGE_HIDEMOUSE, false );
if (hge -> System_Initiate())
{
gui = new hgeGUI();
slider = new MySlider(slider_id, 20 , 50 );
slider_value = slider -> GetValue();
fnt = new hgeFont( " font1.fnt " );
fnt -> SetColor( 0xFFFFFFFF );
gui -> AddCtrl(slider);
hge -> System_Start();
gui -> DelCtrl(slider_id);
delete gui;
delete fnt;
}
else
MessageBox(NULL, hge -> System_GetErrorMessage(), " Error " , MB_OK | MB_ICONERROR | MB_APPLMODAL);
hge -> System_Shutdown();
hge -> Release();
return 0 ;
}
运行效果:
当然了,这个滚动条还是很挫的,你还想写更好的滚动条吗?比如说希望实现word那样,会随着内容的增加而缩放滚动条游标的大小?
那么那么,你应该自己从hgeGUIobject继承,重新写一个自己专用slider了,毕竟haaf写的那一套gui控件大都不好用,教学意义更大于实用意义呢,有了上面的参考,相信也不难吧。
如果你想知道更多关于hgeGUIobject的细节,你可以看这位前辈的介绍:
http://blog.csdn.net/tkokof1/article/details/5851682