Consulting

Results 1 to 13 of 13

Thread: Adding Custom button in titlebar of userform

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #13
    Knowledge Base Approver VBAX Guru GTO's Avatar
    Joined
    Sep 2008
    Posts
    3,368
    Location

    Fake Titlebar workaround

    Hi There,

    Maybe this has to do with the users one is faced with, but adding custom buttons to the titlebar seems non-intuitive for the users. Shucks, least as I can see, the use of the close button (or the close button and the minimize and restore/maximize buttons) is one of the few things we can safely bet on the user not mucking up. Now we want to "un-train" the user? Again, maybe just the users I am used to, so onward...

    Hopefully someone will take pity and point out how to do this if I am incorrect, but I see no way of actually creating an additional custom button in the titlebar of a userform with VBA and/or API.

    I would note that as a concept it certainly seems possible, as I did find this in C# : http://www.codeproject.com/KB/cs/mintraybtn.aspx

    Unfortunately, I do not understand the code to even know if the efforts are translatable.

    If this is possible through VB6 as you indicated, maybe zip a text file with the code. Then maybe someone could see a way in VBA?

    I did find a workaround in VB, that I was able to carry over to VBA. Quite frankly, this seems far too mucky to me to be worth it, but for what its worth:

    In a Standard Module:

    '//*****************************************************************************//
    '// Using code adapted from Masaru Kaji (Colo) at:                              //
    '// http://puremis.net/excel/code/024.shtml                                     //
    '// and code for grabbing a label as a pseudo titlebar at:                      //
    '// http://www.developerfusion.com/code/...stom-title-bar                   //
    '//*****************************************************************************//
    Option Explicit
     
    Public Declare Function ReleaseCapture Lib "user32" () As Long
     
    Public Declare Function SendMessage Lib "user32" _
                             Alias "SendMessageA" (ByVal hWnd As Long, _
                                                   ByVal wMsg As Long, _
                                                   ByVal wParam As Long, _
                                                   ByRef lParam As Any _
                                                   ) As Long
     
    Public Declare Function SetWindowText Lib "user32" _
                             Alias "SetWindowTextA" (ByVal hWnd As Long, _
                                                     ByVal lpString As String _
                                                     ) As Long
     
    Public Declare Function GetWindowLong Lib "user32" _
                            Alias "GetWindowLongA" (ByVal hWnd As Long, _
                                                    ByVal nIndex As Long _
                                                    ) As Long
     
    Public Declare Function SetWindowLong Lib "user32" _
                            Alias "SetWindowLongA" (ByVal hWnd As Long, _
                                                    ByVal nIndex As Long, _
                                                    ByVal dwNewLong As Long _
                                                    ) As Long
     
    Public Declare Function DrawMenuBar Lib "user32" (ByVal hWnd As Long _
                                                      ) As Long
     
    Public Declare Function FindWindowA Lib "user32" (ByVal lpClassName As String, _
                                                      ByVal lpWindowName As String _
                                                      ) As Long
     
    Public Const HTCAPTION = 2
    Public Const WM_NCLBUTTONDOWN = &HA1
    Public Const GWL_STYLE = -16
    Public Const WS_CAPTION = &HC00000
     
    Public Function TitleBar_Hide(UF As Object, lUFHandle As Long)
    Dim lWindow As Long
     
        lUFHandle = FindWindowA(vbNullString, UF.Caption)
        lWindow = GetWindowLong(lUFHandle, GWL_STYLE)
        lWindow = lWindow And (Not WS_CAPTION)
        Call SetWindowLong(lUFHandle, GWL_STYLE, lWindow)
        Call DrawMenuBar(lUFHandle)
    End Function
    In a new UserForm, with two labels, three command buttons, and one image control, all named as indicated...

    Userform Module:

    Option Explicit
     
    Dim hWnd As Long
     
    Private Sub cmdCancel_Click()
        Unload Me
    End Sub
     
    Private Sub lblTitleBar_MouseDown(ByVal Button As Integer, _
                                 ByVal Shift As Integer, _
                                 ByVal X As Single, _
                                 ByVal Y As Single)
        '// I have read exactly nothinig on ReleaseCapture and have very little true    //
        '// grasp on SendMessage, so this part is mostly like electricity to a five     //
        '// year old.  Its magic, it works, I cannot see how, but I know not to stick a //
        '// butter knife into a socket.                                                 //
        ReleaseCapture
        SendMessage hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0&
    End Sub
     
    Private Sub cmdClose_Click()
        Unload Me
    End Sub
     
    Private Sub cmdSpecial_Click()
        MsgBox "Hello World!", 0, vbNullString
    End Sub
     
    Private Sub UserForm_Initialize()
    Dim lRetVal As Long
     
    Const TITLEBAR_HGT As Double = 14
    Const TITLEBAR_CAPTION As String = "Fake TitleBar"
        With Me '(frmFakeTitlebar)
            .Caption = "Fake Titlebar"
            .Width = 240
     
            With .lblTitleBar
                .BackColor = &H8000000F
                .BorderStyle = fmBorderStyleNone
                '// What the caption is doesn't matter, but we do need one, as we'll    //
                '// use it for SetWindowText                                            //
                .Caption = "My TitleBar"
                .Height = TITLEBAR_HGT
                .Width = .Parent.Width + 4
                .Left = -2
                .Top = 0
                .Picture = Me.imgMyTitlebar.Picture
            End With
            '// The image control would have a picture saved of whatever color/gradient //
            '// that best reflects the normal titlebar.  I believe that this is another //
            '// area where the workaround comes up short, as (didn't bother testing) I'm//
            '// fairly certain that if the user chooses different 'looks' for the       //
            '// windows' appearance, we cannot replicate on the fly?                    //
            '// Note that we set the image control's visibility to False, effectively   //
            '//burying it behind lblTitleBar                                            //
            With .imgMyTitlebar
                .BorderStyle = fmBorderStyleNone
                .Height = 15
                .Width = 244
                .Left = -2
                .Top = 0
                .Visible = False
            End With
            With .lblCaption
                .BackStyle = fmBackStyleTransparent
                .Caption = TITLEBAR_CAPTION
                With .Font
                    .Bold = False
                    .Name = "System"
                    .Size = 9
                    .Underline = False
                End With
                .ForeColor = &HFFFFFF
                .Height = TITLEBAR_HGT
                .Width = Me.Width * 0.667
                .Left = 2
                .Top = 0
                .TextAlign = fmTextAlignLeft
            End With
            '// Here's about the best I could manage.  As command buttons appear to have//
            '// a non-adjustable internal margin for the caption, same as the label used//
            '// as a titlebar, I used the picture property and cropped screen shots for //
            '// the images.  Admittedly extrememly rudimentary...                       //
            With .cmdClose
                .Height = 12
                .Width = 12
                .Left = .Parent.Width - 17
                .Top = 1
                .TabStop = False
            End With
     
            With .cmdSpecial
                .Height = 12
                .Width = 12
                .Left = .Parent.Width - 30
                .Top = 1
                .TabStop = False
            End With
     
            '// Now, any other controls we are adding need to be positioned offset to   //
            '// lblTitleBar's height, as using any type of common spacing such as 12 or //
            '// 6, would of course result in the control being up in the new 'titlebar's'//
            '// area.  Although I think this whole idea seems a bit mucky, I would use  //
            '// a Constant to at least make it a bit easier.                            //
            With .cmdCancel
                .Caption = "Unload"
                .Font.Size = 11
                .Height = 22
                .Width = 45
                .Left = 186
                .Top = TITLEBAR_HGT + 12
            End With
            .Height = .cmdCancel.Top + .cmdCancel.Height + 12
        End With
     
        '// Hide the normal titlebar                                                    //
        TitleBar_Hide Me, hWnd
        '// Get the fake titlebar (label) set up so it can be used to 'grab/drag' the   //
        '// form like the titlebar normally would.                                      //
        lRetVal = SetWindowText(hWnd, Me.lblTitleBar.Caption)
    End Sub
    Note: I am writing in xl2000, and for some reason, I seem to recall hWnd being available in 2003. I might well be recalling incorrectly, but of course if it is, this would save a step.

    As mentioned, I certainly think this is too mucky. Regardless of opinion as to whether sticking extra buttons in the titlebar is the way to go about it, unless there is a proper way of getting a button added to the actual titlebar, I would be at Bob's question, as to why would we want to?

    Regardless, if this is the route you want to take, I hope this helps,

    Mark
    Last edited by GTO; 05-31-2010 at 08:04 AM. Reason: Forgot to attach the file :-(

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •