Win API - Správy a LISTBOX
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Win API - Správy a LISTBOXWin API - Správy a LISTBOX

 

Win API - Správy a LISTBOX

Google       Google       23. 5. 2009       17 562×

V tomto dieli sa budeme venovať vzájomnej komunikácii medzi oknami a na záver si ukážeme vytvorenie ovládacieho prvku LISTBOX. Pôvodne mal byť tento článok o niečom inom (FTP), ale presunieme si to do ďalšieho dielu.

Komunikácia medzi oknami

Prebieha pomocou správ. Je to veľmi jednoduché, pretože to funguje presne tak ako doteraz, keď Windows zasielal správy našim oknám. Okná si môžu správy zasielať aj medzi sebou a to pomocou funkcie:

 SendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
Jednotlivé parametre sú:
  • hWnd - manipulátor okna, ktorému chceme správu zaslať,
  • Msg - identifikátor správy, ktorú chceme zaslať,
  • hWnd - wParam správy,
  • hWnd - lParam správy.
Správy odoslané pomocou tejto funkcie sa dostanú až k procedúre okna, kde ich môžeme spracovať rovnako ako napr. správu WM_CREATE, WM_PAINT a podobne.

Čo sú správy

Správy sú obyčajné čísla, ktoré majú pomocou príkazu #define priradený identifikátor. Napríklad správa WM_CREATE má hodnotu 1, WM_PAINT = 15, a podobne. Pre zaujímavosť uvádzam úryvok zo súboru winuser.h, kde sú tieto správy definované.

#define WM_CREATE 1
#define WM_CTLCOLORBTN 309
#define WM_CTLCOLORDLG 310
#define WM_CTLCOLOREDIT 307
#define WM_CTLCOLORLISTBOX 308
#define WM_CTLCOLORMSGBOX 306
#define WM_CTLCOLORSCROLLBAR 311
#define WM_CTLCOLORSTATIC 312
#define WM_CUT 768
#define WM_DEADCHAR 259
#define WM_DELETEITEM 45
#define WM_DESTROY 2
#define WM_DESTROYCLIPBOARD 775
#define WM_DEVICECHANGE 537
#define WM_DEVMODECHANGE 27
#define WM_DISPLAYCHANGE 126
#define WM_DRAWCLIPBOARD 776
#define WM_DRAWITEM 43
#define WM_DROPFILES 563
#define WM_ENABLE 10
#define WM_ENDSESSION 22
#define WM_ENTERIDLE 289
#define WM_ENTERMENULOOP 529
#define WM_ENTERSIZEMOVE 561
#define WM_ERASEBKGND 20
#define WM_EXITMENULOOP 530
#define WM_EXITSIZEMOVE 562
#define WM_FONTCHANGE 29
#define WM_GETDLGCODE 135
#define WM_GETFONT 49
#define WM_GETHOTKEY 51
#define WM_GETICON 127
#define WM_GETMINMAXINFO 36
#define WM_GETTEXT 13
#define WM_GETTEXTLENGTH 14
/* FIXME/CHECK: Are WM_HANDHEL{FIRST,LAST} valid for WINVER < 0x400? */
#define WM_HANDHELDFIRST 856
#define WM_HANDHELDLAST 863
#define WM_HELP 83
#define WM_HOTKEY 786
#define WM_HSCROLL 276
#define WM_HSCROLLCLIPBOARD 782
#define WM_ICONERASEBKGND 39
#define WM_INITDIALOG 272
#define WM_INITMENU 278
#define WM_INITMENUPOPUP 279
#define WM_INPUTLANGCHANGE 81
#define WM_INPUTLANGCHANGEREQUEST 80
#define WM_KEYDOWN 256
#define WM_KEYUP 257
#define WM_KILLFOCUS 8
#define WM_MDIACTIVATE 546
Ak by mal niekto záujem, nie je problém nájsť si súbor winuser.h, otvoriť ho a trochu si ho poobzerať. Práve vďaka tomuto systému, kde správa ako text predstavuje určité číslo, ide o systém, ktorý je pomerne jednoduchý na zapamätanie (ťažko by ste si pamätali, že pri vytvorení okna dostane okno "správu" 1, pri maľovaní 15, pri pustení tlačidla na klávesnici zasa 257 a pod.). Okrem týchto preddefinovaných správ môžeme pomocou funkcie SendMessage(...) posielať aj naše "vymyslené" správy. Ak chceme nášmu dcérskemu oknu povedať, že má napr. prepísať text v nadpise, pošleme mu SendMessage(hWndChild,MM_PREPIS,NULL,NULL); pričom identifikátoru MM_PREPIS priradíme hodnotu, ktorá by sa nemala zhodovať s preddefinovanými správami. Túto správu potom jednoducho spracujeme pomocou procedúry dcérskeho okna:
LRESULT CALLBACK WndProc(HWND hWndChild, UINT message, WPARAM wParam, LPARAM lParam)   
{   
        switch(message)   
        {  case MM_PREPIS:
           /*Kód ktorý chcete vykonať*/
           break;
          .........................
          case WM_DESTROY:   
          PostQuitMessage(0);   
          return 0;   
        }   
        return DefWindowProc(hWnd, message, wParam, lParam);   
}  
Pomocou správ taktiež komunikujeme s ovládacími prvkami. Teraz si to ukážeme na jednoduchom príklade s využitím ovládacieho prvku typu LISTBOX.

