如何实现在点击时执行不同功能的通用按钮类?

时间:2011-05-02 16:10:30

标签: c++ button sdl

好的,我正在使用 SDL和C ++ ,我开始为我的地图编辑器开发一个简单的GUI。从单个按钮的工作原型,我写了一个通用的GUIObject类和一个通用的Button类。但我现在有一个问题,为了让课程可以重复使用,我需要能够为每个按钮设置它所调用的功能(即帮助!打开帮助窗口,打开打开文件对话框,它们是相同的Button类,但它们执行不同的功能。)

现在,我前段时间使用了一个用于Ruby GUI的简单库,它的语法使用了那些在那里被标记为“块操作符”的东西:

示例:

@login_button = Button.new(@window, 98, 131, Network_Data::LOGIN_BUTTON){execute_login}

最后一部分{}是你放置自己的函数和类以某种方式提取并在单击时执行该函数的东西。我也听说Java有类似的东西:

onClick = new Function() { }

那么我将如何在C ++程序(使用SDL库)中实现这一点。我不想使用任何GUI库,因为它们看起来太复杂了,我很难在已经构建的代码中插入这些库。

4 个答案:

答案 0 :(得分:2)

你可以使用function / functor / method指针来完成它。 (功能应该足够且相对简单)

你可以在你的按钮构造函数中传递一个指向回调函数的指针。

这是使用函数指针的基本示例。

class Button
{   
    typedef void(*eventFunction)();

    Button( eventFunction funcPtr ) : m_funcPtr( funcPtr ){}
    ///< A constructor.
    /// @param funcPtr The function pointer to register.

    ~Button(){ m_funcPtr = NULL; }
    ///< A destructor.          

    void operator() () const
    {
        (m_funcPtr)();
    }
    ///< Invokes the registered function.

    private:
        eventFunction m_funcPtr;
};

你可以这样使用它:

void myFunction1() { /* do something */ }
void myFunction2() { /* do something else */ }

Button myButton1( &myFunction1 );
myButton1(); // invoke the function registered

Button myButton2( &myFunction2 );
myButton2(); // invoke the function registered

这是使用可变参数模板(C ++ 0x)

的更复杂的示例
template < class Tr, class... Args >
class Button
{
    typedef Tr(*eventFunction)(Args...);

    Button( eventFunction funcPtr ) : m_funcPtr( funcPtr ){}
    ///< A constructor.
    /// @param funcPtr The function pointer to register.

    ~Button(){ m_funcPtr = NULL; }
    ///< A destructor.          

    void operator() ( Args&... args ) const
    {
        (m_funcPtr)(args...);
    }
    ///< Invokes the registered function with the provided arguments.
    /// @param args The arguments to transmit to the invoked function.

    private:
        eventFunction m_funcPtr;
};

你可以这样使用它:

void myFunction1( int, double ) { /* do something */ }
void myFunction2() { /* do something */ }

Button<void, int, double> myButton1( &myFunction1 );
myButton1( 10, 20.5 );  // invoke the function registered with two arguments

Button<void> myButton2( &myFunction2 );
myButton1(); // invoke the function registered without argument

Tr模板如果您从未计划使用其他函数而不是函数返回void,则可以删除并替换为void

因此Button<void, int, double> myButton1( &myFunction1 );会更改为Button<int, double> myButton1( &myFunction1 );

Button<void> myButton2( &myFunction2 );会更改为Button<> myButton2( &myFunction2 );


你可以用方法做几乎相同的事情(你需要注册一个指向要调用的类的实例的指针和指向方法的指针)和functor(你需要注册一个指向函数实例的指针)致电)。


根据您的要求,这里使用方法是同一个类。你可以找到一种让你的Button类同时接受函数,仿函数和方法的方法(想想虚拟^^)。这是C ++ 0x版本

template < class C, class Tr, class... Args >
class Button
{
    typedef Tr(C::*eventMethod)(Args...);
    ~Button(){}

    Button( C& target, eventMethod method ) : m_target(target), m_method(method) {}
    ///< A constructor.
    /// @param target The class member instance used to call the method.
    /// @param method The class member method pointer to register.

    bool operator () ( Args&... args ) const
    {
        (m_target.*(m_method))(args...);
    }
    ///< Invokes the registered method with the provided arguments.
    /// @param args The arguments to transmit to the invoked method.

    private:
        eventMethod m_method;
        C& m_target;
};

你可以这样使用它:

class MyClass
{
    void method1(){};
    void method2( int, double ){};
};

MyClass myC1;

Button<MyClass, void> myButton1( myC1, &MyClass::method1 );
myButton1(); // invoke the registered method using the registered class instance.

Button<MyClass, void, int, double> myButton2( myC1, &MyClass::method2 );
myButton2( 15, 170.5 ); // invoke the registered method using the registered class instance.

如果您需要从方法所属的类中调用它,请使用this作为目标参数,而不是myC1

答案 1 :(得分:1)

有两种方法。您可以使用运行时多态(boost::functionstd::tr1::functionstd::function),也可以使用模板。

答案 2 :(得分:0)

您需要使用按钮类来调用其用户指定的函数。我建议你看一下Boost Signals库。该库实现信号和插槽方法,具有非常好的文档,并得到很好的支持。此外,这些链接应该有助于获得一般的想法:

希望它有所帮助。祝你好运!

答案 3 :(得分:0)

它在c ++中的工作方式与在java中使用的方式几乎相同:

onClick = new ClickFunction;

但是你显然需要以下内容来定义必要的类:

template<class A, class B>
class Function { public: virtual B Map(A a) const=0; };

Function<int, int> *onClick;

class ClickFunction : public Function<int,int>
{
public:
    ClickFunction(MyObject &o) : o(o) { }
    int Map(int a) const { return 10; }
private:
    MyObject &o;
};