用CEGUI做界面将近3个月了,比较忙,而且自己懒了许多,没能像以前那样抽出大量时间研究CEGUI,查阅更多的资料书籍,只是在工作间隙,将官网上的一些资料和同事推荐的《CEGUI深入解析》看了看。
国人写的这本书还是不错的,从中我学到的一些CEGUI很重要的知识,希望更多的中国人出更多的技术书籍,让后人受益。这本书我断断续续3个月才看完,实在是看得很慢。最近两天有时间,在看完之后,为了加深自己的理解,根据书中的推荐,写了一个Timer控件,来熟悉一些CEGUI的控件创建,使用过程。在这过程中,有些地方不好搞,特别是CEGUILayoutEditor编辑器的源码编译比较麻烦,不过用了一天时间,基本搞通了整个流程,这里记录总结一下,以便日后回顾。
本人使用CEGUI 0.7.4 和 CEGUILayoutEditor 0.7.1(因为官网主页最新的是0.7.1的)
通过分析,我们的计时器控件只需要继承自CEGUI::PushButton控件即可,将其所有图片设置同一张背景图。然后在控件的构造函数中,订阅窗口每帧的更新事件,并在事件处理函数中完成计时,文本显示,触发事件等功能。下面是计时器控件的属性相关代码:
/*********************************************************************** filename: CEGUITimerWindowProperties.h created: 7/31/2013 author: xujie *************************************************************************/ #ifndef _CEGUITimerWindowProperties_h_ #define _CEGUITimerWindowProperties_h_ #include "CEGUIProperty.h" // Start of CEGUI namespace section namespace CEGUI { namespace TimerWindowProperties { class TimerFormatText : public Property { public: TimerFormatText() : Property( "TimerFormatText", "Property to get/set the text of timer. Value is a String.",//$(CurrentTime) "$(CurrentTime)") {} String get(const PropertyReceiver* receiver) const; void set(PropertyReceiver* receiver, const String& value); }; class TotalTime : public Property { public: TotalTime() : Property( "TotalTime", "Property to get/set the total time of timer. Value is a String.", "15") {} String get(const PropertyReceiver* receiver) const; void set(PropertyReceiver* receiver, const String& value); }; } } // End of CEGUI namespace section #endif // end of guard _CEGUIFrameWindowProperties_h_
/*********************************************************************** filename: CEGUITimerWindowProperties.h created: 7/31/2013 author: xujie *************************************************************************/ #include "elements/CEGUITimerWindowProperties.h" #include "elements/CEGUITimerWindow.h" #include "CEGUIPropertyHelper.h" #include "CEGUIExceptions.h" // Start of CEGUI namespace section namespace CEGUI { namespace TimerWindowProperties { String TimerFormatText::get(const PropertyReceiver* receiver) const { return static_cast<const TimerWindow*>(receiver)->GetTimerFormatText(); } void TimerFormatText::set(PropertyReceiver* receiver, const String& value) { static_cast<TimerWindow*>(receiver)->SetTimerFormatText( value ); } String TotalTime::get(const PropertyReceiver* receiver) const { return PropertyHelper::floatToString( static_cast<const TimerWindow*>(receiver)->GetTotalTime() ); } void TotalTime::set(PropertyReceiver* receiver, const String& value) { static_cast<TimerWindow*>(receiver)->SetTimer( PropertyHelper::stringToFloat( value ) ); } } } // End of CEGUI namespace section
下面是计时器控件的逻辑代码:
/*********************************************************************** filename: CEGUITimerWindow.h created: 7/31/2013 author: xujie purpose: Interface to a default window *************************************************************************/ #ifndef _CEGUITimerWindow_h_ #define _CEGUITimerWindow_h_ #include "CEGUIPushButton.h" #include "CEGUITimerWindowProperties.h" #if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable : 4251) #endif // Start of CEGUI namespace section namespace CEGUI { class CEGUIEXPORT TimerWindow : public PushButton { public: /************************************************************************* Constants *************************************************************************/ // type name for th is widget static const String WidgetTypeName; //!< The unique typename of this widget static const String EventNamespace; static const String EventTimerEnded; static const String EventOneSecondPast; static TimerWindowProperties::TimerFormatText TimerFormatTextProperty; static TimerWindowProperties::TotalTime TotalTimeProperty; /************************************************************************* Construction and Destruction *************************************************************************/ /*! \brief Constructor for GUISheet windows. */ TimerWindow(const String& type, const String& name); /*! \brief Destructor for GUISheet windows. */ virtual ~TimerWindow(void) {} void SetTimer( float fTotalTime ); float GetTotalTime() const; float GetCurrentTime() const; void SetTimerFormatText( const String& strFormatText ); const String& GetTimerFormatText() const; protected: void SetTimerText( int nSecond ); protected: bool OnUpdate( const CEGUI::EventArgs& Arg ); /*! \brief Return whether this window was inherited from the given class name at some point in the inheritance hierarchy. \param class_name The class name that is to be checked. \return true if this window was inherited from \a class_name. false if not. */ virtual bool testClassName_impl(const String& class_name) const { if (class_name=="TimerWindow") return true; return Window::testClassName_impl(class_name); } private: float m_fTotalTime; float m_fCurrentTime; String m_strTimerFormatText; }; } // End of CEGUI namespace section #endif
/*********************************************************************** filename: CEGUITimerWindow.cpp created: 7/31/2013 author: xujie purpose: Interface to a default window *************************************************************************/ #include "elements/CEGUITimerWindow.h" #include <sstream> // Start of CEGUI namespace section namespace CEGUI { /************************************************************************* Constants *************************************************************************/ // type name for this widget const String TimerWindow::WidgetTypeName( "CEGUI/TimerWindow" ); const String TimerWindow::EventNamespace( "TimerWindow" ); const String TimerWindow::EventTimerEnded( "TimerEnded" ); const String TimerWindow::EventOneSecondPast( "OneSecondPast" ); TimerWindowProperties::TimerFormatText TimerWindow::TimerFormatTextProperty; TimerWindowProperties::TotalTime TimerWindow::TotalTimeProperty; /************************************************************************* Constructor *************************************************************************/ TimerWindow::TimerWindow(const String& type, const String& name) : PushButton(type, name), m_fTotalTime( 0 ), m_fCurrentTime( 0 ), m_strTimerFormatText( "$(CurrentTime)" ) { subscribeEvent( CEGUI::Window::EventWindowUpdated, CEGUI::Event::Subscriber( &TimerWindow::OnUpdate, this ) ); addProperty( &TimerFormatTextProperty ); addProperty( &TotalTimeProperty ); } void TimerWindow::SetTimer( float fTotalTime ) { m_fTotalTime = fTotalTime; m_fCurrentTime = fTotalTime; } float TimerWindow::GetTotalTime() const { return m_fTotalTime; } float TimerWindow::GetCurrentTime() const { return m_fCurrentTime; } void TimerWindow::SetTimerFormatText( const String& strFormatText ) { m_strTimerFormatText = strFormatText; } const String& TimerWindow::GetTimerFormatText() const { return m_strTimerFormatText; } void TimerWindow::SetTimerText( int nSecond ) { String strCurrentTimeTag( "$(CurrentTime)" ); //get current time text std::stringstream ss; ss << nSecond; String strCurrentTimeText = ss.str().c_str(); //replace current time tag to real time text String strText = m_strTimerFormatText; String::size_type nCurrentTimeTagIndex = strText.find( strCurrentTimeTag ); if( String::npos != nCurrentTimeTagIndex ) { strText.replace( nCurrentTimeTagIndex, strCurrentTimeTag.size(), strCurrentTimeText ); } setText( strText ); } bool TimerWindow::OnUpdate( const CEGUI::EventArgs& Arg ) { const CEGUI::UpdateEventArgs* pUpdateEventArg = dynamic_cast< const CEGUI::UpdateEventArgs* >( &Arg ); if( NULL == pUpdateEventArg ) { return false; } if( m_fCurrentTime < 0.0f ) { return true; } float fPreviousTime = m_fCurrentTime; m_fCurrentTime -= pUpdateEventArg->d_timeSinceLastFrame; //one second pasts if( ( int )fPreviousTime != ( int )m_fCurrentTime )//if the two variables are positive { CEGUI::UpdateEventArgs oArg = *pUpdateEventArg; fireEvent( EventOneSecondPast, oArg, EventNamespace ); SetTimerText( ( int )fPreviousTime ); } //one second pasts and timer ended if( fPreviousTime * m_fCurrentTime < 0.0f )//if m_fCurrentTime is less than 0 { CEGUI::UpdateEventArgs oArg = *pUpdateEventArg; fireEvent( EventOneSecondPast, oArg, EventNamespace ); fireEvent( EventTimerEnded, oArg, EventNamespace ); SetTimerText( ( int )fPreviousTime ); } return true; } //----------------------------------------------------------------------------// }
WindowFactoryManager::addFactory< TplWindowFactory<TimerWindow> >();
<FalagardMapping WindowType="TaharezLook/TimerWindow" TargetType="CEGUI/TimerWindow" Renderer="Falagard/Button" LookNFeel="TaharezLook/Button" />其中两个文件中,第一个是给CEGUI系统用的,第二个是给CEGUILayoutEditor用的。
CEGUI::TimerWindow* pTimerWindow = dynamic_cast< CEGUI::TimerWindow* >( CEGUI::WindowManager::getSingleton().createWindow( "TaharezLook/TimerWindow", "Root/TimerWindow" ) ); if( pTimerWindow ) { pTimerWindow->setProperty( "NormalImage", "set:TaharezLook image:ButtonMiddleNormal" ); pTimerWindow->setProperty( "HoverImage", "set:TaharezLook image:ButtonMiddleNormal" ); pTimerWindow->setProperty( "PushedImage", "set:TaharezLook image:ButtonMiddleNormal" ); pTimerWindow->setProperty( "DisabledImage", "set:TaharezLook image:ButtonMiddleNormal" ); pTimerWindow->setPosition( CEGUI::UVector2( cegui_absdim( 0 ), cegui_absdim( 200 ) ) ); pTimerWindow->setSize( CEGUI::UVector2( cegui_absdim( 700 ), cegui_absdim( 100 ) ) ); pTimerWindow->SetTimer( 15.0f ); pTimerWindow->SetTimerFormatText( L"剩余$(CurrentTime)秒进入竞技场" ); pTimerWindow->subscribeEvent( CEGUI::TimerWindow::EventTimerEnded, CEGUI::Event::Subscriber( &FirstWindowSample::_OnTimerEnded, this ) ); root->addChildWindow( pTimerWindow ); }
pTimerWindow->SetTimerFormatText( L"剩余$(CurrentTime)秒进入竞技场" );例外,我们CEGUI已经支持中文显示,不知道的朋友可以到网上查阅一下相关教程。大体流程是:为CEGUI提供一个中文字符文件,然后让控件使用这种字体文件就可以显示中文了。
TimerFormatText,text;TotalTime,text;结果如下:
SupportedProperties=TimerFormatText,text;TotalTime,text;Alpha,float;ClickStepSize,float;MaximumValue,float;Visible,bool;AlwaysOnTop,bool;ClippedByParent,bool;InheritsAlpha,bool;Selected,bool;ReadOnly,bool;CloseButtonEnabled,bool;DragMovingEnabled,bool;FrameEnabled,bool;SizingEnabled,bool;TitlebarEnabled,bool;MultiSelect,bool;Sort,bool;DraggingEnabled,bool;BackgroundEnabled,bool;InheritsTooltipText,bool;HoverImage,text;PushedImage,text;DisabledImage,text;NormalImage,text;Font,font;TitlebarFont,font;VerticalAlignment,vert_align;HorizontalAlignment,horz_align;VertFormatting,vert_text_format;HorzFormatting,horz_text_format;Tooltip,text;Image,text;TextColours,text;这个配置文件,此字段太长了,有点难看。
通过CELayoutEditor编辑器,修改TextDemo.layou并运行Sample_TextDemo例子的截图:
整个流程终于跑通,也让我非常开心。如果你遇到了什么意外,请留言,一起进步。