LEKCJA46.TXT

(26 KB) Pobierz
LEKCJA 46: O PROGRAMACH OBIEKTOWO - ZDARZENIOWYCH.  
________________________________________________________________ 
Po aplikacjach sekwencyjnych, proceduralno-zdarzeniowych, jedno- 
 
i dwupoziomowych, pora rozwa�y� dok�adniej stosowanie technik  
obiektowych.  
________________________________________________________________ 
 
Programy pracuj�ce w �rodowisku Windows tworzone s� w oparciu o  
tzw. model tr�jwarstwowy. Pierwsza warstwa to warstwa  
wizualizacji, druga - interfejs, a trzecia - to w�a�ciwa  
maszyneria programu. W tej lekcji zajmiemy si� "anatomi�"  
aplikacji wielowarstwowych a nast�pnie sposobami wykorzystania  
bogatego instrumentarium oferowanego przez Borlanda wraz z  
kompilatorami BC++ 3+...4+.  
 
Biblioteka OWL w wersjach BORLAND C++ 3, 3.1, 4 i 4.5 zawiera  
definicje klas potrzebnych do tworzenia aplikacji dla Windows.  
Fundamentalne znaczenie dla wi�kszo�ci typowych aplikacji maj�  
nast�puj�ce klasy:  
 
TModule (modu� - program lub biblioteka DLL) 
TApplication (program - aplikacja)  
TWindow (Okno)  
  
Rozpoczn� od kr�tkiego opisu dwu podstawowych klas.  
 
KLASA TApplication.  
 
Tworz�c obiekt klasy TNaszProgram b�dziemy wykorzystywa�  
dziedziczenie od tej w�a�nie klasy bazowej:  
 
class TNaszProgram : public TApplication  
 
Podstawowym celem zastosowania tej w�a�nie klasy bazowej jest  
odziedziczenie gotowej funkcji - metody virtual InitMainWindow() 
 
(zainicjuj g��wne okno programu). Utworzenie obiektu klasy  
TNaszProgram nast�puje zwykle w czterech etapach:  
 
* Windows uruchamiaj� program wywo�uj�c g��wn� funkcj� WinMain() 
 
 lub OwlMain() wchodz�c� w sk�ad ka�dej aplikacji.  
* Funkcja WinMain() tworzy przy pomocy operatora new nowy obiekt 
 
- aplikacj�.  
* Obiekt - aplikacja zaczyna funkcjonowa�. Konstruktor obiektu  
(w�asny, b�d� odziedziczony po klasie TApplication) wywo�uje  
funkcj� - wirtualn� metod� InitMainWindow(). 
* Funkcja przy pomocy operatora new tworzy obiekt - okno  
aplikacji.  
 
Wska�nik do utworzonego obiektu zwraca funkcja GetApplication(). 
 
Dla zobrazowania mechanizm�w poni�ej przedstawiamy uproszczony  
"wyci�g" z dwu opisywanych klas. Nie jest to dok�adna kopia kodu 
 
�r�d�owego Borlanda, lecz skr�t tego kodu pozwalaj�cy na  
zrozumienie metod implementacji okienkowych mechanizm�w wewn�trz 
 
klas biblioteki OWL i tym samym wewn�trz obiekt�w obiektowo -  
zdarzeniowych aplikacji.  
A oto najwa�niejsze elementy implementacji klasy TApplication:  
 
- Konstruktor obiektu "Aplikacja":  
 
TApplication::TApplication(const char far* name,  
                           HINSTANCE       Instance,  
                           HINSTANCE       prevInstance,  
                           const char far* CmdLine,  
                           int             CmdShow,  
                           TModule*&       gModule)  
{  
  hPrevInstance = prevInstance;  
  nCmdShow = CmdShow;  
  MainWindow = 0;  
  HAccTable = 0;              //Accelerator Keys Table Handle 
  BreakMessageLoop = FALSE; 
  AddApplicationObject(this);    //this to wska�nik do w�asnego 
  gModule = this;           //obiektu, czyli do bie�. aplikacji 
}  
  
Funkcja - metoda "Zainicjuj Instancj�": 
 
