Модераторы: Rickert
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> GUI, Listener и оповещение всех контролов, Оповещение всех контролов о событии 
:(
    Опции темы
ProfessorLoL
Дата 8.4.2013, 10:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 8.4.2013

Репутация: нет
Всего: нет



Всем привет. Есть некая библиотека, в которой осуществляется вся работа с окном и событиями. В этой библиотеки главным классом является класс CApplication. Он создает окно, получает события ввода и отсылает сообщения всем слушателям, которые подписались на их получения. Есть класс CAppListener. Именно наследники этого класса могут подписываться на получения сообщений от CApplication.

Приведу немного кода, а затем задам собственно вопрос:

Код

class CAppListener
{
    public:
                CAppListener();
                virtual ~CAppListener();
                
                virtual void DoMessage(char *msg) = 0;
};

class CApplication
{
    public:
                CApplication();
                virtual ~CApplication();
                
                void AddListener(CAppListener *listener)
                {
                    this->listener.push_back(listener);
                };
                
                void SendMessage(char *msg)
                {
                    std::list<CAppListener*>::iterator it;
                    for(it = listener.begin(); it!=listener.end(); ++it)
                        (*it)->DoMessage(msg);
                };
                
                // какая-то функция, получающая виндовые сообщения и оповещающая о них всех слушателей.
                void WndProc(MSG msg)
                {
                    switch(msg)
                    {
                        case WM_KEYDOWN:
                                                SendMessage("KEYDOWN");
                                                break;
                                            
                        case WM_LBUTTONDOWN:
                                                SendMessage("LBUTTONDOWN");
                                                break;
                    }
                };
                
    private:
                std::list<CAppListener*> listener;
};

class CControl
{
    public:
                CControl();
                virtual ~CControl();
                
                void AddControl(CControl *control)
                {
                    this->child.push_back(control);
                };
                
                virtual Draw() = 0;
                bool Update(char *msg) = 0;
                
    protected:
                std::list<CControl*> child;
};

class CGUI: public CControl, public CAppListener
{
    public:
                CGUI();
                virtual ~CGUI();
                
                void Draw();
                
                bool Update(char *msg)
                {
                    std::list<CControl*>::iterator it;
                    for(it = child.begin(); it!=child.end(); ++it)
                        // если какой-то элемент вернул истину (то есть он обработал сообщение) 
                        // то прерываем отправку сообщений остальным
                        if((*it)->Update(msg)) return true;
                    return false;
                };
                
                // получили сообщение, запускаем Update для всех контролов по иерархии.
                void DoMessage(char *msg)
                {
                    result = Update(msg);
                };
                
    private:
                bool result; // для того, что бы понять, был ли обработан хотя бы один контрол в GUI
};

class CButton: public CControl
{
    public:
                CButton();
                virtual ~CButton();
                
                void Draw();
                bool Update(char *msg)
                {
                                        // обрабатываем сначала детей
                    std::list<CControl*>::iterator it;
                    for(it = child.begin(); it!=child.end(); ++it)
                        if((*it)->Update(msg)) return true;

                    if(strcmp(msg, "LBUTTONDOWN") == 0)
                    {
                        // тут обрабатываем проверку попадания в кнопку мыши
                        // если попали то изменяем какие-то параметры, запускаем обработчики
                        return true;
                    }
                    
                    if(strcmp(msg, "KEYDOWN") == 0)
                    {
                        // обрабатываем
                                                // ВОТ ТУТ скажем надо оповестить все контролы о том, что мы обработали нажитие. КАК????? 
                        return true;
                    }
                    
                    return false;
                };
};

// Использовать планирую так:

int main()
{
    CApplication *app = new CApplication();
    CGUI *gui = new CGUI();
    CButton *buton = new CButton();
    
    app->AddListener(gui);
    gui->AddControl(button);
    
    while(true)
    {
        app->run();
    }
    
    return 0;
}


Вся система прекрасно работает. Все контролы созданные таким образом и включенные в иерархию получают события от клавиатуры и мыши. Но возникла необходимость оповестить все контролы о каком-то событии, которое произошло при обработке какого-то конкретного контрола. Допустим ткнули мышкой -> бежим по иерархии контролов и ищем того, кому предназначено сообщение -> обрабатываем сообщение в контроле и ВОТ ТУТ НАДО ПОСЛАТЬ КАКОЕ-ТО СООБЩЕНИЕ ВСЕМ КОНТРОЛАМ. Проблема в том, что отсылать сообщение может только объект класса CApplication. Но доступа в контроле мы к нему не имеем. Помогите.
PM MAIL   Вверх
Bitter
Дата 8.4.2013, 12:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный лентяй
***


Профиль
Группа: Завсегдатай
Сообщений: 1209
Регистрация: 15.8.2004
Где: Харьков, Ukraine

Репутация: 5
Всего: 27



Цитата(ProfessorLoL @  8.4.2013,  10:59 Найти цитируемый пост)
ВОТ ТУТ НАДО ПОСЛАТЬ КАКОЕ-ТО СООБЩЕНИЕ ВСЕМ КОНТРОЛАМ

Я так понял, всем контролам, которые подписаны на сообщения? Или вообще всем контролам в программе?

Цитата(ProfessorLoL @  8.4.2013,  10:59 Найти цитируемый пост)
Но доступа в контроле мы к нему не имеем.

Ну а получить ссылку на него? Он же наверное представлен в виде синглтона?
PM MAIL ICQ Skype   Вверх
ProfessorLoL
Дата 8.4.2013, 13:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 8.4.2013

Репутация: нет
Всего: нет



Цитата

Я так понял, всем контролам, которые подписаны на сообщения? Или вообще всем контролам в программе?

По сути всем вообще котролам. Но, вообще, только объект класса CGUI подписан на сообщения. Именно он получает сообщения от CApplication. А все остальные контролы получают сообщения потому, что являются детьми GUI. Просто идя вниз по иерархии. Таким образом решается проблема "кому принять сообщение от клика мыши, если один элемент закрывает другой." 

Цитата

Ну а получить ссылку на него? Он же наверное представлен в виде синглтона?

Таскать в каждом контроле ссылку на CApplication или на СGUI не хотелось бы.. хотя да, это решило бы проблему. Хотелось бы иметь какое-то красивое решение, которое позволило бы отправлять из любого контрола сообщение в CGUI обьект.

Это сообщение отредактировал(а) ProfessorLoL - 8.4.2013, 13:06
PM MAIL   Вверх
ProfessorLoL
Дата 12.4.2013, 12:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 8.4.2013

Репутация: нет
Всего: нет



Вот, может кому-то будет полезным, если наткнется на топик из поиска по похожей проблеме: В общем, ничего лучшего не придумал, чем таскать в каждом контроле, помимо ссылки на родителя ссылку на CGUI, который является как бы менеджером всей системы интерфейса. Например кнопку теперь можно создать так:

Код

 CButton *button = new CButton(gui, window, 100, 100, 150, 24, "Кнопка 1");


где window это окно в котором кнопка будет рисоваться в координатах 100,100

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

Код

 this->gui->Update("сообщение", input); 

и оно запустит рассылку заново всем контролам в программе с этого места, а потом вернется в эту точку. 
Если же надо послать сообщение только тем контролам, которые являются братьями данного, то тоже самое делается через родителя.
Так например можно легко сбрасывать все RadioButton'ы. Щелкаем по одному, посылаем сообщение "UNCHECKED" всем остальным имеющим одного предка с данным, а текущий RadioButton делаем SetChecked(true);
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Программирование игр, графики и искуственного интеллекта"
Rickert

НА ЗЛОБУ ДНЯ: Дорогие посетители, прошу обратить внимание что новые темы касающиеся новых вопросов создаются кнопкой "Новая тема" а не "Ответить"! Любые оффтопиковые вопросы, заданные в текущих тематических темах будут удалены а их авторы, при рецедиве, забанены.

  • Литературу, связанную с программированием графики, обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы связанные с программированием графики и мультимедии на языках С++ и Delphi
  • Вопросы по реализации алгоритмов рассматриваются здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rickert.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Программирование игр, графики и искусственного интеллекта | Следующая тема »


 




[ Время генерации скрипта: 0.0733 ]   [ Использовано запросов: 20 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.