Ownerdrawn controls



  • Hallo leute,
    ich hab mal ein paar grundlegende fragen zu ownerdrawn controls.
    1.was sind überhaupt ownerdrawn controls?
    2.welche möglichkeiten habe ich bei ownerdrawn controls?
    3.hat jemand vielleicht mal ein kleines Beispiel oder eine gute adresse, damit ich mir das mal vor augen halten kann?

    Thx && cya



  • Ein OWNERDRAWN control ist beispielsweise ein grafischer Button. Du malst bunte Bildchen, die Du angeben kannst und der PC behandelt das wie einen Button.

    Eine einfache Möglichkeit ist, ein Childfenster zu definieren und darin dann ein Eventhandling zu implementieren das beispielsweise auf tastaturbefehle, Mousebewegung und was man sonst noch so braucht, reagiert..

    cYa
    DjR



  • Anhang: erst gestern hab ich einen einfachen Button - mit riesiger Hilfe von jemand aus nem Board - zusammengeschraubt. wenn ich wieder zuhause bin, schick ich Dir mal meinen Code..



  • ok, kannste den posten?



  • Ich kenn eine sehr gute Seite, auf der erklärt wird wie man ownerdraw technik implementiert.

    Die Seite ist die WinAPI-FAQ. 😃



  • hier mein code (hat etwas gedauert)

    Zuallererst mal die Keklaration der Klasse:

    /* ************************************************************************** *
     *   MyButton.h                                                               *
     *   MyButton  -  Buttonklasse Deklaration                                    *
     *   (c) 2002 by DocJunioR                                                    *
     *   erstellt: 31.10.2002    v 0.1                                            *
     * ************************************************************************** *
     *   Änderungen :    Datum   *   Änderung                                     *
     *                           *                                                *
     * ************************************************************************** */
     #include <windows.h>
     #include <commctrl.h>
     #include <winuser.h>
    
    /* *****  MyButtonMessages  ************************************************* */
     #define  MBM_NORMAL                 0
     #define  MBM_CLICKED                1
     #define  MBM_DEACTIVATED            2
     #define  MBM_HOVER                  4
    
     class C_MyButton
     {
    /* *****  Variablen  ******************************************************** */
      private: 
         int Status;
         int PosX, PosY;
         WNDCLASS wincl;
         MSG msg;
         HWND parentwnd;
         BITMAP  B_Normal, B_Active, B_Deacti, B_Hover;
         HBITMAP H_Normal, H_Active, H_Deacti, H_Hover;
         HDC hdc, hdcMem;
         UINT smsg;
    
    /* *****  Funtionen  ******************************************************** */     
      public:
         HWND hwnd;
         static LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, 
                                           WPARAM wParam, LPARAM lParam);
    
          C_MyButton (HWND hWndP, HINSTANCE hInstance, 
                      int x, int y, 
                      LPSTR Norm, LPSTR Dis, LPSTR Toggl, 
                      LPSTR Hov, UINT BMsg);
    
         ~C_MyButton();
    
     };
    

    dann kommen die Methoden.
    Achtung: ich hab HD hier außerhalb der Klasse, was Arg unsauber ist!!
    Hab damit nur was getestet. man sollte es als Static in die ChildProc aufnehmen!

    /* ************************************************************************** *
     *   MyButton.cpp                                                             *
     *   MyButton  -  Buttonklasse Methoden                                       *
     *   (c) 2002 by DocJunioR                                                    *
     *   erstellt: 31.10.2002    v 0.1                                            *
     * ************************************************************************** *
     *   Änderungen :    Datum   *   Änderung                                     *
     *                           *                                                *
     * ************************************************************************** */
     #include "c_mybutton.h"
    
     int HD = 0;
    
     C_MyButton::C_MyButton (HWND hWndP, HINSTANCE hInstance, 
                             int x, int y, 
                             LPSTR Norm, LPSTR Dis, LPSTR Toggl, 
                             LPSTR Hov, UINT BMsg)
     {
        PosX = x, PosY = y; 
        Status = MBM_NORMAL;
        smsg = BMsg;
        parentwnd = hWndP;
    
    /* *****  Fensterklasse initialisieren  ************************************* */
    
        wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
        wincl.cbWndExtra = 0;                      /* structure or the window instance */
        wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
        wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
        wincl.hIcon  = NULL;
        wincl.hInstance = hInstance;
        wincl.lpfnWndProc = ChildProc;      /* This function is called by windows */
        wincl.lpszClassName = "MyButton";
        wincl.lpszMenuName = NULL;                 /* No menu */
        wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    
        RegisterClass(&wincl);
    
    /* *****  Bilder laden  ***************************************************** */
       H_Normal =  (HBITMAP) LoadImage(hInstance, Norm, IMAGE_BITMAP, 0 , 0,
                            LR_DEFAULTSIZE | LR_LOADFROMFILE | LR_CREATEDIBSECTION);
       H_Active =  (HBITMAP) LoadImage(hInstance, Toggl, IMAGE_BITMAP, 0 , 0,
                            LR_DEFAULTSIZE | LR_LOADFROMFILE | LR_CREATEDIBSECTION);
       H_Deacti =  (HBITMAP) LoadImage(hInstance, Dis, IMAGE_BITMAP, 0 , 0,
                            LR_DEFAULTSIZE | LR_LOADFROMFILE | LR_CREATEDIBSECTION);
       H_Hover  =  (HBITMAP) LoadImage(hInstance, Hov, IMAGE_BITMAP, 0 , 0,
                            LR_DEFAULTSIZE | LR_LOADFROMFILE | LR_CREATEDIBSECTION);
    
       GetObject (H_Normal, sizeof(BITMAP), &B_Normal);
       GetObject (H_Active, sizeof(BITMAP), &B_Active);
       GetObject (H_Deacti, sizeof(BITMAP), &B_Deacti);
       GetObject (H_Hover, sizeof(BITMAP), &B_Hover);
    
       hwnd = CreateWindow("MyButton", "\0", WS_CHILD|WS_VISIBLE, PosX, PosY,
                        B_Normal.bmWidth, B_Normal.bmHeight,
                        hWndP, NULL, (HINSTANCE) GetWindowLong (hWndP, GWL_HINSTANCE),
                        NULL);
       SetWindowLong(hwnd, GWL_USERDATA, (long) this);
    
    }
    
    C_MyButton::~C_MyButton()
    {
    
         DeleteObject(H_Normal);
         DeleteObject(H_Active);
         DeleteObject(H_Deacti);
         DeleteObject(H_Hover);
    }
    
    LRESULT CALLBACK C_MyButton::ChildProc(HWND hWnd, UINT message, 
                                           WPARAM wParam, LPARAM lParam)
    {
       // Weil reine Zuweisung in static nicht geht
      C_MyButton *Bt = (C_MyButton*) GetWindowLong(hWnd, GWL_USERDATA);
    
      PAINTSTRUCT ps;
    
      TRACKMOUSEEVENT tme;  // Mausbewegung verfolgen
    
      switch (message)
      {
         case WM_LBUTTONDOWN:
              if (!(Bt->Status & MBM_CLICKED)) Bt->Status = MBM_CLICKED;
              InvalidateRect(Bt->hwnd, NULL, FALSE);
              return 0;
         case WM_LBUTTONUP:
              // Message an Fenster senden um zu reagieren
              SendMessage(Bt->parentwnd, Bt->smsg, Bt->Status & MBM_DEACTIVATED, lParam);
    
                Bt->Status = MBM_NORMAL;
                HD = 0;
                InvalidateRect(Bt->hwnd, NULL, FALSE);
              return 0;                
         case WM_MOUSEMOVE:
              if (HD == 0)
              {
                HD = 1;
                Bt->Status += MBM_HOVER;        // OnMouseOver 
              }   
              // Melden, wenn Button verlassen wurde 
                tme.hwndTrack=Bt->hwnd;
                tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_LEAVE;
                TrackMouseEvent(&tme);
                InvalidateRect(Bt->hwnd, NULL, FALSE);
              return 0;
         case WM_MOUSELEAVE:
              Bt->Status -= MBM_HOVER;             // OnMouseOut
              HD = 0;
              InvalidateRect(Bt->hwnd, NULL, FALSE);
              return 0;
         case WM_SIZE:
              return 0;
         case WM_PAINT:
              Bt->hdc = BeginPaint(hWnd, &ps);
              Bt->hdcMem = CreateCompatibleDC(Bt->hdc);
    
              if (Bt->Status == MBM_DEACTIVATED)
                  SelectObject (Bt->hdcMem, Bt->H_Deacti);
              else if (Bt->Status == MBM_HOVER)
                  SelectObject (Bt->hdcMem, Bt->H_Hover);
              else if (Bt->Status == (MBM_CLICKED) || Bt->Status == (MBM_CLICKED + MBM_HOVER))
                  SelectObject (Bt->hdcMem, Bt->H_Active);
              else 
                  SelectObject (Bt->hdcMem, Bt->H_Normal);
    
                  BitBlt(   Bt->hdc, 0, 0, Bt->B_Normal.bmWidth, 
                            Bt->B_Normal.bmHeight, Bt->hdcMem, 0, 0, SRCCOPY);
    
                  DeleteDC (Bt->hdcMem);
                  EndPaint(hWnd, &ps);    
              return 0;
         case WM_DESTROY:
              PostQuitMessage(0);
              return 0;     
      }
    
     return DefWindowProc (hWnd, message, wParam, lParam);
    }
    

    und zuguter Letzt nun noch die Testfunktion.

    /* ************************************************************************** *
     *   TestButton.cpp                                                           *
     *   MyButton  -  Buttonklasse Testfenster                                    *
     *   (c) 2002 by DocJunioR                                                    *
     *   erstellt: 31.10.2002    v 0.1                                            *
     * ************************************************************************** *
     *   Änderungen :    Datum   *   Änderung                                     *
     *                           *                                                *
     * ************************************************************************** */
    #include <windows.h>
    #include "c_mybutton.h"
    
    #define WM_BUTTON1 (WM_USER + 1)
    #define WM_BUTTON2 (WM_USER + 2)
    
    /*  Declare Windows procedure  */
    LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
    
    /*  Make the class name into a global variable  */
    char szClassName[ ] = "WindowsApp";
    
    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 */
        C_MyButton *B1, *B2;
    
        /* 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);
        B1 = new C_MyButton(hwnd, hThisInstance, 30, 30,  
                          "gfx/TN.bmp","gfx/TDis.bmp","gfx/TTog.bmp","gfx/THov.bmp",
                          WM_BUTTON1);    
        B2 = new C_MyButton(hwnd, hThisInstance, 30, 90,  
                          "gfx/TN.bmp","gfx/TDis.bmp","gfx/TTog.bmp","gfx/THov.bmp",
                          WM_BUTTON2);    
    
        /* 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_DESTROY:
                PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
                break;
            case (WM_BUTTON1):
    //            MessageBox(NULL,"No 1", "erster", MB_OK);
                break;     
            case (WM_BUTTON2):
    //            MessageBox(NULL,"No 2", "zweiter", MB_OK);
                break;     
            default:                      /* for messages that we don't deal with */
                return DefWindowProc (hwnd, message, wParam, lParam);
        }
    
        return 0;
    }
    

    Die Buttons sind bmps beliebiger Größe. Allerdings müssen sie schon alle die gleiche Größe haben. Ansonsten wird sich an der größe des normalen Button orientiert.
    das Deaktivieren von Buttons ist noch nicht drin, ist aber eigentlich kein Problem. Wie gesagt, ich hab erst vorgestern damit begonnen..

    cYa
    DjR


Anmelden zum Antworten