Schaltfläche in Symbolleiste zur Laufzeit einfügen



  • Hallo,Forum! Jetzt stell ich mal wieder eine Frage zu folgendem Programm:

    #define STRICT
    #include <windows.h>
    #include <commctrl.h>
    #include "Symbolleiste_2.h"
    
    const int NumButtons = 3;
    HWND hToolBar;
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    const char szAppName[] = "Symbolleiste";
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
    	HWND hWnd;
       MSG  msg;
       HMENU hMenu;
       WNDCLASSEX wc;
    
       wc.cbSize			= sizeof(WNDCLASSEX);
       wc.style				= CS_HREDRAW|CS_VREDRAW;
       wc.lpfnWndProc		= WndProc;
       wc.cbClsExtra		= 0;
       wc.cbWndExtra		= 0;
       wc.hInstance		= hInstance;
       wc.hCursor			= LoadCursor(NULL, IDC_CROSS);
       wc.hIcon				= LoadIcon(NULL, IDI_APPLICATION);
       wc.hbrBackground	= (HBRUSH)(COLOR_INACTIVECAPTION);
       wc.lpszClassName	= szAppName;
       wc.lpszMenuName	= NULL;
       wc.hIconSm			= (HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ICON1),
       							IMAGE_ICON, 16, 16, 0);
    
       if (RegisterClassEx(&wc) == 0)
       	return 0;
       hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDM_MENU1));
       hWnd = CreateWindowEx(NULL,
       								szAppName,
                               szAppName,
                               WS_OVERLAPPEDWINDOW|WS_VISIBLE,
                               CW_USEDEFAULT,
                               CW_USEDEFAULT,
                               400,
                               400,
                               NULL,
                               hMenu,
                               hInstance,
                               NULL);
    
       InitCommonControls ();
       TBBUTTON ToolButton[3];
    
       ToolButton[0].iBitmap 	= 0;
       ToolButton[0].idCommand = IDM_TB_EXIT;
       ToolButton[0].fsState	= TBSTATE_ENABLED;
       ToolButton[0].fsStyle	= TBSTYLE_BUTTON;
       ToolButton[0].dwData		= 0;
       ToolButton[0].iString	= 0;
    
       ToolButton[1].iBitmap 	= 1;
       ToolButton[1].idCommand = IDM_TB_HIDESHOW;
       ToolButton[1].fsState	= TBSTATE_ENABLED;
       ToolButton[1].fsStyle	= TBSTYLE_CHECK;
       ToolButton[1].dwData		= 0;
       ToolButton[1].iString	= 0;
    
       ToolButton[2].iBitmap 	= IDB_BITMAP2;
       ToolButton[2].idCommand = IDM_TB_SHOW;
       ToolButton[2].fsState	= TBSTATE_ENABLED;
       ToolButton[2].fsStyle	= TBSTYLE_BUTTON;
       ToolButton[2].dwData		= 0;
       ToolButton[2].iString	= 0;
    
       void tb_add_button(HWND, int, char*, int style);//Muß diese Funktionsdefinition an eine andere Stelle?
    
       hToolBar = CreateToolbarEx(hWnd,
       									WS_VISIBLE|WS_CHILD,3,NumButtons,
                                  hInstance,IDB_BITMAP1,ToolButton, NumButtons, 16,16,16,16,
                                  sizeof(TBBUTTON));
    
       ShowWindow (hWnd, iCmdShow);	
       UpdateWindow (hWnd);				
    	while (GetMessage(&msg, NULL,0,0))	
       {
          TranslateMessage(&msg);	//Nachrichtenschleife
          DispatchMessage(&msg);
       }
    	return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    //WndProc bearbeitet alle Nachrichten, die für diese Fensterklasse bestimmt sind.
    {
       switch (message)
       {
          case WM_COMMAND:
          {
          	switch (LOWORD(wParam))
             {
    
              //Hier kommt noch ein Haufen Code, der auch funktioniert :+1: 
    
                case IDM_TB_SHOW:
                {
                	tb_add_button(hToolBar, 1, IDB_BITMAP2, TBSTYLE_CHECK);
                   break;
                }
    
             }
             break;
          }
    
       	case WM_DESTROY:
          {
          	PostQuitMessage (0);	//Beendung der Anwendung
             return 0;
          }
       }
       return DefWindowProc(hwnd, message, wParam, lParam); 	//DefaultWindowProcedure, Standardbearbeitung.
    
    }
    ////////////////////////////////////////////////////////////////////////////////////////
    
    void tb_add_button(HWND hToolBar, int command, char* bitmap, int style = TBSTYLE_BUTTON)
    {
    	HBITMAP h_Bitmap;
       h_Bitmap = LoadBitmap(NULL, MAKEINTRESOURCE(IDB_BITMAP2));
    
       TBADDBITMAP bitid;
       bitid.hInst = GetModuleHandle(NULL);
       bitid.nID = (UINT)h_Bitmap;
    
       TBBUTTON newbutton;
       newbutton.iBitmap = SendMessage(hToolBar, TB_ADDBITMAP, 1, (long)&bitid);
       newbutton.idCommand = command;
       newbutton.fsState = TBSTATE_ENABLED;
       newbutton.fsStyle = style;
       newbutton.dwData = 0;
       newbutton.iString = NULL;
       SendMessage(hToolBar, TB_ADDBUTTONS, (WPARAM)1, (LPARAM)(LPTBBUTTON)&newbutton);
    }
    

    Wie man sieht, versuche ich, eine Schaltfläche zur Laufzeit in eine Symbolleiste einzufügen, wenn IDM_TB_SHOW gedrückt wird (auch ein Knopf in der Symbolleiste). Dazu dient die Funktion "void tb_add_button".
    Das Problem: Wenn ich das Prog kompiliere, erhalte ich die Meldung "call to undefined function tb_add_button". Dabei ist die Funktion in WinMain definiert.
    Wenn ich sie vor WinMain global definiere, kommen andere Fehlermeldungen, unter anderem, weil InitCommonControls noch nicht ausgeführt wurde (die Parameter davon werden ja in der Funktion gebraucht) oder weil der dritte Parameter (char*) nicht convertiert werden kann.
    Vielleicht habe ich aber auch einen falschen Ansatz?
    Was muß ich da ändern?



  • Elektronix schrieb:

    void tb_add_button(HWND, int, char*, int style);//Muß diese Funktionsdefinition an eine andere Stelle?
    

    Das ist keine Funktionsdefinition, sondern eine Deklaration 😉 . Diese sind und müssen IMMER im globalen Scope lieben.

    Elektronix schrieb:

    Dabei ist die Funktion in WinMain definiert.

    Nö sie ist global definiert. Anders gehts auch nicht. 😉



  • CodeFinder schrieb:

    Diese sind und müssen IMMER im globalen Scope lieben.

    Lieben? Liegen? 🤡

    Ok, werde das mal ändern, mal schauen, was geht.



  • Ups 😃 ... 🤡



  • So, mein Code sieht jetzt so aus:

    #define STRICT
    #include <windows.h>
    #include <commctrl.h>
    #include "Symbolleiste_2.h"
    
    const int NumButtons = 3;
    HWND hToolBar;
    void tb_add_button(HWND, int, int, int style);
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    const char szAppName[] = "Symbolleiste";
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
    	HWND hWnd;
       MSG  msg;
       HMENU hMenu;
       WNDCLASSEX wc;
    
       wc.cbSize			= sizeof(WNDCLASSEX);
       wc.style				= CS_HREDRAW|CS_VREDRAW;
       wc.lpfnWndProc		= WndProc;
       wc.cbClsExtra		= 0;
       wc.cbWndExtra		= 0;
       wc.hInstance		= hInstance;
       wc.hCursor			= LoadCursor(NULL, IDC_CROSS);
       wc.hIcon				= LoadIcon(NULL, IDI_APPLICATION);
       wc.hbrBackground	= (HBRUSH)(COLOR_INACTIVECAPTION);
       wc.lpszClassName	= szAppName;
       wc.lpszMenuName	= NULL;
       wc.hIconSm			= (HICON)LoadImage(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_ICON1),
       							IMAGE_ICON, 16, 16, 0);
    
       if (RegisterClassEx(&wc) == 0)
       	return 0;
       hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDM_MENU1));
       hWnd = CreateWindowEx(NULL,
       								szAppName,
                               szAppName,
                               WS_OVERLAPPEDWINDOW|WS_VISIBLE,
                               CW_USEDEFAULT,
                               CW_USEDEFAULT,
                               400,
                               400,
                               NULL,
                               hMenu,
                               hInstance,
                               NULL);
    
       InitCommonControls ();
       TBBUTTON ToolButton[3];
    
       ToolButton[0].iBitmap 	= 0;
       ToolButton[0].idCommand = IDM_TB_EXIT;
       ToolButton[0].fsState	= TBSTATE_ENABLED;
       ToolButton[0].fsStyle	= TBSTYLE_BUTTON;
       ToolButton[0].dwData		= 0;
       ToolButton[0].iString	= 0;
    
       ToolButton[1].iBitmap 	= 1;
       ToolButton[1].idCommand = IDM_TB_HIDESHOW;
       ToolButton[1].fsState	= TBSTATE_ENABLED;
       ToolButton[1].fsStyle	= TBSTYLE_CHECK;
       ToolButton[1].dwData		= 0;
       ToolButton[1].iString	= 0;
    
       ToolButton[2].iBitmap 	= IDB_BITMAP2;
       ToolButton[2].idCommand = IDM_TB_SHOW;
       ToolButton[2].fsState	= TBSTATE_ENABLED;
       ToolButton[2].fsStyle	= TBSTYLE_BUTTON;
       ToolButton[2].dwData		= 0;
       ToolButton[2].iString	= 0;
    
       hToolBar = CreateToolbarEx(hWnd,
       									WS_VISIBLE|WS_CHILD,3,NumButtons,
                                  hInstance,IDB_BITMAP1,ToolButton, NumButtons, 16,16,16,16,
                                  sizeof(TBBUTTON));
    
       ShowWindow (hWnd, iCmdShow);	
       UpdateWindow (hWnd);					while (GetMessage(&msg, NULL,0,0))	
       {
    		TranslateMessage(&msg);	//Nachrichtenschleife
          DispatchMessage(&msg);
       }
    	return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    //WndProc bearbeitet alle Nachrichten, die für diese Fensterklasse bestimmt sind.
    {
    	switch (message)
       {
       	case WM_COMMAND:
          {
          	switch (LOWORD(wParam))
             {  //Dazwischen noch ein bischen Quelltext, tut hier nicht zur Sache
                case IDM_TB_SHOW:
                {
                	tb_add_button(hToolBar, 1, IDB_BITMAP2, TBSTYLE_BUTTON);//Einfügen des Buttons.
                   break;
                }
    
             }
             break;
          }
    
       	case WM_DESTROY:
          {
          	PostQuitMessage (0);	//Beendung der Anwendung
             return 0;
          }
       }
       return DefWindowProc(hwnd, message, wParam, lParam); 	//DefaultWindowProcedure, Standardbearbeitung.
    
    }
    ////////////////////////////////////////////////////////////////////////////////////////
    
    void tb_add_button(HWND hToolBar, int command, int bitmap, int style)
    {
    	HBITMAP h_Bitmap;
       h_Bitmap = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(bitmap));
       if (h_Bitmap==NULL)
       {
       	MessageBox(NULL, "kein Bitmap geladen", "Bitmapfehler", MB_ICONEXCLAMATION|MB_OK|MB_DEFBUTTON1);
       }
    
       TBADDBITMAP bitid;
       bitid.hInst = GetModuleHandle(NULL);
       bitid.nID = (UINT)h_Bitmap;
    
       TBBUTTON newbutton;
       newbutton.iBitmap = SendMessage(hToolBar, TB_ADDBITMAP, 1, (long)&bitid);
       newbutton.idCommand = command;
       newbutton.fsState = TBSTATE_ENABLED;
       newbutton.fsStyle = style;
       newbutton.dwData = 0;
       newbutton.iString = NULL;
       SendMessage(hToolBar, TB_ADDBUTTONS, (WPARAM)1, (LPARAM)(LPTBBUTTON)&newbutton);
    }
    

    Das Einfügen des Button funktioniert schonmal. Aber der Button ist nackt, hat keine Bitmap. Es wird aber auch kein Bitmap-Fehler angezeigt (siehe MessageBox).

    Wo steckt da noch ein Fehler?
    Bei der Gelegenheit wüßte ich auch gerne, wie man den Button wieder aus der Symbolleiste entfernt- und zwar nicht mur mit TBSTATE_HIDDEN versteckt, sondern zur Laufzeit richtig aus der Leiste löscht? Gibt es eine Funktion wie z. B. TB_DELETEBUTTON oder ähnliches?



  • Die letzte Frage hat sich erledigt. TB_DELETEBUTTON gibt es tatsächlich. 🙂

    Aber die andere Frage bleibt: Auf meiner neuen Schaltfläche erscheint kein Bitmap, obwohl ich eines angegeben habe. Ich bekomme auch keine Fehlermeldung (Quelltext siehe mein letztes Posting). Was mache ich falsch?



  • Was lange gährt, wird endlich Wut- oder so ähnlich. Ich habs selbst herausgefunden.

    Bei TBADDBITMAP muß hInst auf NULL gesetzt werden, weil ich die Bitmap aus einer Resource laden wollte. GetModuleHandle(NULL) funktioniert nur, wenn man das Bitmap aus einer Datei läd, oder, wenn man Standardsymbole benutzt. 🙂 🕶


Anmelden zum Antworten