void TApplication::InitInstance()  
{  
  InitMainWindow();  
if (MainWindow)  
   {  
    MainWindow->SetFlag(wfMainWindow);  
    MainWindow->Create();  
    MainWindow->Show(nCmdShow);  
   }  
 
Metoda "Zainicjuj g��wne okno aplikacji":  
 
void TApplication::InitMainWindow()  
{  
  SetMainWindow(new TFrameWindow(0, GetName()));  
}  
 
Metoda Run() - "Uruchom program":  
 
int TApplication::Run()  
{  
  int status;  
   {  
    if (!hPrevInstance) InitApplication();  
    InitInstance();  
    status = MessageLoop();  
  }  
 
A oto p�tla pobierania komunikat�w w uproszczeniu. "Pump" to po  
prostu "pompowanie" komunikat�w (message) oczekuj�cych (waiting) 
 
w kolejce. PeekMessage() to sprawdzenie, czy w kolejce oczekuje  
komunikat. PM_REMOWE to "brak komunikatu". 
 
BOOL TApplication::PumpWaitingMessages()  
{  
  MSG  msg;  
  BOOL foundOne = FALSE;  
  
  while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))  
     {  
    foundOne = TRUE;  
    if (msg.message == WM_QUIT)  
      {  
      BreakMessageLoop = TRUE;  
      MessageLoopResult = msg.wParam;  
      ::PostQuitMessage(msg.wParam);  
      break;  
    }  
  
    if (!ProcessAppMsg(msg))  
      {  
      ::TranslateMessage(&msg);  
      ::DispatchMessage(&msg);  
    }  
  }  
  return foundOne;  
}  
  
int TApplication::MessageLoop()  
{  
  long idleCount = 0;  
MessageLoopResult = 0;  
  while (!BreakMessageLoop) {  
    TRY {  
      if (!IdleAction(idleCount++))  
        ::WaitMessage();           
      if (PumpWaitingMessages())      
        idleCount = 0;  
    }  
      if (MessageLoopResult != 0) {  
        ::PostQuitMessage(MessageLoopResult);  
        break;  
      }  
    })  
  }  
  BreakMessageLoop = FALSE;  
  return MessageLoopResult;  
}  
  
else if (::IsWindowEnabled(wnd)) {  
      *(info->Wnds++) = wnd;  
      ::EnableWindow(wnd, FALSE);  
    }  
  }  
  return TRUE;  
}  
  
 
KLASA TWindow.  
 
Klasa TWindow (Okno) zawiera implementacj� wielu przydatnych  
przy tworzeniu aplikacji "cegie�ek". Poni�ej przedstawiono  
fragment pliku �r�d�owego (patrz \SOURCE\OWL\WINDOW.CPP). �atwo  
mo�na rozpozna� pewne znane ju� elementy.  
 ... 
extern LRESULT FAR PASCAL _export InitWndProc(HWND, UINT,  
WPARAM, LPARAM);  
 ... 
struct TCurrentEvent       //Struktura Bie��ceZdarzenie 
{  
  TWindow*  win;           //Wska�nik do okna 
  UINT      message;       //Komunikat 
  WPARAM    wParam;         
  LPARAM    lParam;  
}; 
 ... 
DEFINE_RESPONSE_TABLE(TWindow)  
//Makro: Zdefiniuj tablic� odpowiedzi na zdarzenia 
//EV_WM_SIZE - Zdarzenie (EVent)-nadszed� komunikat WM_SIZE  
  ... 
  EV_WM_SETCURSOR,  
  EV_WM_SIZE,  
  EV_WM_MOVE,  
  EV_WM_PAINT,  
  EV_WM_LBUTTONDOWN,  
  EV_WM_KILLFOCUS,  
  EV_WM_CREATE,  
  EV_WM_CLOSE,  
  EV_WM_DESTROY, 
  EV_COMMAND(CM_EXIT, CmExit),  
  ...  
END_RESPONSE_TABLE;  
 
Funkcje - metody obs�uguj�ce komunikaty zaimplementowane zosta�y 
 
wewn�trz klasy TWindow tak: 
 
TWindow::EvCreate(CREATESTRUCT far&)  
{  
  SetupWindow();  
  return (int)DefaultProcessing();  
}  
  
void TWindow::EvSize(UINT sizeType, TSize&)  
{  
  if (Scroller && sizeType != SIZE_MINIMIZED)  
  {  
    Scroller->SetPageSize();  
    Scroller->SetSBarRange();  
  }  
} 
 
Metoda GetWindowClass() bardzo przypomina klasyczne  
zainicjowanie zanej ju� struktury WNDCLASS:  
 
void TWindow::GetWindowClass(WNDCLASS& wndClass)  
{  
  wndClass.cbClsExtra = 0;  
  wndClass.cbWndExtra = 0;  
  wndClass.hInstance = *GetModule();  
  wndClass.hIcon = 0;  
  wndClass.hCursor = ::LoadCursor(0, IDC_ARROW);  
  wndClass.hbrBackground = HBRUSH(COLOR_WINDOW + 1);  
  wndClass.lpszMenuName = 0;  
  wndClass.lpszClassName = GetClassName();  
  wndClass.style = CS_DBLCLKS;  
  wndClass.lpfnWndProc = InitWndProc;  
}  
  
Skoro te wszystkie "klocki" zosta�y ju� zaimplementowane  
wewn�trz definicji klas, nasze programy powinny tylko umiej�tnie 
 
z nich korzysta� a teksty �r�d�owe program�w powinny ulec  
skr�ceniu i uproszczeniu.  
 
STADIA TWORZENIA OBIEKTOWEJ APLIKACJI.  
 
Poniewa� znakomita wi�kszo�� dzisiejszych u�ytkownik�w pracuje z 
 
Windows 3.1, 3.11, i NT - zaczniemy tworzenie aplikacji od  
umieszczenia na pocz�tku informacji dla OWL, �e nasz docelowy  
program ma by� przeznaczony w�a�nie dla tego �rodowiska:  
 
#define WIN31  
 
Jak ju� wiemy dzi�ki kr�tkiemu przegl�dowi struktury bazowych  
klas przeprowadzonemu powy�ej - funkcje API Windows s� w istocie 
 
klasycznymi funkcjami pos�uguj�cymi si� mechanizmami j�zyka C.  
C++ jest "pedantem typologicznym" i przeprowadza dodatkowe  
testowanie typ�w parametr�w przekazywanych do funkcji (patrz  
"Technika programowania w C++"). Aby u�atwi� wsp�prac�,  
zwi�kszy� poziom bezpiecze�stwa i "uregulowa�" potencjalne  
konflikty - dodamy do programu:  
 
#define STRICT  
 
Chc�c korzysta� z biblioteki OWL wypada do��czy� w�a�ciwy plik  
nag��wkowy:  
 
#include <owl.h>  
 
Plik OWL.H zawiera ju� wewn�trz do��czony WINDOWS.H, kt�ry  
wyst�powa� we wcze�niejszych aplikacjach proceduralno -  
zdarzeniowych i jeszcze par� innych plik�w.  
Poniewa� chcemy skorzysta� z gotowych zasob�w - odziedziczymy  
pewne cechy po klasie bazowej TApplication. Zgodnie z zasadami  
programowania obiektowego chc�c utworzy� obiekt musimy najpierw  
zdefiniowa� klas�:  
 
class TOkno ... 
 
i wskaza� po kt�rej klasie bazowej chcemy dziedziczy�:  
 
class TOkno  :  public TApplication  
{  
 ...  
 
Konstruktor obiektu klasy TOkno powinien tylko przekaza�  
parametry konstruktorowi klasy bazowej - i ju�.  
 
class TOkno  :  public TApplication  
{ 
public:  
TOkno(LPSTR name, HANDLE hInstance, HANDLE hPrevInstance,  
      LPSTR lpCmdLine, int nShow)  :  TApplication(name,  
      hInstance, hPrevInstance, lpCmdLine, nShow)  
  {  
    return;  
  }  
  virtual void InitMainWindow();  
};  
 
Umie�cili�my w definicji klasy jeszcze jedn� funkcj� inicjuj�c�  
g��wne okno aplikacji. Mo�emy j� zdefiniowa� np. tak:  
 
void TOkno::InitMainWindow(void)  
{  
  MainWindow = new (TWindow(0, "Napis - Tytul Okna"));  
}  
 
Dzia�anie funkcji polega na utworzeniu nowego obiektu (operator  
new) klasy bazowej TWindow. G��wne okno stanie si� zatem  
obiektem klasy TWindow (Niekt�re specyficzne aplikacje pos�uguj� 
 
si� okienkiem dialogowym jako g��wnym oknem programu. W takiej  
sytuacji dziedziczenie powinno nast�powa� po klasie TDialog).  
Konstruktorowi tego obiektu przekazujemy jako parame...
Zgłoś jeśli naruszono regulamin