информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Spanning Tree Protocol: недокументированное применениеСетевые кракеры и правда о деле ЛевинаСтрашный баг в Windows
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Бэкдор в xz/liblzma, предназначенный... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
все доски
FAQ
IRC
новые сообщения
site updates
guestbook
beginners
sysadmin
programming
operating systems
theory
web building
software
hardware
networking
law
hacking
gadgets
job
dnet
humor
miscellaneous
scrap
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
[C++] ШАГ 3-4. Сообщения пользователя 23.07.03 12:47  Число просмотров: 2146
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
Спасибо за ответы на мой пост. Вообще я себя чувствую немного не удобно, т.к. нагружаю Вас. Однако, прошу заметить, что Ваше мнение для меня очень важно и полезно.

Отвечу на замечания в конце сразу, когда мы все подведём черту топика.
Там будет, на мой взгляд, здорово из обсуждаемой модели выкинуть всё лишнее, чтобы получить НЕЧТО хорошее.
Кстати, не знаю как Вы, а я вижу, что с Вашей критикой у меня получается всё луше и луше.



*** ШАГ 3*

На предыдущем шаге 2 для различных групп объектов CWnd (диалогов, видов) предложено использовать различные экземпляры классов-потомков CMessanger c переопределёнными виртуальными методами FillControls,DisplayControls. Причиной было названо удобство организации передачи сообщений в пределах КАЖДОЙ ИЗ ГРУПП. Однако всё это опять только «косметика»…

Но есть причины разделения объектов на группы с различными месанджерами и функционального характера. В ряде случаев необходимо уметь посылать широковещательные сообщения всем членам группы. До сих пор сообщения, например, UM_ERASE обрабатывались только в теле FillControls,DisplayControls в том порядке, в котором мы определили:

switch(msg)
{
case UM_ERASE:
TV->ClearTree();
MAINPANEL->ClearControls();
PAGE_GENERAL->ClearControls();
PAGE2->ClearControls();

}

Если порядок обработки указанного сообщения для нас не важен (что вначале – TV, или MAINPANEL? см. врезку выше), то можно просто широковещательно рассылать сообщение UM_ERASE, например, при помощи функции SendMessage API, или одноимённого метода CWnd*. Сделаем это, определив для CMessanger функцию-член CMessanger:: SendMessage:

///////////////////////////////////////////////////
//
// file “utilwnd.h”
//
///////////////////////////////////////////////////

#include <afxtempl.h>

class CMessanger {
public:

class CWndInfo { // CWnd object info
public:
CWnd* m_pWnd;// pointer to CWnd registered object
UINT ID; // user symb.const. for CWnd registered object public:
CWndInfo() : m_pWnd(NULL), ID(0) {};
CWndInfo(CWnd* pWnd, UINT ID_WND = 0){
m_pWnd = pWnd; ID = ID_WND;
}
~CWndInfo() {};
};

public:

CMessanger() {};

// register CWnd object in CWndInfo array. Save pointer to CWnd object
// and user defined symbolic constant ID_WND for this CWnd object
void Register(CWnd* pWnd, UINT ID_WND)
{
m_aWnd.Add(new CWndInfo(pWnd, ID_WND));
}

// get CWnd* pointer from CWndInfo array by user defined constant ID_WND
CWnd* GetWnd(UINT ID_WND)
{
for (int i = 0; i < m_aWnd.GetSize(); i++)
if ( ID_WND == m_aWnd.GetAt(i)->ID) return m_aWnd.GetAt(i)->m_pWnd;
return NULL;
}

//**** main message handling****
virtual bool FillControls (UINT message,UINT ID_WND = IDW_ALL) {return true;};
virtual bool DisplayControls(UINT message,UINT ID_WND = IDW_ALL) {return true;};

//**** additional message handling****
// broadcast (ID_WND == IDW_ALL) or direct message handling
void SendMessage(UINT message , UINT ID_WND = IDW_ALL,
WPARAM wParam = 0, LPARAM lParam = 0);

private:
CArray <CWndInfo*, CWndInfo*> m_aWnd;
};

///////////////////////////////////////////////////
//
// file “utilwnd.cpp”
//
///////////////////////////////////////////////////
#include "StdAfx.h"
#include "utilwnd.h"

