在hge中实现自己的滚动条

在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 ;
}

怎么样,代码很简单吧?但是因为太简单了,所以很多场合并不适用,比如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 ;
}

运行效果:



当然了,这个滚动条还是很挫的,你还想写更好的滚动条吗?比如说希望实现word那样,会随着内容的增加而缩放滚动条游标的大小?

那么那么,你应该自己从hgeGUIobject继承,重新写一个自己专用slider了,毕竟haaf写的那一套gui控件大都不好用,教学意义更大于实用意义呢,有了上面的参考,相信也不难吧。

如果你想知道更多关于hgeGUIobject的细节,你可以看这位前辈的介绍:
http://blog.csdn.net/tkokof1/article/details/5851682





你可能感兴趣的:(在hge中实现自己的滚动条)