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:
In a new UserForm, with two labels, three command buttons, and one image control, all named as indicated...'//*****************************************************************************// '// 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
Userform Module:
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.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
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





Reply With Quote