LISTBOX

Na úvod uvediem kód ukážkového programu. Pre zmenu je použitý a upravený kód z Dev C++.

#include 
#define Pridaj              101
#define Odober              102
#define Zobraz              103
#define EditText            104
#define EditData            105

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";
HWND button[3],edit,listBox;
char buffer[256];
                                 

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)

{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nFunsterStil);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {   case WM_CREATE:
        edit = CreateWindow("EDIT","Text", WS_CHILD | WS_VISIBLE | ES_CENTER | ES_AUTOHSCROLL , 10,20,100,20,hwnd,(HMENU)EditText,NULL,NULL);
        button [0] = CreateWindow("BUTTON","Pridaj", WS_CHILD | WS_VISIBLE, 120,20,100,20,hwnd,(HMENU)Pridaj,NULL,NULL);
        button [1] = CreateWindow("BUTTON","Odober", WS_CHILD | WS_VISIBLE, 10,50,100,20,hwnd,(HMENU)Odober,NULL,NULL);
        button [2] = CreateWindow("BUTTON","Zobraz", WS_CHILD | WS_VISIBLE, 120,50,100,20,hwnd,(HMENU)Zobraz,NULL,NULL);        
        listBox = CreateWindow("LISTBOX","", WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_HASSTRINGS , 230,20,150,100,hwnd,NULL,NULL,NULL); 
        break;
        case WM_COMMAND:
             switch(LOWORD(wParam))
             {case Pridaj:
                   GetWindowText(edit,buffer,255);
                   index = SendMessage(listBox,LB_INSERTSTRING,-1,(LPARAM)&buffer);
                   break;
             case Odober:
                  index = SendMessage(listBox,LB_GETCURSEL,NULL,NULL);
                  SendMessage(listBox,LB_DELETESTRING ,(WPARAM)index,NULL);                  
                  break;
             case Zobraz:
                  index = SendMessage(listBox,LB_GETCURSEL,NULL,NULL); 
                  SendMessage(listBox,LB_GETTEXT,(WPARAM)index,(LPARAM)&buffer); 
                  MessageBox(hwnd,buffer,"Text:",MB_OK);
                  break;
             default:
                   break;
                                   }
             break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
Teraz si vysvetlíme základné časti programu. Nebudeme ho však vysvetľovať celý. Ak budete potrebovať vysvetliť program podrobnejšie, pozrite do úvodnych dielov tohoto seriálu (od Kamila Skálu (Stormu)), alebo článok Direct 3D - 1. diel (odo mňa).
#define Pridaj              101
#define Odober              102
#define Zobraz              103
#define EditText            104
#define EditData            105

char szClassName[ ] = "WindowsApp";
HWND button[3],edit,listBox;
char buffer[256];
Ide o identifikátory ovládacich prvkov a o potrebné premenné. Ďalej sa pozrieme na spracovanie jednotlivých správ, zvyšku by ste mali rozumieť...
case WM_CREATE:
        edit = CreateWindow("EDIT","Text", WS_CHILD | WS_VISIBLE | ES_CENTER | ES_AUTOHSCROLL , 10,20,100,20,hwnd,(HMENU)EditText,NULL,NULL);
        button [0] = CreateWindow("BUTTON","Pridaj", WS_CHILD | WS_VISIBLE, 120,20,100,20,hwnd,(HMENU)Pridaj,NULL,NULL);
        button [1] = CreateWindow("BUTTON","Odober", WS_CHILD | WS_VISIBLE, 10,50,100,20,hwnd,(HMENU)Odober,NULL,NULL);
        button [2] = CreateWindow("BUTTON","Zobraz", WS_CHILD | WS_VISIBLE, 120,50,100,20,hwnd,(HMENU)Zobraz,NULL,NULL);        
        listBox = CreateWindow("LISTBOX","", WS_CHILD | WS_VISIBLE | WS_BORDER | LBS_HASSTRINGS , 230,20,150,100,hwnd,NULL,NULL,NULL); 
Vytvorenie okna EDIT a BUTTON by vám už malo byť známe a LISTBOX pochopíte v tomto článku. LISTBOX vytvárate rovnako ako BUTTON a EDIT s tým rozdielom, že ako triedu použijete "LISTBOX". Na komunikáciu s LISTBOX-om budeme používať správy a funkciu SendMessage(...). Ako? To uvidíte neskôr.
case WM_COMMAND:
             switch(LOWORD(wParam))
             {case Pridaj:
                   GetWindowText(edit,buffer,255);
                   index = SendMessage(listBox,LB_INSERTSTRING,-1,(LPARAM)&buffer);
                   break;
Najprv získame text z EDITBOX-u pomocou GetWindowText(..) a potom ho pridáme do zoznamu SendMessage(..).
  • listBox je manipulátor LISTBOX-um ktorému posielame správu,
  • LB_INSERTSTRING je identifikátor správy, ktorú posielame oknu (LB_INSERTSTRING - vloží reťazec do zoznamu),
  • lParam a wParam pre každú správu znamená niečo iné. Pre túto správu -1 znamená, že pridá reťazec na koniec zoznamu a &buffer je adresa bufferu v ktorom je text.
case Odober:
                  index = SendMessage(listBox,LB_GETCURSEL,NULL,NULL);
                  SendMessage(listBox,LB_DELETESTRING ,(WPARAM)index,NULL);                  
                  break;
             case Zobraz:
                  index = SendMessage(listBox,LB_GETCURSEL,NULL,NULL); 
                  SendMessage(listBox,LB_GETTEXT,(WPARAM)index,(LPARAM)&buffer); 
                  MessageBox(hwnd,buffer,"Text:",MB_OK);
                  break;
Najprv zistíme pomocou zaslania správy LB_GETCURSEL, ktorá položka v LISTBOX-e je vybraná. Potom ju zmažeme pomocou LB_DELETESTRING. Na zobrazenie položky zistíme najprv jej index v LISTBOX-e (LB_GETCURSEL) a potom získame text na danej polohe pomocou LB_GETTEXT, pričom wParam je práve index reťazca v LISTBOX-e a lParam je adresa bufferu na uloženie daného reťazca. Pre podrobnejšie informácie viď MSDN.com.

Čo dalej? Verím, že ste plní očakávania a preto do ďalšieho dielu zaradím niečo o FTP, niečo o súboroch, niečo o tlači a tak podobne. Ako bonus napíšem aj o programovaní pre Windows Mobile.

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

3 názory  —  3 nové  
Hlasování bylo ukončeno    
0 hlasů
Google
Autor sa venuje programovaniu v C++, PHP a JavaScript-e. Taktiež programujte grafiku pomocou Direct 3D a OpenGL. Mimo IT má rád dobré filmy, cyklistiku, lyžovanie a plávanie.
Web    

Nové články

Obrázek ke článku Stavebnice umělé inteligence 1

Stavebnice umělé inteligence 1

Článek popisuje první část stavebnice umělé inteligence. Obsahuje lineární a plošnou optimalizaci.  Demo verzi je možné použít pro výuku i zájmovou činnost. Profesionální verze je určena pro vývojáře, kteří chtějí integrovat popsané moduly do svých systémů.

Obrázek ke článku Hybridní inteligentní systémy 2

Hybridní inteligentní systémy 2

V technické praxi využíváme často kombinaci různých disciplín umělé inteligence a klasických výpočtů. Takovým systémům říkáme hybridní systémy. V tomto článku se zmíním o určitém typu hybridního systému, který je užitečný ve velmi složitých výrobních procesech.

Obrázek ke článku Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Vedení týmu v oboru informačních technologií se nijak zvlášť neliší od jiných oborů. Přesto však IT manažeři čelí výzvě v podobě velmi rychlého rozvoje a tím i rostoucími nároky na své lidi. Udržet pozornost, motivaci a efektivitu týmu vyžaduje opravdu pevné manažerské základy a zároveň otevřenost a flexibilitu pro stále nové výzvy.

Obrázek ke článku Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Za poslední rok se podoba práce zaměstnanců změnila k nepoznání. Především plošné zavedení home office, které mělo být zpočátku jen dočasným opatřením, je pro mnohé už více než rok každodenní realitou. Co ale dělat, když se při práci z domova ztrácí motivace, zaměstnanci přestávají komunikovat a dříve fungující tým se rozpadá na skupinu solitérů? Odborníci na personalistiku dali dohromady několik rad, jak udržet tým v chodu, i když pracovní podmínky nejsou ideální.

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý