SDL入门教程(十一):2、设计按钮ButtonClass

[复制链接]

该用户从未签到

2380

主题

2433

帖子

9139

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9139
QQ
跳转到指定楼层
楼主
发表于 2017-12-19 09:54:16 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

想要查看内容赶紧注册登陆吧!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
2.1:设计框架与基类的接口

        有了更加完善的SurfaceClass的支持,我们可以进行按钮的设计了。接着上一节的话题,按钮除了要给我们表现出来是否被按下的视觉效果,还要起到实际上的作用。一种最简单的思路,既是鼠标在按钮上一旦按下,程序就马上响应。这种思路很朴素,也很实用。大名鼎鼎的QuakeIII的菜单按钮就是这么设计的,这样我们几乎是可以直接使用SDL的事件响应,即:事件不为空——鼠标事件的左键按下——响应处理。
        但是也许我们已经习惯更加人性话的GUI按钮了。比如,如果是不小心点错了,马上响应意味着没有机会改正操作失误。事实上,我们仔细分析当今GUI上的按钮,可以发现按钮的实际效果,是在按下鼠标,并且又松开的时候产生的响应。其实这样说也并不完全准确,更加准确的描述,应该是鼠标既要在按钮上按下,又要在按钮上松开——其实这还是不完整,我想说的是,为了描述这个复杂的状态,我们不得不在ButtonClass中引入几个bool量,以判断按钮是否真正起作用。
        按钮的构成与视觉效果,根据我们之前的知识,大概具有这几类:完全由PictureSurface组成,这又分为两类,两张Picture(out和over)或者三张Picture(再加张down);由TextSurface组成;由一张精灵图的PictureSurafce切分出来。他们的接口几乎是一样的:设置位置和按下时的偏移(setup),扣色(colorkey),添加文字(addText),显示(blit),鼠标事件判断(mouse out, over, down, up 甚至是 up outside)和有效点击(effectiveClick)。所以,我们有理由用基类来规定这些接口。或者说,用ABC(抽象基类)的纯虚函数硬性规定这些接口。

2.2:鼠标事件判断与有效点击

移动:SDL_MOUSEMOTION
触发的开关是鼠标发生了移动。我们需要判断鼠标是否移动到了按钮上,或者移动到了不是按钮区域的地方;
点击:SDL_MOUSEBUTTONDOWN
触发条件是鼠标按下了,我们需要进一步判断是不是左键按下了(gameEvent.button.button == SDL_BUTTON_LEFT ),然后判断是不是在按钮区域内按下的。
松开:SDL_MOUSEBUTTONUP
触发条件是鼠标松开了,我们需要进一步判断是不是左键松开了(gameEvent.button.button == SDL_BUTTON_LEFT ),然后判断是不是在按钮区域内松开的。
按钮外松开:SDL_MOUSEBUTTONUP
触发条件是鼠标松开了,我们需要进一步判断是不是左键松开了(gameEvent.button.button == SDL_BUTTON_LEFT ),然后判断是不是在按钮区域内松开的。
        我们之所以需要做这些判断,是为了构建我们刚才设想中的按钮效果,即有效点击(effectiveClick)。因为有效点击不是通过一次事件的判断完成的,我们通过三个bool量在整个按钮的生命周期类描述按钮所接收到的鼠标事件:inBox鼠标在按钮区域内;clickDown鼠标在按钮区域类被按下过(并且没有在外面松开);clickUp鼠标在按钮区域内松开。我们来看看这段代码吧……我承认,if得很混乱,但是居然能正常工作,呵呵。
bool BaseButton::effectiveClick(const SDL_Event& game_event)
{
    inBox
= this->mouseOver(game_event);
   
if ( this->mouseDown(game_event) == true ){
        clickDown
= true;
        inBox
= true;
    }
   
if ( this->mouseUp(game_event) == true ){
        
if ( clickDown == true )
            clickUp
= true;
        inBox
= true;
    }
   
if ( this->mouseUpOutside(game_event) == true )
        clickDown
= false;

   
if ( inBox == true && clickDown == false ){
        
this->blitOver();
        
return false;
    }
   
else if ( inBox == true && clickDown == true ){
        
if ( clickUp == true ){
            clickUp
= false;
            clickDown
= false;
            
this->blitOver();
            
return true;
        }
else {
            
this->blitDown();
            
return false;
        }
    }
   
else {
        
this->blitOut();
        
return false;
    }
}

        最有意思的是,我们可以把这个函数构建在基类中——即使blitxxx()这类的函数都是纯虚函数——但是他们已经代表了算法。在用不同的派生类调用基类的这个方法的时候,blitxxx()会被替换成相应派生类的版本,从而减少了重复写代码的工作。

2.3:ButtonClass的源代码
http://www.cppblog.com/lf426/archive/2008/04/15/47156.html
分享到:  QQ好友和群QQ好友和群
收藏收藏
回复

使用道具 举报

快速回复高级模式
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表