Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Есть ли события в С++?..


Автор: Kurt 11.9.2005, 18:19
Блуждая в поисках работы (ну не везет мне пока! smile ), наткнулся на задание реализовать простенькую игрушку - одна фигрука (управляемая компьютером) пытается в лабиринте настигнуть другую фигурку (управляется игроком). Естественно, нужно было уметь пересчитывать траекторию движения автоматической фигурки как только юзер изменил положение своей фигурки.
Первоначально просили сделать на С++, но в итоге сошлись на C#. (smile) Проблема пересчета траектории была решена через события. Как только "ручной" объект перешел на другую клетку лабиринта, генерится событие, к-е обрабатывается "автоматическим" объектом - заново вычисляется путь.
Задание сделал и отправил. Теперь вот думаю, как бы я решил эту задачу на С++.
Подскажите, пожалуйста, есть ли в С++ что-то подобное событиям? То есть мне надо чтобы один объект при наступлении некоторых условий генерировал событие, а другой - реагировал на него. Если можете показать пример, как это сделать - вообще здорово..

Автор: srd 11.9.2005, 19:47
Существуют разные реализации схемы сигнал/слот. Например, boost::signals или libsigc++

Автор: Void 11.9.2005, 19:59
Пример кода с использованием Boost.Signals и Boost.Bind:
Код
#include <iostream>

#include <boost/signal.hpp>
#include <boost/bind.hpp>

class EventProducer {
    typedef boost::signal<void(int)> signal_t;
    typedef boost::signals::connection connection_t;
    signal_t sig_;
    int x_;
public:
    EventProducer(int x) : x_(x) { }
    void fire_event() {
        std::cout << "Event fired: x = " << x_ << std::endl;
        sig_(x_);
    }
    connection_t connect(signal_t::slot_function_type subscriber) {
        return sig_.connect(subscriber);
    }
};

class EventConsumer {
    int id_;
public:
    EventConsumer(int id) : id_(id) { }
    void process_event(int x) {
        std::cout << "Event consumed: x = " << x << ", id = " <<
            id_ << std::endl;
    }
};

int main() {
    using namespace boost::signals;
    EventProducer obj(3);
    EventConsumer obj1(1), obj2(2);
    obj.connect(boost::bind(&EventConsumer::process_event, &obj1, _1));
    connection c2 =
        obj.connect(boost::bind(&EventConsumer::process_event, &obj2, _1));
    obj.fire_event();
    c2.disconnect();
    obj.fire_event();
}

Вывод:
Код
Event fired: x = 3
Event consumed: x = 3, id = 1
Event consumed: x = 3, id = 2
Event fired: x = 3
Event consumed: x = 3, id = 1

Автор: chipset 12.9.2005, 03:45
Исключения можешь бросать и ловить другими классами.
А вообще просто закидываешь делегат и вызываешь при необходимости (вариант лучше) smile

Автор: Void 12.9.2005, 06:31
Цитата(chipset @ 12.9.2005, 05:45)
Исключения можешь бросать и ловить другими классами.

Это как (в контексте задачи)? smile

Автор: chipset 12.9.2005, 07:34
Цитата(Void @ 11.9.2005, 20:31)
Это как (в контексте задачи)?

Перечитал, понял - в контексте задачи никак, да и не красиво это, в общем smile

Автор: Guest 12.9.2005, 08:47
Это можно и без boost делаеть . См паттерн Chain of Responsibility.
Но в вашем случае всего то два объекта, один из которых генерит запрос, другой обрабатывает. Это вообще элементарно

Автор: oleg1973 12.9.2005, 10:09
чет вы перемудрили слишком
что мешает сделать 2 процедуры - первая для "ручного" обьекта а вторая для автоматического и гонять их в цикле?
какие нафиг события?

п.с.
куда катится мир?

Автор: Ignat 12.9.2005, 12:41
Цитата(oleg1973 @ 12.9.2005, 11:09)
гонять их в цикле

