0

この C++ プログラムでは、イメージ ボタンとヒット テスト機能を備えたイメージ ボタン コントロールを作成して、ビデオ内でマウスがクリックされたかどうかを調べます。

class ImageButton{
public:
ImageButton(int xPos, int yPos, int width, int height);
virtual void onMousePress(); //triggered internally if the mouse clicked inside the button
virtual void onMousePressOutside() //triggered internally if the mouse clicked outside the button
private:
bool hitTest(int, int); //check if is in bounds
};

さて、このImageButtonコントロールを利用しなければならない別の場所があります。私は C# から来たので、コントロールを非常に簡単に使用して、次のようなイベントをサブスクライブしたことを覚えています。

btnControl.Click += new MouseClickEventHandler(Sender e, EVentArgs e)

ライブラリを使用して、C++ でイベント サブスクライブの同様の機能を取得し始めたばかりPocoですが、2 番目のクラスでサブスクライブできるイベントを作成し、この 2 番目のクラスでサブスクライブされた関数をトリガーする方法を知りたいと思いましたonMousePressImageButton?

4

3 に答える 3

0

上記を解決するために私は次のことをしたでしょう、それがあなたを助けるかどうかチェックしてください。

class EventData
{
};

// base class for all the secondary classes which expect to get a call back control from
// the first object where we perform hit-test.

class EventHandler
{
public:
virtual void performAction(EventData* ed) = 0;
};

// Second class constructor can register itself to your first object.

class SecondClass : public EventHandler
{
public:
    SecondClass()
    { 
        ImageButton::registerForEventAction(*this);
    }
    void performAction(EventData* ed)
    {
       // this method gets called back when a hit test gets passed and we will get control
       // at the same time at second object to perform necessary operation.
    }
};

// ... extending your first class with below method, and another member variable.

class ImageButton 
{
// extension to base definition of ImageButton .. assuming namespace kind of convention 
// just for simplicity and completeness

private:
std::vector<EventHandler&> registeredHandlers;

public:
static void ImageButton::registerForEventAction(EventHandler& eh)
{
  // For Simplicity I'm assuming your First class object is singleton, if not you need to
  // figure out how you can get access to first object in your second class.

 ImageButton::getInstance().registeredHandlers.push_back(eh);
}

bool hitTest(int, int)
{
bool success = true; 
// ideally above variable should be set to false at the start setting it to true for 
// readability

   if (success) {
        for (std::vector<EventHandler&>::iterator i = registeredHandlers.begin(); i !=       registeredHandlers.end(); ++i) {
        // pass on any event data if you need to.
           (*i).performAction(NULL);
        }
    } // End of if
}// End of method
}; // End of Class Definition
于 2013-01-23T14:14:07.110 に答える
0

1 つの方法は、オブザーバー デザイン パターンを適用することです。たとえば、ImageButton クラスがイベントを受け取り、関連するクライアント オブジェクトが ImageButton に登録されます。イベントが発生すると、ImageButton は登録されているすべてのクライアントに通知します。クライアントは、適切と思われるイベントに対応する責任を負います。

別の同様のアプローチは、ライブラリが提供する場合、シグナル/スロット メカニズムを使用することです。私自身の経験から、プログラム内の実行の流れが明示的に見えるため、シグナルやスロットよりも明示的なオブザーバー パターンの適用を好みます。シグナル/スロットメカニズムを広範囲に使用すると、ある時点で魔法のようなことが起こり始め、プログラムが何をしているのかわかりにくくなります。

シグナルとスロットをサポートする Qt を製品の GUI に長年使用しています。以前は、シグナルとスロットがいたるところで使用されていました。ただし、上記の理由により、厳密に GUI コードでのみ使用し、ビジネス コードに伝播させないようにポリシーを変更しました。

于 2013-01-23T14:02:40.160 に答える
0

デリゲートに似たものを使いたい場合は、これにかなり近いはずです。

#include <functional>
//typedef void (*VoidCallback)(void); // only works with static member functions
typedef std::tr1::function<void (void)> VoidCallback;

class ImageButton{
public:
// ...
    VoidCallback onMousePress;
    VoidCallback onMousePressOutside;
private:
    bool hitTest(int x, int y) { onMousePress(); return true; }
};

class ImageButtonWrapper {
private:
    ImageButton m_btn;
    static void foo() { printf("foo happened\n"); }
    void bar() { printf("this bar happened\n"); }
public:
    ImageButtonWrapper() : m_btn(0,0,100,100) {
        m_btn.onMousePress = &foo;
        m_btn.onMousePressOutside = std::bind(&ImageButtonWrapper::bar, this);
    }
};
于 2013-01-23T15:18:51.847 に答える