Announcement

Collapse
No announcement yet.

couldn't display icon in tooltips

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • couldn't display icon in tooltips

    Hi all

    I had modified Borje's code from https://forum.powerbasic.com/forum/u...173#post794173

    by adding the icon named "Canada.ico" ( this icon is available in the samples file named treeview.bas )
    but unable to display the icon in the tooltips

    The modified program is as below

    Code:
    ' Thanks to Borje
       ' with accelerator keys  and tooltips with icon
    
    #COMPILE EXE
    #INCLUDE "win32api.inc"
    #INCLUDE "CommCtrl.Inc"
    
    %BUTTON1  = 500 : %BUTTON2  = 501
    %BUTTON3  = 503 : %BUTTON4  = 504
    %TAB1 = 550
    
    %IDM_F10 = %WM_USER + 610
    %IDM_F11 = %WM_USER + 611
    %IDM_F12 = %WM_USER + 612
    
    GLOBAL hWnd_ToolTip AS LONG
    
    GLOBAL hTab1, hTab2 AS LONG
    
    
    #RESOURCE ICON,   1100, "canada.ico"
    
    
    '============================================
    FUNCTION PBMAIN
      LOCAL hDlg AS DWORD
    
      DIALOG NEW 0, "Tooltips and Accel test", , , 170, 200, %WS_CAPTION , 0 TO hDlg
    
      CONTROL ADD TAB, hDlg, %TAB1, "",0,0,170,90, , , 'CALL PBCallback()
      TAB INSERT PAGE hDlg, %TAB1, 1, 0, "Tab Page 1" CALL TabProc TO hTab1
        CONTROL ADD BUTTON, hTab1, %BUTTON3, "Button #3", 50, 30, 50, 14
      TAB INSERT PAGE hDlg, %TAB1, 2, 0, "Tab Page 2" CALL TabProc TO hTab2
        CONTROL ADD BUTTON, hTab2, %BUTTON4, "Button #4", 50, 30, 50, 14
    
      '------------------------------------------------------------------
      CONTROL ADD BUTTON, hDlg,  %BUTTON1,  "&Close", 55, 120, 60, 25
      CONTROL ADD BUTTON, hDlg,  %BUTTON2,  "Button #2", 55, 155, 60, 25
      DIALOG SET COLOR hDlg, -1, %RGB_LEMONCHIFFON
    
      DIM ac(2) AS ACCELAPI, hAccel AS DWORD
      ac(0).fvirt = %FVIRTKEY : ac(0).key = %VK_F10 : ac(0).cmd = %IDM_F10
      ac(1).fvirt = %FVIRTKEY : ac(1).key = %VK_F11 : ac(1).cmd = %IDM_F11
      ac(2).fvirt = %FVIRTKEY : ac(2).key = %VK_F12 : ac(2).cmd = %IDM_F12
      ACCEL ATTACH hDlg, ac() TO hAccel
    
      '------------------------------------------------------------------
      DIALOG SHOW MODAL hDlg, CALL DLGPROC  ' <- Modal or Modeless works like expected
    
    '  DIALOG SHOW MODELESS hDlg, CALL DLGPROC  ' <- also works with message loop below
    '  DO
    '      DIALOG DOEVENTS
    '  LOOP WHILE ISWIN(hDlg)
    
    
    END FUNCTION
    
    '==================================================================================================
    ' Callback
    '==================================================================================================
    CALLBACK FUNCTION DLGPROC
      SELECT CASE CBMSG
        CASE %WM_INITDIALOG
            SetToolTip CBHNDL, %BUTTON2, "This is button #2"
            SetToolTip CBHNDL, %BUTTON1, "Click this to close the window"
            SetToolTip hTab1,  %BUTTON3, "Tab Control Button3, Page 1"
            SetToolTip hTab2,  %BUTTON4, "Tab Control Button4, Page 2"
    
        CASE %WM_COMMAND
          SELECT CASE CBCTL
          ' accelerator keys
          CASE %IDM_F10
               IF CBCTLMSG = 1 THEN
                    ? "%IDM_F10"
               END IF
          CASE %IDM_F11
               IF CBCTLMSG = 1 THEN
                    ? "%IDM_F11"
               END IF
    
          CASE %IDM_F12
               IF CBCTLMSG = 1 THEN
                   ? "%IDM_F12"
                END IF
    
          CASE %BUTTON1
               IF CBCTLMSG = %BN_CLICKED THEN
                   DIALOG END CBHNDL
               END IF
    
           END SELECT
     END SELECT
    END FUNCTION
    
    '==================================================================================================
    ' SetToolTip
    ' with information icon
    ' Note that icon styles are as follows
    ' https://docs.microsoft.com/en-us/windows/win32/controls/ttm-settitle
     '    %TTI_NONE      No icon.
    '     %TTI_INFO      Info icon.
    '     %TTI_WARNING       Warning icon
    '     %TTI_ERROR         Error Icon
    '     %TTI_INFO_LARGE    Large info Icon
    '     %TTI_WARNING_LARGE Large error Icon
    '     %TTI_ERROR_LARGE     Large error Icon
    
    FUNCTION SetToolTip(BYVAL hDlg AS LONG, BYVAL CtlID AS LONG, BYVAL sText AS STRING) AS LONG
      STATIC TI AS TOOLINFO
      LOCAL iStyle AS LONG
      LOCAL sTitle AS STRING
      IF IsWindow(hWnd_ToolTip) = 0 THEN
        iStyle = %TTS_ALWAYSTIP OR %TTS_BALLOON
        hWnd_ToolTip = CreateWindowEx( 0, "tooltips_class32", "", iStyle, 0, 0, 0, 0, _
                                 hDlg, BYVAL 0&, GetModuleHandle(BYVAL 0&), BYVAL 0&)
        SetWindowTheme(hWnd_ToolTip, " ", " ")                        '
        DIALOG SEND hWnd_ToolTip, %TTM_SETMAXTIPWIDTH, 0, 300
        DIALOG SEND hWnd_ToolTip, %TTM_SETDELAYTIME, %TTDT_AUTOPOP, 10000
        DIALOG SEND hWnd_ToolTip, %TTM_SETDELAYTIME, %TTDT_INITIAL, 500
        DIALOG SEND hWnd_ToolTip, %TTM_SETDELAYTIME, %TTDT_RESHOW, 1
        DIALOG SEND hWnd_ToolTip, %TTM_SETTIPBKCOLOR, %RGB_AZURE,0
    
        sTitle = "Information"  ' or whatever..
       ' DIALOG SEND hWnd_ToolTip, %TTM_SETTITLE,  %TTI_WARNING  , STRPTR(sTitle)
        DIALOG SEND hWnd_ToolTip, %TTM_SETTITLE,  1100  , STRPTR(sTitle)
      END IF
    
    
      IF hWnd_ToolTip THEN
        TI.cbSize = SIZEOF(TI)
        TI.uFlags = %TTF_SUBCLASS OR %TTF_IDISHWND
        TI.hWnd = hDlg
        IF CtlID = 0 THEN
          TI.uId = hDlg
        ELSE
          TI.uId = GetDlgItem(hDlg, CtlID)
        END IF
        IF SendMessage(hWnd_ToolTip, %TTM_GETTOOLINFO, 0, BYVAL VARPTR(TI)) THEN
          CALL SendMessage(hWnd_ToolTip, %TTM_DELTOOL, 0, BYVAL VARPTR(TI))
        END IF
        sText = sText + CHR$(0)
        TI.lpszText = STRPTR(sText)
        FUNCTION = SendMessage(hWnd_ToolTip, %TTM_ADDTOOL, 0, BYVAL VARPTR(TI))
      END IF
    END FUNCTION
    
    '====================================================================
    ' Tab Control Callback
    '====================================================================
    CALLBACK FUNCTION TabProc
    
      SELECT CASE AS LONG CB.MSG
      CASE %WM_COMMAND
          SELECT CASE AS LONG CBCTL
          CASE %BUTTON3  ' on page 1
              IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                  ? "Tab Button3, Page1 Clicked"
              END IF
          CASE %BUTTON4  ' on page 2
              IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                  ? "Tab Button4, Page2 Clicked"
              END IF
          END SELECT
      END SELECT
    
    END FUNCTION

  • #2
    The added code lines are :

    Code:
    #RESOURCE ICON,   1100, "canada.ico"
    
    DIALOG SEND hWnd_ToolTip, %TTM_SETTITLE,  1100  , STRPTR(sTitle)
    All I need was to add an icon (canada.ico) from the resource and then to display this icon in the tooltips

    Comment


    • #3
      A handle and a resource ID are not the same thing.

      Use LoadImage() first to get a handle to the icon for use in DIALOG SEND

      Comment


      • #4
        Thanks Stuart, but still can't get the icon showing in the tooltip despite using LoadImageW() in the FUNCTION SetToolTip

        Code:
        ' Tooltips Accel.bas
        ' https://forum.powerbasic.com/forum/user-to-user-discussions/programming/794061-tooltips-not-showing?p=794173#post794173
        
           ' with accelerator keys  and tooltips with icon
        
        #COMPILE EXE
        #INCLUDE "win32api.inc"
        #INCLUDE "CommCtrl.Inc"
        
        %BUTTON1  = 500 : %BUTTON2  = 501
        %BUTTON3  = 503 : %BUTTON4  = 504
        %TAB1 = 550
        
        %IDM_F10 = %WM_USER + 610
        %IDM_F11 = %WM_USER + 611
        %IDM_F12 = %WM_USER + 612
        
        GLOBAL hWnd_ToolTip AS LONG
        
        GLOBAL hTab1, hTab2 AS LONG
        
        
        #RESOURCE ICON,   1100, "canada.ico"
        
        
        '============================================
        FUNCTION PBMAIN
          LOCAL hDlg AS DWORD
        
          DIALOG NEW 0, "Tooltips and Accel test", , , 170, 200, %WS_CAPTION , 0 TO hDlg
        
          CONTROL ADD TAB, hDlg, %TAB1, "",0,0,170,90, , , 'CALL PBCallback()
          TAB INSERT PAGE hDlg, %TAB1, 1, 0, "Tab Page 1" CALL TabProc TO hTab1
            CONTROL ADD BUTTON, hTab1, %BUTTON3, "Button #3", 50, 30, 50, 14
          TAB INSERT PAGE hDlg, %TAB1, 2, 0, "Tab Page 2" CALL TabProc TO hTab2
            CONTROL ADD BUTTON, hTab2, %BUTTON4, "Button #4", 50, 30, 50, 14
        
          '------------------------------------------------------------------
          CONTROL ADD BUTTON, hDlg,  %BUTTON1,  "&Close", 55, 120, 60, 25
          CONTROL ADD BUTTON, hDlg,  %BUTTON2,  "Button #2", 55, 155, 60, 25
          DIALOG SET COLOR hDlg, -1, %RGB_LEMONCHIFFON
        
          DIM ac(2) AS ACCELAPI, hAccel AS DWORD
          ac(0).fvirt = %FVIRTKEY : ac(0).key = %VK_F10 : ac(0).cmd = %IDM_F10
          ac(1).fvirt = %FVIRTKEY : ac(1).key = %VK_F11 : ac(1).cmd = %IDM_F11
          ac(2).fvirt = %FVIRTKEY : ac(2).key = %VK_F12 : ac(2).cmd = %IDM_F12
          ACCEL ATTACH hDlg, ac() TO hAccel
        
          '------------------------------------------------------------------
          DIALOG SHOW MODAL hDlg, CALL DLGPROC  ' <- Modal or Modeless works like expected
        
        '  DIALOG SHOW MODELESS hDlg, CALL DLGPROC  ' <- also works with message loop below
        '  DO
        '      DIALOG DOEVENTS
        '  LOOP WHILE ISWIN(hDlg)
        
        
        END FUNCTION
        
        '==================================================================================================
        ' Callback
        '==================================================================================================
        CALLBACK FUNCTION DLGPROC
          SELECT CASE CBMSG
            CASE %WM_INITDIALOG
                SetToolTip CBHNDL, %BUTTON2, "This is button #2"
                SetToolTip CBHNDL, %BUTTON1, "Click this to close the window"
                SetToolTip hTab1,  %BUTTON3, "Tab Control Button3, Page 1"
                SetToolTip hTab2,  %BUTTON4, "Tab Control Button4, Page 2"
        
            CASE %WM_COMMAND
              SELECT CASE CBCTL
              ' accelerator keys
              CASE %IDM_F10
                   IF CBCTLMSG = 1 THEN
                        ? "%IDM_F10"
                   END IF
              CASE %IDM_F11
                   IF CBCTLMSG = 1 THEN
                        ? "%IDM_F11"
                   END IF
        
              CASE %IDM_F12
                   IF CBCTLMSG = 1 THEN
                       ? "%IDM_F12"
                    END IF
        
              CASE %BUTTON1
                   IF CBCTLMSG = %BN_CLICKED THEN
                       DIALOG END CBHNDL
                   END IF
        
               END SELECT
         END SELECT
        END FUNCTION
        
        '==================================================================================================
        ' SetToolTip
        ' with information icon
        ' Note that icon styles are as follows
        ' https://docs.microsoft.com/en-us/windows/win32/controls/ttm-settitle
         '    %TTI_NONE      No icon.
        '     %TTI_INFO      Info icon.
        '     %TTI_WARNING       Warning icon
        '     %TTI_ERROR         Error Icon
        '     %TTI_INFO_LARGE    Large info Icon
        '     %TTI_WARNING_LARGE Large error Icon
        '     %TTI_ERROR_LARGE     Large error Icon
        
        FUNCTION SetToolTip(BYVAL hDlg AS LONG, BYVAL CtlID AS LONG, BYVAL sText AS STRING) AS LONG
          STATIC TI AS TOOLINFO
          LOCAL iStyle AS LONG
          LOCAL sTitle AS STRING
          IF IsWindow(hWnd_ToolTip) = 0 THEN
            iStyle = %TTS_ALWAYSTIP OR %TTS_BALLOON
            hWnd_ToolTip = CreateWindowEx( 0, "tooltips_class32", "", iStyle, 0, 0, 0, 0, _
                                     hDlg, BYVAL 0&, GetModuleHandle(BYVAL 0&), BYVAL 0&)
            SetWindowTheme(hWnd_ToolTip, " ", " ")                        '
            DIALOG SEND hWnd_ToolTip, %TTM_SETMAXTIPWIDTH, 0, 300
            DIALOG SEND hWnd_ToolTip, %TTM_SETDELAYTIME, %TTDT_AUTOPOP, 10000
            DIALOG SEND hWnd_ToolTip, %TTM_SETDELAYTIME, %TTDT_INITIAL, 500
            DIALOG SEND hWnd_ToolTip, %TTM_SETDELAYTIME, %TTDT_RESHOW, 1
            DIALOG SEND hWnd_ToolTip, %TTM_SETTIPBKCOLOR, %RGB_AZURE,0
           '  https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadimagew
             sTitle = "Information"  ' or whatever..
           ' DIALOG SEND hWnd_ToolTip, %TTM_SETTITLE,  %TTI_WARNING  , STRPTR(sTitle)
            LOCAL hIcon, hInst AS DWORD
            LOCAL resFile AS LONG
            resfile = 1100
            ' need program instance handle for resource
            hInst = GetWindowLong(hWnd_ToolTip, %GWL_HINSTANCE)
            hIcon = LoadImageW(hInst, BYVAL resFile, %IMAGE_ICON, 0, 0, %LR_DEFAULTSIZE)
            DIALOG SEND hWnd_ToolTip, %TTM_SETTITLE,  hIcon  , STRPTR(sTitle)
          END IF
        
        
          IF hWnd_ToolTip THEN
        
        
        
            TI.cbSize = SIZEOF(TI)
            TI.uFlags = %TTF_SUBCLASS OR %TTF_IDISHWND
            TI.hWnd = hDlg
            IF CtlID = 0 THEN
              TI.uId = hDlg
            ELSE
              TI.uId = GetDlgItem(hDlg, CtlID)
            END IF
            IF SendMessage(hWnd_ToolTip, %TTM_GETTOOLINFO, 0, BYVAL VARPTR(TI)) THEN
              CALL SendMessage(hWnd_ToolTip, %TTM_DELTOOL, 0, BYVAL VARPTR(TI))
            END IF
            sText = sText + CHR$(0)
            TI.lpszText = STRPTR(sText)
            FUNCTION = SendMessage(hWnd_ToolTip, %TTM_ADDTOOL, 0, BYVAL VARPTR(TI))
          END IF
        END FUNCTION
        
        '====================================================================
        ' Tab Control Callback
        '====================================================================
        CALLBACK FUNCTION TabProc
        
          SELECT CASE AS LONG CB.MSG
          CASE %WM_COMMAND
              SELECT CASE AS LONG CBCTL
              CASE %BUTTON3  ' on page 1
                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                      ? "Tab Button3, Page1 Clicked"
                  END IF
              CASE %BUTTON4  ' on page 2
                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                      ? "Tab Button4, Page2 Clicked"
                  END IF
              END SELECT
          END SELECT
        
        END FUNCTION

        Comment


        • #5
          I was using it in the following lines

          Code:
          ' https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadimagew
          sTitle = "Information" ' or whatever..
          ' DIALOG SEND hWnd_ToolTip, %TTM_SETTITLE, %TTI_WARNING , STRPTR(sTitle)
          LOCAL hIcon, hInst AS DWORD
          LOCAL resFile AS LONG
          resfile = 1100
          ' need program instance handle for resource
          hInst = GetWindowLong(hWnd_ToolTip, %GWL_HINSTANCE)
          hIcon = LoadImageW(hInst, BYVAL resFile, %IMAGE_ICON, 0, 0, %LR_DEFAULTSIZE)
          DIALOG SEND hWnd_ToolTip, %TTM_SETTITLE, hIcon , STRPTR(sTitle)

          Comment


          • #6
            Seems like you need manifest to use own icon.
            '
            Code:
            #RESOURCE MANIFEST, 1, "XPTheme.xml"  ' at beginning of code - make sure path to XPTheme.xml is correct.
            '

            Comment


            • #7
              Originally posted by Borje Hagsten View Post
              Seems like you need manifest to use own icon.
              '
              Code:
              #RESOURCE MANIFEST, 1, "XPTheme.xml" ' at beginning of code - make sure path to XPTheme.xml is correct.
              '
              Good catch! Reference to Common Controls v6 required.
              Code:
              ...
              #RESOURCE MANIFEST, 1, "XPTheme.xml" ' at beginning of code - make sure path to XPTheme.xml is correct.
              ...
              LOCAL hIcon AS DWORD
              hIcon = LoadImage(EXE.INST,"#1100",%IMAGE_ICON,0,0,0)
              DIALOG SEND hWnd_ToolTip, %TTM_SETTITLE, hIcon , STRPTR(sTitle)

              Comment


              • #8
                BTW Tim, there is also a fault in hInst code - you should look for program instance, not tooltip.. whatever. Tested and following works:
                Click image for larger version  Name:	CanadaTooltip.jpg Views:	0 Size:	8.2 KB ID:	794202
                '
                Code:
                    LOCAL sTitle AS STRING, hIcon AS DWORD
                    sTitle = "Information"
                    hIcon = LoadImage(GetModuleHandle(""), "#1100", %IMAGE_ICON, 0, 0, %LR_DEFAULTSIZE)
                    SendMessage hWnd_ToolTip, %TTM_SETTITLE, hIcon, STRPTR(sTitle)  '%TTI_INFO
                    DestroyIcon hIcon
                '
                Also found that if one add %TTF_CENTERTIP to ti.uflags, the problem with "blinking" tooltip i some cases seems to be fixed.
                '
                Code:
                    TI.uFlags = %TTF_SUBCLASS OR %TTF_IDISHWND OR %TTF_CENTERTIP
                '

                Comment


                • #9
                  Ah, EXE.INST. Thank you, Stuart - I always forget about those "new" features in PBWin10.

                  Comment


                  • #10
                    Thank you, I had never used the EXE READ-ONLY user defined TYPE. It was new with PBWin 9 and PBCC 5. (just checked the old Help files.) If I needed the hInstance I used WINMAIN instead of PBMAIN. (ties to a discussion a couple days ago, doesn't it?)

                    Cheers,
                    Dale

                    Comment


                    • #11
                      Thank you Everyone

                      It seems like the below code will also work with EXE.INST instead of GetModuleHandle("")

                      Code:
                         hIcon = LoadImage(EXE.INST, "#1100", %IMAGE_ICON, 20, 20, %LR_DEFAULTSIZE)

                      Comment


                      • #12
                        Of course. What do you think that EXE.INST does other than to call GetModuleHandle?
                        Forum: http://www.jose.it-berater.org/smfforum/index.php

                        Comment


                        • #13
                          If you look in Help and MSDN you'll see EXE.INST and the number returned by GetModuleHandle() are the same number, hInstance.

                          GetModuleHandle() gets hInstance for .exe or .dll. When you start a program Windows gives it to the main function. With WINMAIN it is the first of four parameters. With PBMAIN Windows still passes it, but PowerBASIC takes care of "behind the scenes". Before PBWin 9 and PBCC 5 it might have gone in the bit bucket. Now it goes in EXE.INST

                          Cheers,
                          Dale

                          Comment


                          • #14
                            Overlapped posting- I do not think EXE.INST uses GetModulerHandle. Why do that when it comes in whichever MAIN you use?

                            Cheers,
                            Dale

                            Comment


                            • #15
                              Originally posted by Dale Yarker View Post
                              Overlapped posting- I do not think EXE.INST uses GetModulerHandle. Why do that when it comes in whichever MAIN you use?

                              Cheers,
                              Yep, as a guess, the EXE object and COMMAND$ array are both populated from the WINMAIN parameters when that function is wrapped by PBMAIN.



                              Comment


                              • #16
                                With a two buttons dialog, one for EXE.INST call, and one for GetModuleHandle() call,
                                using rohitab API Monitor2 you will see that a simple dialog will call GetModuleHandleW and GetModuleHandleA by itself on start.

                                Then it store it for later EXE.INST call because clicking EXE.INST button won't generate GetModuleHandle() call.
                                Clicking GetModuleHandle() button will of course generate the api call.

                                Comment


                                • #17
                                  > Yep, as a guess, the EXE object and COMMAND$ array are both populated from the WINMAIN parameters when that function is wrapped by PBMAIN.

                                  There is not an API function called WINMAIN. WinMain is the conventional name used for the application entry point. If the compiler supports it (some compilers, such FreeBasic, don't) it generates code to retrieve the information calling GetModuleHandle and GetCommandLine and then calls the user-provided entry point (that can be called WinMain or any other name) passing the retrieved information in its parameters.
                                  Forum: http://www.jose.it-berater.org/smfforum/index.php

                                  Comment


                                  • #18
                                    There is not an API function called WINMAIN.
                                    ??????????????? No one said there was. It is an application's entry point as said. When called by Windows to start the application, hInstance is a parameter passed by Windows which it just created. For here, I do not care what FreeBASIC does. (But since hInstance is one of 4 parameters passed by Windows, I'd WAG that FreeBASIC just ignores them.)((If Windows calls GetModuleHandle internally to pass hInstance to whatever MAIN function, that also is not our problem.))
                                    Dale

                                    Comment


                                    • #19
                                      I find it very hard to believe that WIndows needs to get the application name and pass it to GetModuleHandle in order to get the handle of the instance it is creating in order to pass it to the entry point WINMAIN. Same with GetCommandLine

                                      Comment


                                      • #20
                                        Agreed, but even if it did, there is no reason that I see for the application to call those API functions for provided parameters.

                                        Dale

                                        Comment

                                        Working...
                                        X