tab control und linker



  • Du must natürlich nur die Attribute benutzen, die du brauchst:

    • dwState -> wird in TCM_INSERTITEM ingnoriert
    • dwStateMask -> ebenso
    • lpReserved1 -> wird nicht benutzt
    • lpReserved2 -> ebenso
    • cchTextMax -> wird nur genutzt wenn Informationen vom TC geholt werden
    • iImage -> für ein Bildchen (Optional) muss vorher mit dem Flag TCIF_IMAGE in mask gültig gemacht werden
    • lParam -> brauchen wir im Bsp. nicht, nimmt irgendeinen 4-Byte-Wert auf, z.B. Zeiger, ID, etc..., der für jede Reguisterkarte gespeichert wird

    [ Dieser Beitrag wurde am 03.06.2003 um 13:24 Uhr von D@niel $chumann editiert. ]



  • ich habe jetzt mal nur einen Reiter erstellt aber alles was man sieht ist ein großes graues steuerelement, ohne den angegebenen string, und sonst ist auch nix da....woran liegt das?!



  • Zeig mal deinen Code. Ich habe es eben sicherheitshalber mal so probiert und es ging:

    InitCommonControls();
            TCITEM tci;
            tci.mask=TCIF_TEXT;
            tci.pszText="Registerkarte 1";
            SendMessage(CreateWindowEx(NULL, WC_TABCONTROL, "", WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, 0, 0, 200, 200, hwnd, 0, ((LPCREATESTRUCT)lParam)->hInstance, NULL), TCM_INSERTITEM, 0, (LPARAM) (const LPTCITEM) &tci);
    


  • HWND CreateTabControl(HINSTANCE hInstance)
    {
        /*get the client window*/
        RECT rect;
        TCITEM tc;
        memset (&tc, 0, sizeof (TCITEM));
    
        GetClientRect (hWindow, &rect);
    
        /*make a new instance of a common dialog initialsation structure*/
        INITCOMMONCONTROLSEX cc;
        memset (&cc, 0 , sizeof (INITCOMMONCONTROLSEX));
    
        cc.dwSize = sizeof (INITCOMMONCONTROLSEX);
        cc.dwICC = ICC_TAB_CLASSES | ICC_WIN95_CLASSES;
    
        /*ensure that the common dialog dll is loaded*/
        InitCommonControlsEx (&cc);
    
        /*create Child window*/
        hTc = CreateWindowEx (NULL,
                              WC_TABCONTROL,
                              "",
                              WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
                              10, 300, 
                              100, 100, 
                              hWindow, 
                              NULL, 
                              hGlobInstance, 
                              NULL);
    
        if (hTc == NULL)
        {
            MessageBox (hWindow, "Kann Reiter nicht erstellen", "Abacus Calculator V.1.0", MB_OK | MB_ICONINFORMATION);
            return 0;
        }
    
        else
        {
            tc.mask=TCIF_TEXT;
            tc.pszText = "Allgemein";
    
            int z = SendMessage (hWindow, TCM_INSERTITEM, 0, (LPARAM) (TCITEM*) &tc);
    
            tc.pszText ="wissenschaftlich";
            int x = SendMessage (hWindow, TCM_INSERTITEM, 1, (LPARAM) (TCITEM*) &tc);
    
            return hTc;
        }
    
    }
    
    obwohl eine sache macht mich stutzig: normalerweise kommt ja die fensterklasse in "" also "BUTTON" oder "EDIT" oder "LISTBOX".... wenn ich WS_TABCONTROL in "" setze klappt gar nix mehr...
    


  • Das mit dem Klassenname ist schon richtig. In der Headerdatei CommCtrl.h steht volgendes:

    #define WC_TABCONTROL          "SysTabControl32"
    

    es wird dort also vom Preprozessor ein String eingefügt.

    Aber die beiden Nachrichten:

    int z = SendMessage (hWindow, TCM_INSERTITEM, 0, (LPARAM) (TCITEM*) &tc);
    
            tc.pszText ="wissenschaftlich";
            int x = SendMessage (hWindow, TCM_INSERTITEM, 1, (LPARAM) (TCITEM*) &tc);
    

    schickst du an das falsche Fenster. Du darfst sie nicht dem Elternfenster schcken, das kann damit nichts anfangen. Die Nachrichten mit den entsprechenden Parametern versteht nur das Steuerelement. Ersetz in den beiden Zeilen einfach hWindow durch hTc und es wird funktionieren.

    [ Dieser Beitrag wurde am 03.06.2003 um 23:17 Uhr von D@niel $chumann editiert. ]



  • cool das funktioniert jetzt ja wirklich... wie kann ich denn nun die Steuerelemente in die Registerkarten eintragen? also mit dem hwnd geht das ja net hat ja nicht jede karte nen eigenes hwnd was man als elternfenster angeben könnte. wie wird das denn gemanged?



  • Jetzt erstellst du ein paar Dialoge. Für jede Registerkarte einen. Den Dialogen gibst du keinen Rand und machst sie Untergeordnet (rechte Maustaste auf den Dialog->Eigenschaften->Formate->Stil = "Untergeordnet" und ->Rand = "Kein").
    Ich hoffe du hast VC++ und hast schon mal mit Dialogen bzw. dem Resourceneditor gearbeitet.
    Immer wenn jetzt eine Registerkarte gewechselt wird (du bekommst eine Benachrichtung, siehe MSDN) musst du den entsprechenden Dialog anzeigen und den alten verstecken. Du kannst entweder beim Start alle Dialoge vorladen oder lädst ihn erst wenn er auch gebraucht wird und hältst ihn dann im Speicher, falls er nochmal gebraucht wird, oder wie auch immer. Als Parent bekommen die Dialoge das TC.

    Du musst das natürlich nicht über Dialoge machen, ist aber wohl am einfachsten bzw. am wenigsten umständlich ;).



  • ja ich habe vc++ , das heisst ich kann die Dialoge im Resourceneditor erstellen. Damit kenne ich mich auch ganz gut aus. Aber ich muss doch sicher dann irgendwo die Dialoge zuordnen oder? oder geht das wieder über Messages?!



  • Ich hab das mal so gelöst:

    //innerhalb der WndProc des Elternfensters (in diesem Fall ein Dialog)
    INT_PTR CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
        static HWND dialog[4];
        static unsigned char visible=0;
        static bool autoanswer=false;
    
        switch(message){
        case WM_INITDIALOG:
            dialog[0]=0;
            dialog[1]=0;
            dialog[2]=0;
            dialog[3]=0;
    //------------ Code --------------
            NMHDR nmhdr;
            nmhdr.code=TCN_SELCHANGE;
            nmhdr.hwndFrom=0;
            nmhdr.idFrom=0;
            SendMessage(hwnd, WM_NOTIFY, 0, (long)&nmhdr);
        return 1;
    
    //------------ Code --------------
    
        case WM_NOTIFY:
            switch(LPNMHDR(lParam)->code){
            case TCN_SELCHANGE:
                DWORD dwSelected;
    
                dwSelected=SendDlgItemMessage(hwnd,IDC_TAB1,TCM_GETCURSEL,0,0);
                if(dwSelected==-1)break;
                if(dialog[visible])ShowWindow(dialog[visible], SW_HIDE);
                if(!dialog[dwSelected]){
                    switch(dwSelected){
                    case 0:
                        dialog[0]=CreateDialogParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DIALOG1), hwnd, DialogProc1, 0);
                        break;
                    case 1:
                        dialog[1]=CreateDialogParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DIALOG2), hwnd, DialogProc2, 0);
                        break;
                    case 2:
                        dialog[2]=CreateDialogParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DIALOG3), hwnd, DialogProc3, 0);
                        break;
                    case 3:
                        dialog[3]=CreateDialogParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DIALOG4), hwnd, DialogProc4, 0);
                        break;
                    }
                    RECT r, r2;
                    GetWindowRect(GetDlgItem(hwnd, IDC_TAB1), &r);
                    GetWindowRect(hwnd, &r2);
                    r2.bottom=r.bottom-r2.bottom;
                    r2.left=r.left-r2.left;
                    r2.right=r.right-r2.right;
                    r2.top=r.top-r2.top;
                    GetWindowRect(dialog[dwSelected], &r);
                    MoveWindow(dialog[dwSelected], r2.left, r2.top, r.right-r.left, r.bottom-r.top, true);
                }
                visible=dwSelected;
                ShowWindow(dialog[visible], SW_SHOW);
                break;
            }
        return 1;
    
    //------------ Code --------------
    //...
    

    Ich hoffe ich hab keinen wichtigen Code rausgenommen. Müsste aber so funktionieren. Ist übrigens für 4 Registerkarten. In der Resourcendatei sind die 4 Dialoge definiert (IDD_DIALOG1 ... IDD_DIALOG4). Natürlich brauchst du auch noch für jeden Dialog eine WndProc.



  • Auf diese Art erzeugst Du jedesmal einen neuen Dialog, wenn eine neue Seite gewählt wird. Dann wird es irgendwann von Dialogen nur so wimmeln. 🙂

    Ich würde die Dialoge vielmehr alle auf einen Schlag erzeugen, z.B. in WM_CREATE. Jetzt kannst Du auf TCN_SELCHANGE warten, um den zur Seite gehörenden Dialog per ShowWindow sichtbar zu machen. Dann sollte aber zusätzlich auch TCN_SELCHANGING abgefangen werden (wird gesendet, bevor die Auswahl geändert wird), um hier den zurzeit sichtbaren Dialog zu verstecken.

    [edit] Und jetzt sehe ich auch die if-Abfrage vor dem switch. Ich glaub, ich gehe besser wieder ins Bett ... [/edit]

    [ Dieser Beitrag wurde am 04.06.2003 um 14:20 Uhr von -King- editiert. ]


Anmelden zum Antworten