// broadcast (ID_WND == IDW_ALL) or direct message handling
void CMessanger::SendMessage(UINT message , UINT ID_WND, WPARAM wParam, LPARAM lParam)
{
for (int i = 0; i < m_aWnd.GetSize(); i++) { CWnd* pWnd = m_aWnd.GetAt(i)->m_pWnd;
if ( ID_WND == IDW_ALL|ID_WND == m_aWnd.GetAt(i)->ID)
pWnd->SendMessage(message, wParam, lParam);
}
}
//-------------------------------------------------------------

Для того, чтобы СWnd объект реагировал на событие UM_XXX, которое послано всем объектам группы (ID_WND == IDW_ALL), или только ему, необходимо для его класса определить соответствующий обработчик:

//////////////////////////////////////////////////////////////////////////
//
// CPageGeneral dialog declaration
//
/////////////////////////////////////////////////////////////////////////

class CPageGeneral : public Cdialog {

protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()

public:

afx_msg LRESULT OnSendMessage(WPARAM wParam, LPARAM lParam)
{
// Do something
return 0;
}

bool StartUp( void );
bool ClearControls( void );
bool Read ( void );


};


//////////////////////////////////////////////////////////////////////////
//
// CPageGeneral dialog implementation
//
/////////////////////////////////////////////////////////////////////////

BEGIN_MESSAGE_MAP(CPageGeneral, CDialog)

ON_MESSAGE(UM_NOTIFY, OnSendMessage)
END_MESSAGE_MAP()


Понятно, что при помощи анализа комбинации параметров wParam, lParam обработчика сообщения UM_NOTIFY можно легко разделить конкретные сообщения UM_STARTUP, UM_ERASE и т.д., и вызвать соответствующие обработчики-члены класса объекта, который получил сообщения. Например,

afx_msg LRESULT OnSendMessage(WPARAM wParam, LPARAM lParam)
{
if (wParam==UN_STARTUP)
return StartUp(); // см. выше определение класса
else if (wParam==UN_ERASE)
return ClearControls();// см. выше определение класса


return 0;
}

Как это можно использовать? Например, так:

void CPageGeneral::OnBnClickedEditButton()
{
// «одним махом» переводим все контролы в состояние ST_EDIT
// широковещательной рассылкой без использования
// функций методов FillControls, DisplayControls класса
// CMessanger
xxx.SendMessage(UM_NOTIFY, IDW_ALL, UM_EDIT, 0);
}

*PS к ШАГ 3**

1) Можно посылать широковещательные сообщения всем объектам сразу, без использования FillControls, DisplayControls, если последовательность обработки сообщений для всех объектов НЕ ВАЖНА. Не стоит быть наивным, полагая, что это всегда так и есть. Моя практика программирования ЭТОГО!!! показывает, что в СЛОЖНЫХ проектах не редки случаи, когда последовательность ВАЖНА. Не буду спорить о том, что зависимость от порядка обработки сообщений может быть вызвана только моим неумением программирования. По крайней мере, я об этом знаю и учитываю. Выбираю принцип такой – если, для ряда сообщений последовательность важна, то обработку выполняю, контролируя последовательность вызовов в FillControls, DisplayControls; если – нет, то обрабатываем широковещательно. Естественно, что одно не исключает другого, и можно комбинировать способы рассылки сообщений.

2) Если необходимо послать сообщение конкретному объекту, а не широковещательно всем, то в параметрах SendMessage заменяем макро IDW_ALL макроопределением IDW_XXX идентификатора требуемого объекта CWnd.

3) Может сложиться впечатление, что рассылка сообщений при помощи SendMessage приближает стиль программирования к парадигмам ООП, в отличие от использования FillControls, DisplayControls. Это было бы ложным утверждением. И SendMessage, и FillControls/DisplayControls в примерах выше вызывают ОДНИ И ТЕЖЕ МЕТОДЫ объектов CWnd (OnStartUp(), ClearControls(), см. определение диалога выше).

4) Я бы не противопоставлял возможность обработки сообщений при помощи FillControls/DisplayControls «альтернативному» методу доставки и анализа сообщений при помощи SendMessage. Я бы комбинировал одно и другое. У FillControls/DisplayControls есть одно преимущество – они позволяют прозрачно контролировать ОБЩУЮ общую логику событий приложения.

5) Забегая вперёд - о всё большей и большей схожести всего ЭТОГО!!! с медиатором и прочими музыкальными принадлежностями предлагаю высказаться другим. Мож просто медиатор взять, а остальное забыть?

