关于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