Батенька, да вы извращенец. В реалтайме цикл гонять?

И какие нифиг процедуры в С++?

Автор: Dreamer_0x01 12.9.2005, 14:26
может я не очень въехал в тему.

1. писать свой цикл обработки сообщений
2. есть достаточно эффектный путь, который с успехом применяется в Яве - там есть такая фича, как интерфейсы. Говорят, что в С++ аналогичная штука делается с помощью множественного наследования. Щас может быть соображу, как ;)

Автор: Denn 12.9.2005, 14:51
Цитата(Dreamer_0x01 @ 12.9.2005, 14:26)
Говорят, что в С++ аналогичная штука делается с помощью множественного наследования. Щас может быть соображу, как ;)

Шаблон Command называется.

Автор: Kurt 12.9.2005, 20:05
Dreamer_0x01
Если покажешь пример - буду очень благодарен..

[offtop]
Н-да.. Надо подтянуть свои знания в C++.. smile
[/offtop]

Автор: oleg1973 13.9.2005, 01:59
мамамиииия какой маразм, люди вы бредите
и так представим некое поле в виде клеточек по которому бродят 2 фигуры (размером в клетку)
на даном поле есть некоторые клетки которые нельзя пройти (стены блин)
так как шаг фигуры равен размеру клетки , то вообшем я не вижу проблем для реализации алгоритма

Ignat
ну а в чем проблема?
сначала вызову некий алгоритм который обрабатывает нажатия пимп/джойстика/мыши юсера
а потом вызову алгоритм хождения моей клетки которая получив координаты клетки юсера просчитает оптимальную траэкторию движения


Автор: Kurt 13.9.2005, 02:15
oleg1973
алгоритм поиска, конечно, понятен. вопрос в оптимальном организации системы - ты предлагаешь в цикле гонять процедуры проверки наступления некоторых условий? (в моем случае - премещение объекта на соседнюю клетку). А если объектов (разных) будет 10? 50? 100?

З.Ы.
Господа, обсуждение уходит в сторону. Я, собственно, ничего против не имею, но все же.. smile

Автор: chipset 13.9.2005, 03:04
Реализуешь указатель на функцию-член класса.
Передаешь её как обработчик события.
В случае чего оно вызываеться. Ну не события конечно в прямом понятии, но любые события сводяться к циклу или чему то такому.
Добавлено @ 03:05
А Boost не надо тянуть, имхо.

Автор: Void 13.9.2005, 06:30
Цитата(chipset @ 13.9.2005, 05:04)
Реализуешь указатель на функцию-член класса.
Передаешь её как обработчик события.

Вот только вместе с этим указателем придется передавать еще и указатель на экземпляр этого класса. Сам по себе он невызываем.

Цитата(chipset @ 13.9.2005, 05:04)
А Boost не надо тянуть, имхо.

Предлагаешь писать делегаты самому? Нет, для данной задачи Boost, быть может, и overkill, но вообще не вижу ничего криминального.

Автор: ST1 13.9.2005, 19:01
@Kurt
Возможно вас заинтересует эта информация:
1) http://is.ifmo.ru/projects/loderunner/ -- реализация Lode Runner (Java)
2) http://www.softcraft.ru/forum/viewtopic.php?t=216 -- реализация активных объектов на C++

Автор: Kurt 9.11.2005, 23:57
Хех, опять прихожу к событиям. (отдельный проджект)
Народ, кто-нибудь реализовывал систему событий на основе GLib? Может, примерчик какой подкинете? А то у меня только reference по функциям. smile
..
Просто сам проект на GTK - не хочется тянуть ничего лишнего. Тем более, в манах по GTK рекомендуют именно GLib...

Автор: Neitron 10.11.2005, 10:28
Цитата(Ignat @ 12.9.2005, 12:41)
Цитата(oleg1973 @ 12.9.2005, 11:09)
гонять их в цикле

Батенька, да вы извращенец. В реалтайме цикл гонять?

И какие нифиг процедуры в С++?

Батенька а ты когда-нибудь на АПИ программировал и ловил сообщения?
Я не понимаю, чем вам не нравится создания события на основе сообщений Винды.

Автор: Ignat 10.11.2005, 13:49
Цитата(Neitron @ 10.11.2005, 10:28)
Батенька а ты когда-нибудь на АПИ программировал и ловил сообщения?

Не далее как вчера smile
Добавлено @ 13:50
Кстати, а на каком именно АПИ? Или кроме ВыньАПИ других не существует?

Автор: Neitron 10.11.2005, 14:23
Ignat
Это типо тест на сообразительность?
На моём АПИ моей программы smile

Автор: Ignat 10.11.2005, 14:29
Цитата(Neitron @ 10.11.2005, 14:23)
На моём АПИ моей программы

Просто нигде не сказано, что прогрмма для винды. Она может быть и для юникса. smile

Автор: powerfox 11.11.2005, 15:10
Можно использавать Qt.
Сейчас пишу змейку - использую SDL, там есть возможность отлавливать клавиши:

Код

while(done == 0){ 
        SDL_Event event; 
        while ( SDL_PollEvent(&event) ){ 
            if ( event.type == SDL_QUIT ){ done = 1; } 
            if ( event.type == SDL_KEYDOWN ){
                if ( event.key.keysym.sym == SDLK_ESCAPE ){ done = 1; } 
           } 
      }
        keys = SDL_GetKeyState(NULL);


Всё это гоняется в цикле. Правда, я пока только изучаю С++. а из Qt знаю только "Hello, Qt!" smile

Автор: Kurt 11.11.2005, 22:11
У меня GTK-приложение.
Определены два пользовательских класса.
Задача - при изменении состояния объекта первого класса определенным образом должно среагировать некоторое множество объектов второго класса.
Все. Больше ничего. Мне нужно то же самое, что происходит в любой GTK/QT/WxWindows-программе! Есть класс, есть событие (определенное в этом класса), нужно повесить на него обработчик.
Программа фактически кроссплатформенная - компилится и под Linux и под Windows. И вообще под все, где есть С++ и GTK. Поэтому очень не хочется заморачиваться с этими всеми системными сообщениями и т.п.
Тянуть дополнительные либы тоже жаба душит - и так уже от GTK неплохо зависим. А под зависимостью от GTK я понимаю зависимость еще и от glib, atk, pango и т.п. и т.д.
Господа, я в растерянности. Работа стоит, а время идет. smile

Автор: Дмитрий Т 11.11.2005, 23:41
Цитата(Kurt @ 11.11.2005, 23:11)
Господа, я в растерянности. Работа стоит, а время идет. smile

Всё правильно сказали про указатель на функцию.

Вот пример:

Класс порождающий событие
Код

    class StrFinder;
    
    // type of event
    typedef void (*ShowResult_t) (const std::string& CurWord);

    // main class
    class StrFinder{
        std::string CurWord;
        ShowResult_t ShowResult;
        inline void doShowResult();
    public:
        void SetShowResult (ShowResult_t value);
    };

inline void StrFinder::doShowResult() 
{
    if (ShowResult) {
        ShowResult(CurWord);
    }
}

void StrFinder::SetShowResult (ShowResult_t value) 
{
    ShowResult = value;
}


У реагирующего на событие:
Код

void ShowResult (const std::string& CurWord)
{
    std::cout << CurWord << std::endl;
}


теперь связываем:
Код

f = new StrFinder();
f->SetShowResult(ShowResult);


Этот код - неопробованные вырезки из рабочей программы.

Этот вариант хорош для одного реагирующего на событие, но прост и очень часто встречается. Для нескольких реагирующих надо менять SetShowResult и хранить массив указателей или лучше воспользоваться другой схемой. Кратко почитать о разных схемах работы с событиями в С++ можно на http://www.fox-toolkit.org/faq.html в вопросе "Why did FOX choose the message-map based callback paradigm" (нашёл когда выбирал библиотеку).

Автор: Kurt 12.11.2005, 00:27
Благодарю за ответ.
С твоим примером все стало намного проще. Правда, у меня несколько реагирующих объектов, но это я уже решу... надеюсь. smile

З.Ы. Ну, не спец я в С++, что тут поделаешь? smile

Автор: S.A.P. 12.11.2005, 21:42
Вот мой небольшой велосипед с несколькими реагирующими объектами.
Код

using namespace std;

typedef void (*Slot)();

class Signal {
public:
    vector<Slot> slots;
    void operator()();
    Signal& operator <= ( Slot );
};

void Signal::operator()()
{
    vector<Slot>::iterator it;
    for ( it = slots.begin(); it != slots.end(); it++ ) 
        (*it)();
}

Signal& Signal::operator <= ( Slot slot )
{
    slots.push_back( slot );
    return *this;
}


Юзать можно так.

Код

using namespace std;

void slot1()
{
    cout << "slot1" << endl;
}

void slot2()
{
    cout << "slot2" << endl;
}

void slot3()
{
    cout << "slot3" << endl;
}

int main(int argc, char *argv[])
{
    Signal signal;
    signal <= slot2 <= slot3 <= slot1;
    signal();
    system("PAUSE");
    return EXIT_SUCCESS;
}

вывод:
Цитата

slot2
slot3
slot1


Добавлено @ 21:43
Помидоров не жду smile .

Автор: libricon 12.11.2005, 22:03
хорошая мысть qt
тама реализована система signal - slot
т.е появился сигнал, вызвался слот .
пример
connect ( что ,SIGNAL(событие),кому,SLOT(че сделать));

или чтото похожее


Автор: Kurt 12.11.2005, 23:59
Perchilla
Благодарю. Сейчас попробую применить. smile

libricon
Не спорю, в QT все классно сделали, но, увы, я работаю с GTK.

Автор: powerfox 13.11.2005, 14:16
To Perchilla:
Не могли бы Вы дать пояснения к коду?

Автор: S.A.P. 13.11.2005, 15:17
Цитата(powerfox @ 13.11.2005, 14:16)
To Perchilla:
Не могли бы Вы дать пояснения к коду?

тут я просто создал объект функцию (сигнал) с перегруженным оператором (), к которому можно подключать другие функции (слоты). Для подключения слотов я перегрузил оператор <= (для наглядности). Указатели на слоты храняться в контейнере std::vector. При имитировании сигнала ( signal() ) соответственно вызываются все слоты, которые былы подключены. То есть как в QT, например при нажатии на QPushButton имитируется сигнал clicked().

Но мой пример не очень хорош, чаще требуется передавать какие - то параметры из сигнала в слоты ( например координаты, как у Kurt ). Для частного случая можно и напильником подогнать, но если в одном классе надо держать несколько сигналов с разныи количеством параметров, то лучше написать шаблон. Вот только в шаблонах я пока плаваю smile и не могу понять как правильно это сделать: перегрузить шаблоны для разного количества параметров или можно как то хитро обойти одним шаблоном.

Еще бы не мешало предотвращать попытки повторного подключения слота, дать возможность отключение определенного слота, сделать, чтобы сигнал мог возвращать значения... Но все это больше похоже на переписывание boost::signals.

А вот интересно, как в boost сделали передачу параметров в слоты. Знаю, что в QT это реализовано на уровне препроцессора, что немного огорчает smile .

Автор: Дмитрий Т 13.11.2005, 20:44
Цитата(Kurt @ 13.11.2005, 00:59)
Не спорю, в QT все классно сделали, но, увы, я работаю с GTK.

Кстати, как помню, на qt-шном сайте видел обсуждение по поводу событий, что ради совместимости со старыми наработками разработчики отказываются заменить систему на более эффективную... А на www.fox-toolkit.org утверждается, что в FOX самая лучшая система событий, но я лично не анализировал (по другим причинам выбрал WxWidgets).

Автор: Дмитрий Т 13.11.2005, 21:00
Цитата(Perchilla @ 13.11.2005, 16:17)
... но если в одном классе надо держать несколько сигналов с разныи количеством параметров, то лучше написать шаблон. Вот только в шаблонах я пока плаваю  smile и не могу понять как правильно это сделать: перегрузить шаблоны для разного количества параметров или можно как то хитро обойти одним шаблоном.


Может не шаблон, а несколько классов?
Посмотри раздел Events на
http://wxwidgets.org/manuals/2.6.2/wx_classesbycat.html#classesbycat
у этой достаточно старой и распространённой библиотеки есть иерархия типов событий...

Автор: S.A.P. 14.11.2005, 08:20
Цитата
Может не шаблон, а несколько классов?

просто все мои представления об этом отталкиваются от boost::signals, а там можно так записать:
Код

void print_sum(float x, float y)
{
  std::cout << "The sum is " << x+y << std::endl;
}

void print_product(float x, float y)
{
  std::cout << "The product is " << x*y << std::endl;
}

void print_difference(float x, float y)
{
  std::cout << "The difference is " << x-y << std::endl;
}

void print_quotient(float x, float y)
{
  std::cout << "The quotient is " << x/y << std::endl;
}

// . . . 

boost::signal<void (float, float)> sig;

sig.connect(&print_sum);
sig.connect(&print_product);
sig.connect(&print_difference);
sig.connect(&print_quotient);

sig(5, 3);

Автор: srd 14.11.2005, 13:05
Цитата
А на www.fox-toolkit.org утверждается, что в FOX самая лучшая система событий, но я лично не анализировал (по другим причинам выбрал WxWidgets).

В FOX Toolkit такое же мракобесие на макросах, как в wxWidgets или MFC.

Автор: Guest 15.11.2005, 14:51
Цитата(Perchilla @ 14.11.2005, 08:20)
Цитата
Может не шаблон, а несколько классов?

просто все мои представления об этом отталкиваются от boost::signals, а там можно так записать:
Код

void print_sum(float x, float y)
{
  std::cout << "The sum is " << x+y << std::endl;
}

void print_product(float x, float y)
{
  std::cout << "The product is " << x*y << std::endl;
}

void print_difference(float x, float y)
{
  std::cout << "The difference is " << x-y << std::endl;
}

void print_quotient(float x, float y)
{
  std::cout << "The quotient is " << x/y << std::endl;
}

// . . . 

boost::signal<void (float, float)> sig;

sig.connect(&print_sum);
sig.connect(&print_product);
sig.connect(&print_difference);
sig.connect(&print_quotient);

sig(5, 3);

А где здесь события с разным количеством аргументов? Вроде тоже самое только тип задаётся с помошью шаблона.

Автор: S.A.P. 15.11.2005, 17:05
Цитата(Guest @ 15.11.2005, 14:51)
А где здесь события с разным количеством аргументов? Вроде тоже самое только тип задаётся с помошью шаблона.
разница в том, что я юзая один класс могу создать сигналы с разлиным количеством параметров. Количество параметров у слотов разумеется должно быть одинаково. Правда в QT это не обязательно, но это другая тема.

Автор: nikf 15.11.2005, 20:57
делегаты в .net не более чем функции обратного вызова в си. а нагородили-то на три страницы...QT приплели...

Автор: Void 15.11.2005, 21:04
Цитата(nikf @ 15.11.2005, 22:57)
делегаты в .net не более чем функции обратного вызова в си.

Для Си все просто. А вот для C++ аналогом делегатов дотнета является boost::function + bind'еры. Потому что метод объекта сам по себе не является вызываемой сущностью.

Автор: nikf 15.11.2005, 21:37
Цитата(Void @ 15.11.2005, 21:04)
А вот для C++ аналогом делегатов дотнета является boost
boost это библиотека, а не язык, вопрос про язык был, а библиотек всяких разных в том числе и boost достаточно много. от этого они не становятся стандартом языка

Автор: Void 15.11.2005, 21:45
nikf
Хорошо. Аналогом делегатов дотнета является boost::function или близкая по функциональности библиотека. Так устраивает? В C++ нет примитивов, позволяющих решить поставленную задачу.
Цитата(nikf @ 15.11.2005, 23:37)
от этого они не становятся стандартом языка

Почти стали. Посмотри TR1 по стандартной библиотеке.

Автор: mes 18.3.2008, 17:41
Иногда удобно применять подход описанный ниже. Как называется не знаю. Но цель вынести обшую функционалость в обший класс обработчик.
Состоит из трех частей : 
1 определение типов сообшений,так чтоб их объект содержал нужную информацию о событии - например в описанной ниже хранится координаты покинутой клетки и той на которую перепрыгнул объект
2. Интерфейс обработчика сообшений - состоид из двух частей
а. перегруженный метод (в примере OnEvt) для диспатчеризации нужного типа нужному обработчику
б. виртуальный метод  - обработчик события 
3. сам объект

Преимушества :
1. Типизация которая не даст допустить ошибку.
2..  двойная диспетчиризация, что позволяет раздельно развивать, но совместно использовать  сами обьекты и лабиринты.
3.  логика обработки событий сгруппированна в одном месте. 
4.  информация собирается в момент происхождения события а не в момент обработки
6.  *..
Недостатки:
1. нужна проектировка классов (что в принципе желательно при любом подходе)
2. естественно не потокобезопасная
3 *..
 *..  = может есть что то еше - сейчас не пришло в голову 


Код

namespace Evt {
struct SObjectMoved 
{
  SObjectMoved (SCoord oldcell, newcell) :oldCell (oldcell), newCell (oldCell)
  SCoord  oldCell;
  SCoord newCell;
}
};

class GameObject {...}; // то что движется по лабиринту

class LabirintEvt
{
   public :  
     void OnEvt (const Evt::SObjectMoved& evt,   GameObject* pobj) { doOnObjectMovedEvt(evt,pobj); };  // перегрузка функций для разных событий
     void OnEvt (...)
  protected: 
     void doOnObjectMovedEvt (const Evt::SObjectMoved& evt,   GameObject* pobj) =0;
}

class Pacman : public GameObject {..}  *pPacman;
//где внутри цикла
if (pEvt) pEvt->OnEvt (Evt::SObjectMoved(SCooord(2,1),SCooord(2,2)), pPacman )



Автор: Дмитрий Т 19.3.2008, 09:55
Цитата(mes @ 18.3.2008,  18:41)
Иногда удобно применять подход описанный ниже. Как называется не знаю. Но цель вынести обшую функционалость в обший класс обработчик.
[/code]

Насколько понял, вы просто вынесли код события в отдельное дерево классов начинающееся с LabirintEvt. Не совсем понятно когда такой подход удобен... Если есть объект Лабиринт и объект Человечек, то для рекции Лабиринта на движения Человечка достаточно в одном классе создать указатель на функцию...

Автор: mes 19.3.2008, 15:09
Цитата(Дмитрий Т @  19.3.2008,  09:55 Найти цитируемый пост)
Не совсем понятно когда такой подход удобен

вышеназванный механизм удобен вместо реализации классической системы собщения тем, что диспетчиризация производится напрямую
вместо сигналов тем что подключение подключение происходит сразу пучком и не надо задумываться что куда подключать.
Он предоставляет обший интерфейс (со всеми вытекаюшими преимушествами и недостатками) на определеную группу событий, но выполнен с учетом возможности множественной диспетчеризации [пример ниже]

Цитата(Дмитрий Т @  19.3.2008,  09:55 Найти цитируемый пост)
для рекции Лабиринта на движения Человечка

вобше сообшения предназначены не столько для реакции Лабиринта на движения Человечка   
сколько для реакции "внешних" компонентов на взаимоотношение между Человечком и Лабиринтом.


Пример: Главное окно разбито на несколько компонентов . В одном отображен сам процесс игры, в других информация о игре: координаты объекта , список ходов и т.д.

Код


template <class T>
class TCluster 
{
typedef std::set<T> TEvtSet;
public:
template <class P> void OnEvt (P p1) { for (TEvtSet::iterator it = m_set.begin(); it!=m_set.end(); ++it) { if (*it)  (*it)->OnEvt(p1); }  
.. //здесь для двух и более параметров
void insert (T pevt) {m_set.insert(pevt); }
void erase (T pevt) {m_set.erase(pevt); }
private:
TEvtSet m_set;

};

class CGame
{
public:
 void MoveGameObject (int id, SCoord coord) { if (doMove(...)==success) m_LabirintEvtCluster.OnEvt (SObjectMoved (... ); } // множественная рассылка
void insert (ILabirintEvt * pEvt) {m_LabirintEvtCluster.insert (pEvt); }
void erase (ILabirintEvt * pEvt) {m_LabirintEvtCluster.erase (pEvt); }
private:
     TCluster<ILabirintEvt> m_LabirintEvtCluster;
...
};

class WGamePanel // образец визуального компонента
                                     : public WPanel , protected ILabirintEvt // двойное наследие для упрошения при использовании одного контролера на виджет
{
public:
           WActionScene (WWindow *parent, ..., CGame *pgame) { pgame ->insert((ILabirintEvt*)this); } 
            virtual ~WActionScene (WWindow *parent, ..., CGame *pgame) { pgame ->erase((ILabirintEvt*)this); }
 protected: 
        doOn...Evt ... { }
      ..
}; 
class WActionScene : ... // окно процесса игры 
class WHistory:              // панель с показом ходов
class WCoord :           // текушее положение
..                                  // что нибудь еше

class CStatusBarCtrl: protected ILabirintEvt  // классическое применение контролера событий
{
public:
    CStatusBarCtrl(WStatusBar* pbar, CGame *pgame) : p_bar(pbar) { pgame->insert (this); }
...
private:
WSatatusBar *p_bar;
};

class WMainFame : WFrame  // главное окно
{
public:
...

protected:
  void CreateContols () {  new WActionScene (this,..., &m_Game); // создание компонента на главном окне с получением событием от лабиринта
                                             WPanel *  pwPanel = new WPanel (this) ;// к примеру боковая панель 
                                             new WHistory (pwPanel,..., &m_Game); //создание компонента на боковой панели, но он все так же будет получать сообшения                                 
                                             pStBarCtrl = newCStatusBarCtrl(this->GetStatusBar(), &m_Game);
                                        };
private:
     CGame m_Game;
      CStatusBarCtrl * pStBarCtrl;
};

};


* Пример привел в обшей схеме с упрошениями для легкого представления.. 
названия выбраны условн, приставка W - означает виджет.
Преимушество приведенного примера : реализация визуализации отделена от реализации логики игры.
 


Автор: Дмитрий Т 21.3.2008, 10:40
А здесь не тоже самое http://docs.wxwidgets.org/stable/wx_classesbycat.html#classesbycat дерево начинающееся с Events?

Автор: mes 21.3.2008, 15:10
Цитата(Дмитрий Т @  21.3.2008,  10:40 Найти цитируемый пост)
А здесь не тоже самое http://docs.wxwidgets.org/stable/wx_classe...ml#classesbycat дерево начинающееся с Events? 


Все реализации событий похожи  друг на друга. Однако в зависимости от ситуации отдаешь предпочтение одному (или смеси) из этих способов.
В приведенном выше примере во первых присутствует независимость от библиотек, что позволяет сделать логику модели программы независимой 
от применения ГУИ-библиотеки. Во вторых вышеприведенный пример осушествляет прямую диспетчиризацию (что является иногда недостатком, а иногда преимушеством - в зависимости от исполняемой задачи )


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)