****************************************************
*** ШАГ 4. Бродкасты*

На шаге 3 было показано, что в некоторых случаях, когда НЕ ВАЖНА последовательность обработки однотипных сообщений, весьма эффективны бодкасты при помощи механизма передачи сообщений API или соответствующих методов MFC, инкапсулирующих соответствующие вызовы API.

Однако для выполнения реальной работы с CWnd, например, с диалогом, который уловил UM_NOTIFY, в его обработчике UM_NOTIFY всё равно придётся анализировать WPARAM wParam, LPARAM lParam при помощи switch, или if. Согласитесь, немного всё продолжает оставаться корявым. И даже ещё в большей степени. То мы в FillControls/DisplayControls забубенили один свич, - то (что ещё хуже) до__бубенили ещё один свич в MFC-обработчик ON_MESSAGE(UM_NOTIFY, xxx). Да, всё плохо…

Тогда, для того, чтобы ввести в заблуждение доцента, преподающего ООП, и получить хоть тройку, скажем, что, дескать, наша модель ещё немножко и будет «почти ОО»; скажем, что, дескать, мы-то делаем конкретный проект, и у нас конкретные состояния приложения - enum app_state {ST_STARTUP, ST_CLOSE, ST_READ, и т.д.} myapp_state. Тогда решение на поверхности – для каждого из этих состояний приложения делаем свой бродкаст-обработчик EnableControls, ClearControls, ReadControls и др.:


///////////////////////////////////////////////////
//
// file “utilwnd.cpp”
//
///////////////////////////////////////////////////
class CMessanger {


public:
//**** main message handling****
virtual bool FillControls (UINT message,UINT ID_WND = IDW_ALL) {return true;};
virtual bool DisplayControls(UINT message,UINT ID_WND = IDW_ALL) {return true;};

//**** additional message handling****
// broadcast (ID_WND == IDW_ALL) or direct message handling
void SendMessage(UINT message , UINT ID_WND = IDW_ALL,
WPARAM wParam = 0, LPARAM lParam = 0);

//*special message handling*
//---------------------------------------
void EnableControls(bool status, UINT ID_WND = IDW_ALL)
{
SendMessage(UM_ENABLE_CONTROLS, ID_WND, status);
}
//---------------------------------------
void ClearControls(UINT ID_WND = IDW_ALL)
{
SendMessage(UM_CLEAR_CONTROLS, ID_WND);
}
//---------------------------------------
void ReadControls(UINT ID_WND = IDW_ALL)
{
SendMessage(UM_READ, ID_WND);
}
//---------------------------------------
};


Для того, что бы наш гипотетический диалог реагировал на эти бродкасты, редактируем месадж-мап его класса и определяем соответствующие afx_msg функции-члены:

//////////////////////////////////////////////////////////////////////////
//
// CPageGeneral dialog declaration
//
/////////////////////////////////////////////////////////////////////////

class CPageGeneral : public Cdialog {

protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()

public:

afx_msg LRESULT OnSendMessage(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnEnableControlMessage(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnClearControlMessage(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnReadControlMessage(WPARAM wParam, LPARAM lParam);

bool StartUp( void );
bool ClearControls( void );
bool Read ( void );


};


//////////////////////////////////////////////////////////////////////////
//
// CPageGeneral dialog implementation
//
/////////////////////////////////////////////////////////////////////////

BEGIN_MESSAGE_MAP(CPageGeneral, CDialog)

ON_MESSAGE(UM_NOTIFY, OnSendMessage)
ON_MESSAGE(UM_ ENABLE_CONTROLS, OnEnableControlMessage)
ON_MESSAGE(UM_CLEAR_CONTROLS, OnClearControlMessage)
ON_MESSAGE(UM_READ, OnReadControlMessage)
END_MESSAGE_MAP()


Как это можно использовать? Например, так:

void CPageGeneral::OnBnClickedButton1()
{
// очистить все контролы в группе theMsgGroup1
theMsgGroup1.ClearControls();

// очистить контролы ОДНОГО диалога IDW_XXXXX
// в группе theMsgGroup2
theMsgGroup2.ClearControls(IDW_XXXXX);
}


*** ШАГ 5*

Завтра. Пост и так здоровый получился. Пишите.
<programming> Поиск 






Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach