Witam.
Zaplanowałem sobie że zbuduję sobie kilka klas które będą odpowiedzialne za działanie poszczególnych elementów interfejsu budowanego programu - mianowicie okienko główne, pola tekstowe, przyciski itp. Problemem jest funkcja obsługi zdarzeń - a z tego co wiem może być jedna w systemie do której Windows będzie aktualnie przekazywał komunikaty o zdarzeniach zachodzących w naszej aplikacji.
Mimo wszystko jest możliwość utworzenia np. obiektu "edit" i przekazanie mu w czasie tworzenia adresu procedury obsługi zdarzeń innej niż dla głównego okienka. Jak w takim wypadku sprawić aby akcja wykonana na okienku "edit" powodowała wywołanie procedury przypisanej do tego właśnie okienka???
Poniżej część kodu:
Plik z funkcją "WinMain"
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR,int)
{
okienko x = okienko(hInstance);
x.ustawRozmiar(810, 620);
x.wyswietl();
okienkoTXT zzz = okienkoTXT(x.kontekst());
zzz.wyswietl(10, 420, 600, 160);
x.dodajOkienkoTxt(&zzz);
MSG msg;
while( msg.message!=WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return 0;
}
Plik z definicją klasy okna głównego
class okienkoTXT;
class okienko
{
public:
okienko(HINSTANCE );
~okienko();
inline HWND kontekst(){ return hWnd;};
void ustawRozmiar(int x_T, int y_T) { poczatkowyRozmiarX = x_T;
poczatkowyRozmiarY = y_T;};
void dodajOkienkoTxt(okienkoTXT* tmp){oknoTxt = tmp;};
void wyswietl();
private:
int poczatkowyRozmiarX;
int poczatkowyRozmiarY;
HINSTANCE hInst;
HWND hPrzycisk;
HWND hWnd;
HBITMAP hBitmapa;
UINT rozmiarStrWndClass; //cbSize
UINT opcjeKlsy; //style
WNDPROC wskNaProcZdarzeniowa; //lpfnWndProc
int iloscDodatkowychZasKlasy; //cbClsExtra
int iloscAlokowanychZasobow; //cbWndExtra
HICON uchwytIkony; //hIcon
HINSTANCE uchwytInstancjiPr; //hInstance
HCURSOR uchhwytKursora; //hCursor
HBRUSH uchwytPedzla; //hbrBackground
LPCTSTR nazwaZasPaskaMenu; //lpszMenuName
LPCTSTR nazwaKlasyOkna; //lpszClassName
HICON uchwytIkonyMalej; //hIconSm
static LRESULT CALLBACK StaticProcOkna(HWND,UINT,WPARAM,LPARAM);
LRESULT ProcOkna(UINT,WPARAM,LPARAM);
inline void ustawHwnd(HWND temp){hWnd = temp;};
okienkoTXT* oknoTxt;
};
Plik z implementacją metod z klasy okna głównego
/*****************************************************************************/
okienko::okienko(HINSTANCE hInstance):hInst(hInstance),
hWnd(NULL),
hPrzycisk(NULL),
hBitmapa(NULL),
oknoTxt(NULL)
{
poczatkowyRozmiarX = 800;
poczatkowyRozmiarY = 600;
rozmiarStrWndClass = sizeof(WNDCLASSEX);
opcjeKlsy = CS_HREDRAW|CS_VREDRAW;
wskNaProcZdarzeniowa = (WNDPROC) StaticProcOkna;
iloscDodatkowychZasKlasy = 0;
iloscAlokowanychZasobow = 0;
uchwytIkony = NULL;
uchwytInstancjiPr = GetModuleHandle(NULL);
uchhwytKursora = LoadCursor(NULL,IDC_ARROW);
uchwytPedzla = (HBRUSH) COLOR_WINDOW;
nazwaZasPaskaMenu = NULL;
nazwaKlasyOkna = "ProgramGl";
uchwytIkonyMalej = NULL;
};
/*****************************************************************************/
okienko::~okienko()
{
//.......
};
/*****************************************************************************/
LRESULT okienko::ProcOkna(UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_SIZE:
if (oknoTxt!=NULL)
{
oknoTxt->zmienRozmiar(10, 10, 100, 100);
InvalidateRect(oknoTxt->kontekst(), NULL, FALSE);
}
break;
default:
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
};
/*****************************************************************************/
LRESULT CALLBACK okienko::StaticProcOkna(HWND hWndx,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
okienko* pParent;
if(uMsg == WM_CREATE)
{
pParent = (okienko*)((LPCREATESTRUCT)lParam)->lpCreateParams;
SetWindowLongPtr(hWndx,GWL_USERDATA,(LONG_PTR)pParent);
}
else
{
pParent = (okienko*)GetWindowLongPtr(hWndx,GWL_USERDATA);
if(!pParent) return DefWindowProc(hWndx,uMsg,wParam,lParam);
}
pParent->ustawHwnd(hWndx);
return pParent->ProcOkna(uMsg,wParam,lParam);
}
/*****************************************************************************/
void okienko::wyswietl()
{
WNDCLASSEX klasaOkna;
ZeroMemory(&klasaOkna, sizeof(klasaOkna));
{
klasaOkna.cbClsExtra = iloscDodatkowychZasKlasy;
klasaOkna.cbSize = rozmiarStrWndClass;
klasaOkna.cbWndExtra = iloscAlokowanychZasobow;
klasaOkna.hbrBackground = uchwytPedzla;
klasaOkna.hCursor = uchhwytKursora;
klasaOkna.hIcon = uchwytIkony;
klasaOkna.hIconSm = uchwytIkonyMalej;
klasaOkna.hInstance = uchwytInstancjiPr;
klasaOkna.lpfnWndProc = wskNaProcZdarzeniowa ;
klasaOkna.lpszClassName = nazwaKlasyOkna;
klasaOkna.lpszMenuName = nazwaZasPaskaMenu;
klasaOkna.style = opcjeKlsy;
}
RegisterClassEx(&klasaOkna);
hWnd = CreateWindow(nazwaKlasyOkna,
nazwaKlasyOkna,
WS_OVERLAPPEDWINDOW | WS_CAPTION, //& ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX
CW_USEDEFAULT,
CW_USEDEFAULT,
poczatkowyRozmiarX,
poczatkowyRozmiarY,
HWND_DESKTOP,
NULL,
hInst,
this);
SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG)StaticProcOkna);
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
};
/*****************************************************************************/
Plik z definicją klasy elementu "edit"
class okienkoTXT
{
public:
okienkoTXT(HWND hwnd_T){parentHwnd = hwnd_T;};
~okienkoTXT(){};
void wyswietl(int, int, int, int);
void zmienRozmiar(int, int, int, int);
HWND kontekst(){return textHwnd;};
private:
static LRESULT CALLBACK staticProcOknaTXT(HWND, UINT, WPARAM, LPARAM);
LRESULT procOknaTXT(UINT, WPARAM, LPARAM);
inline void ustawHwnd(HWND temp){parentHwnd = temp;};
int pozycjaX;
int pozycjaY;
int rozmiarX;
int rozmiarY;
HWND parentHwnd;
HWND textHwnd;
};
Plik z implementacją metod z klasy elementu "edit"
/*****************************************************************************/
LRESULT okienkoTXT::procOknaTXT(UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_CREATE:
break;
case WM_PAINT:
break;
case WM_CTLCOLOREDIT:
SetTextColor((HDC)wParam, RGB(0, 255, 0));
SetBkColor((HDC)wParam, RGB(50, 50, 50));
return (LRESULT)(CreateSolidBrush(RGB(50, 50, 50)));
break;
default:
return DefWindowProc(parentHwnd,Msg,wParam,lParam);
};
return DefWindowProc(parentHwnd,Msg,wParam,lParam);
};
/*****************************************************************************/
LRESULT CALLBACK okienkoTXT::staticProcOknaTXT(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
okienkoTXT* pParent;
if(uMsg == WM_CREATE)
{
pParent = (okienkoTXT*)((LPCREATESTRUCT)lParam)->lpCreateParams;
SetWindowLongPtr(hWnd,GWL_USERDATA,(LONG_PTR)pParent);
}
else
{
pParent = (okienkoTXT*)GetWindowLongPtr(hWnd,GWL_USERDATA);
if(!pParent) return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
//pParent->ustawHwnd(hWnd);
return pParent->procOknaTXT(uMsg,wParam,lParam);
};
/*****************************************************************************/
void okienkoTXT::wyswietl(int x1, int y1, int x2, int y2)
{
textHwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_SIZEBOX | WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL ,x1,y1,x2,y2, parentHwnd,(HMENU)200, GetModuleHandle(NULL), this);
SetWindowLongPtr(textHwnd, GWL_WNDPROC, (LONG)staticProcOknaTXT);
HFONT smallfont;
smallfont = CreateFont( 13, // logical height of font
5, // logical average character width
0, // angle of escapement
0, // base-line orientation angle
0, // font weight
0, // italic attribute flag
0, // underline attribute flag
0, // strikeout attribute flag
0, // character set identifier
0, // output precision
0, // clipping precision
ANTIALIASED_QUALITY, // output quality
FF_MODERN | VARIABLE_PITCH , // pitch and family
"Areal" ); // pointer to typeface name string
SendMessage(textHwnd, WM_SETFONT, ( WPARAM ) smallfont, false );
ShowWindow(textHwnd,SW_SHOW);
UpdateWindow(textHwnd);
};
/*****************************************************************************/
void okienkoTXT::zmienRozmiar(int x1, int y1, int x2, int y2)
{
SetWindowPos(textHwnd, HWND_TOP, x1, y1, x2, y2, SWP_NOMOVE);
UpdateWindow(textHwnd);
};
/*****************************************************************************/
Oczywiście pousuwałem część kodu (metod nie mających teraz znaczenia) z klas - mam jedynie nadzieję że nie wyciąłem zbyt wiele. Nie ma min. dyrektyw "#include ..."
Małe objaśnienie kodu:
- Są dwie klasy główne - odpowiedzialna za okienko główne (klasa "okienko") oraz za pole tekstowe (klasa "okienkoTXT")
- Klasa okienka głównego ma dostęp do metod klasy okienka tekstowego przez wskaźnik do tej właśnie klasy pola tekstowego umieszczony w obrębie klasy okienka głównego (zmienna o nazwie "oknoTxt" w klasie "okienko")
- Klasa okienka głównego ma przypisaną swoją procedurę obsługi wywoływaną przez system Windows w momencie jakiegoś zdarzenia wykonanego na tym okienku (procedura: "... okienko::StaticProcOkna( ... ){ ... }" )
- Procedura "... okienko::StaticProcOkna ..." przekazuje sterowanie do funkcji wewnętrznej klasy "okienko" aby ta miała dostęp do wewnętrznych elementów tej klasy (funkcja ta to: "... okienko::ProcOkna( ... ){ ... }")
- Pole "edit" w klasie "okienkoTXT" ma również przypisaną swoją procedurę obsługi która (teoretycznie) powinna stać się domyślną procedurą gdy zostanie wywołane jakieś zdarzenie na polu "edit" (procedura ta to: "... okienkoTXT::StaticProcOknaTXT( ... ){ ... }")
- Procedura "... okienkoTXT::StaticProcOknaTXT ..." przekazuje sterowanie do funkcji wewnętrznej klasy "okienkoTXT" aby ta miała dostęp do wewnętrznych elementów tej klasy (funkcja ta to: "... okienkoTXT::ProcOknaTXT( ... ){ ... }")
Co chciałem osiągnąć:
- Klasy odpowiadają za poszczególne elementy "funkcjonalne" aplikacji - łącznie z obsługą zdarzeń przekazanych do "kontrolowanego" elementu aplikacji (np. powyżej pole "edit")
- Zmiana rozmiaru okna głównego (parent) powoduje jakąś ustaloną zmianę rozmiaru elementu na tym okienku (child)
I teraz co się dziej po uruchomieniu:
- Wyświetla się okno główne i na nim pole tekstowe. Gdy zmienię rozmiar okna głównego to faktycznie jest zmieniony rozmiar okienka tekstowego do określonych rozmiarów (czyli procedura "okienko::ProcOkna()" działa i jest wywoływana z komunikatem WM_SIZE). Natomiast problemem jest to że pole edit nie posiada określonego tła ani też czcionki... i w ogóle nie jest aktywne.
- Gdy w metodzie "void okienkoTXT::wyswietl(int x1, int y1, int x2, int y2) {}" zmienię kod "SetWindowLongPtr(textHwnd, GWL_WNDPROC, (LONG)staticProcOknaTXT);" na "SetWindowLongPtr(parentHwnd, GWL_WNDPROC, (LONG)staticProcOknaTXT);" to pole "edit" wyświetlane jest w odp. kolorze i kolor czcionki jest taki jak ustaliłem (pole jest aktywne i można w nim pisać) ale zmiana rozmiarów okna głównego NIE POCIĄGA za sobą określonej zmiany rozmiaru pola "edit"
NO I PYTANIE:
Coś tutaj totalnie schrzaniłem.... coś źle sobie "wykombinowałem" lub o czymś zapomniałem.... Jak zrobić aby każdy element zamknięty (opakowany) w klasę miał soją procedurę obsługi zdarzeń... i jak wymusić interakcję między klasami... W jaki sposób zrobić aby akcja na okienku powodowała wywołanie procedury obsługi okienka, a akcja na polu "edit" powodowała wywołanie procedury obsługi pola "edit"?????</span>