Here's a dll I've created that provides visually nicer and enhanced (functionality-wise) tooltips. It is dependent on Olaf's vbRichClient (the nice drawing comes via Cairo functionality) but is intended for use with regular VB6 projects, as illustrated in the demo.
Features:
- Regular tooltips (can be mult-line so that's an improvement right there!)
- Balloon Tips (Caps Lock is on kind of information)
- Tray Notifications (the pop-up kind)
- Custom Content (display anything you like; pictures, drawings, text, etc)
All the features above are illustrated in the demo. Here's a few images:
The demo is uploaded as a Project Group; just compile the dll for use in your own projects.
EDIT: Updated the code per comments in post #8
Last edited by ColinE66; Dec 21st, 2014 at 10:06 AM.
Reason: Incorporated suggestions from post #2
If you don't know where you're going, any road will take you there...
A couple of small observations/thoughts regarding the default behaviour of the tooltips:
According to this: http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx, the default hover delay for a tooltip is the same as the double-click delay (about 1/2 second typically) - your tooltips feel a bit "laggy" by comparison, so maybe ut would be better to use the double-click delay as the default value rather than 1000 ms?
Also, your tooltips fade even if tooltip fading has been disabled by the user. It might be preferable to honour the user's settings by calling SystemParametersInfo with SPI_GETTOOLTIPANIMATION (if not enabled then just popup the window) and GETTOOLTIPFADE (if animation is enabled, and this setting is enabled then fade, otherwise slide).
Just my 2 cents
I accomplished everything except for sliding tooltips by adding the following declarations to modDeclares:
Code:
Public Const SPI_GETTOOLTIPANIMATION As Long = &H1016
Public Const SPI_GETTOOLTIPFADE As Long = &H1018
Public Declare Function SystemParametersInfo Lib "user32.dll" Alias "SystemParametersInfoA" (ByVal uAction As Long, ByVal uParam As Long, ByRef lpvParam As Any, ByVal fuWinIni As Long) As Long
Public Declare Function GetDoubleClickTime Lib "user32.dll" () As Long
Then I changed the default value of all the pHoverTime parameters in the RichTip class to -1.
In the Init sub of the RichTip class, I control the hover delay as follows:
Code:
If pHoverTime < 0 Then
mHoverTime = Win.GetDoubleClickTime
Else
mHoverTime = pHoverTime
End If
In the Class_Initialize sub of the RichTip class, I store True in a module level boolean (mAnimationEnabled) if animation is enabled, otherwise False as follows:
Code:
Dim lAnimationEnabled As Long
Win.SystemParametersInfo &H1016, 0&, lAnimationEnabled, 0&
mAnimationEnabled = lAnimationEnabled
Lastly, I changed the logic for using the fade effect in the Show method as follows:
Code:
If (Not mStyle = TrayTip) And mAnimationEnabled Then mWidgetsAlpha = 0 Else mWidgetsAlpha = 1
Considering here, to steal a bit of your Drawing-Code to pep-up the currently
somewhat "unimpressive" Std-Tooltip which is built into the WidgetEngine.
(...and for RC6, the ability to influence the directional behaviour of the small
"tip-ears" also seems like a good idea).
No problem, Olaf. Though you might want to see if you can improve upon the sizing/positioning aspects of the balloon and its stem. If you can do that the code-size might reduce drastically! My brain became a bit fried whilst coding that part and I just stopped once I had it working!
If you don't know where you're going, any road will take you there...
Tidied the code a little and simplified the sub-classing aspects. Also fixed a couple of small drawing errors; one with the tips shadow and the other with the close button.
Oh, and enhanced the demo a little...
If you don't know where you're going, any road will take you there...
When loading prjRichTip.vbp, I got the error message...
Just played that through here (also getting an error, compiled Dlls in Codebank-Zips are not allowed) ...
But since prjRichTip.vbp is already the Dll-Project, you can ignore that message -
and just compile the RichTip.dll into the same Folder as you started the *.vbp from.
Then the Dll-Project can be closed already...
After that you can try to load the Project1.vbp (which is the Demo-Project) -
In case you get no error whilst loading it, then everything should be fine ...
If you get an error like 'RichTip.dll not found' there too, then just open the Project-
references-Dialogue - remove the old, not found Ref to RichTip.dll - and then include
it again as found under the Reference-Entries as "ToolTips, Balloontips, ..."
That did it for me - and the Demo works as it should.
You will find, that many RC5-users don't hesitate to compile certain solutions
(which are stable already) into their own COM-Dlls (as Colin did here with RichTip.dll,
or as I did with vbWidgets.dll).
That's because most of them ship the RC5-Base-Dlls already anyways (regfree in a Bin-Folder) -
so one or more of your own Dlls will not make much difference with regards to your deployment -
and it's the safer way to work with SubClassing-related implementations in the VB6-IDE
(less crashes, even when the Stop-Button is pressed).
But since prjRichTip.vbp is already the Dll-Project, you can ignore that message -
and just compile the RichTip.dll into the same Folder as you started the *.vbp from.
Then the Dll-Project can be closed already...
After that you can try to load the Project1.vbp (which is the Demo-Project) -
In case you get no error whilst loading it, then everything should be fine ...
If you get an error like 'RichTip.dll not found' there too, then just open the Project-
references-Dialogue - remove the old, not found Ref to RichTip.dll - and then include
it again as found under the Reference-Entries as "ToolTips, Balloontips, ..."
That did it for me - and the Demo works as it should.
Read through. The regfree deployment-approach is indeed tempting and I was just curious about how to use the DirectCOM.dll that comes along with vbRichClient5.dll. The only concern for me, though, is that for classes instantiated either by GetInstance or CreateObject, there will not be any auto-completion information, which makes coding a little bit troublesome for a non-professional.
Read through. The regfree deployment-approach is indeed tempting and I was just curious about how to use the DirectCOM.dll that comes along with vbRichClient5.dll. The only concern for me, though, is that for classes instantiated either by GetInstance or CreateObject, there will not be any auto-completion information, which makes coding a little bit troublesome for a non-professional.
For development you should still register any ActiveX DLLs on your machine, so that you can still use Intellisense. You can then create helper functions to create your objects.
In a standard module you can have code like this:
Code:
Public Function InIde() As Boolean
' Returns True if running in the VB6 IDE, otherwise False
Static s_InIde As Boolean
Static s_Checked As Boolean
If s_Checked Then
InIde = s_InIde
Else
On Error Resume Next
Debug.Print 1 / 0
s_InIde = Err.Number: Err.Clear
InIde = s_InIde
s_Checked = True
End If
End Function
Public Function CreateMyClass() As MyLib.MyClass
' Create a new instance of a class (change MyLib.MyClass to the actual Library/Class Name you want
' It will use normal VB6 instancing in the IDE so you can get Intellisense and Run-time Debugging capabilities
' It will use reg-free COM when compiled
If InIde Then
Set CreateMyClass = New MyLib.MyClass
Else
Set CreateMyClass = new_c.RegFree.GetInstanceEx("MyLib.dll", "MyClass")
End If
End Function
Then anywhere else in your project (forms, classes, modules, etc...), you can instantiate your objects like this (and use them as you normally would after instantiation).
Code:
Private Sub Command1_Click()
' Use a command button click event as an example
Dim lo_MyClass As MyLib.MyClass ' Declare you object variable normally
Set lo_MyClass = CreateMyClass ' Create a new instance of your class using the dynamically switching ide-time/run-time helper
lo_MyClass.MySub ' Use methods of your class as normal
End Sub
The regfree deployment-approach is indeed tempting and I was just curious about how to use the DirectCOM.dll that comes along with vbRichClient5.dll. The only concern for me, though, is that for classes instantiated either by GetInstance or CreateObject, there will not be any auto-completion information, which makes coding a little bit troublesome for a non-professional.
As you can see from jpbro's example, intellisense or not has nothing really to do
with the way of instantiation.
When you declare an Object-Variable with a certain available *explicit* Type
(and not 'As Object') as e.g.:
Code:
Dim D As Scripting.Dictionary
Then we talk about early Binding (which offers Intellisense) and so this Declaration
(this Variable which has a concrete Type bound to it) has nothing to do with instantiation,
but only with "available TypeLib-Informations" (which in the above case were read from your
checked in Project-Reference: "Microsoft Scripting Runtime" ... no instantiation at play there...).
And these Typelib-Informations (no matter whether they came from a *.dll or a *.tlb)
will then be compiled by VB6 directly into your self-produced Binary (usually your *.exe).
Now to instantiations against such early-bound explicitely declared ObjectVar-Types:
All three lines below will work in basically the same way, ensuring a new instance in D:
Code:
Dim D As Scripting.Dictionary
Set D = New Scripting.Dictionary
Set D = CreateObject("Scripting.Dictionary")
Set D = GetInstance("scrrun.dll", "Dictionary")
Your new instance in D is:
- early-bound in all three cases
- you will have intellisense in all three cases
- your Method-Calls will be performed fast and directly, using the VTable ... and not slowly over IDispatch
The only difference you will encounter among the three instantiation-lines above is,
that when you unregister scrrun.dll (though leaving it in place) - the first two calls
will fail - whilst the last one (GetInstance) will still be able to deliver an *early-bound*
instance in D (as before).
I guess what I want to point out very clearly is, that (DirectCOM.dll based) regfree instancing
per GetInstance(Ex) is not forcing you in any way, to work latebound - *nor* does it force
you to ship your compiled App in "latebound-mode"...
As already pointed out, the TypeLib-Info at *compile-time* of your App is linked into your
Binary (hence VB will not look for these Interface-Infos in the Registry or some Dll anymore,
when it is later executed at a customer-machine).
The only thing you will have to ensure when you ship your App with a \Bin\-Subfolder which
contains your Dlls is, that in case you plan to use their regfree created instances early-bound
in your App, that the interfaces of these Dlls you ship in \Bin\ *really* need to be the same ones,
your VB6-IDE resolved to at compile-time (the Exe-internally linked-in Type-Interfaces have
to match with the ones in the regfree loaded Dll-Classes).
For your own "MyCOMLib.vbp" this means (in case you fixed a bug in there and recompiled this Dll-Project):
MyCOMLib.vbp being switched to "Binary compatibility" in its project-settings:
- only the \Bin\ Subfolder in your deployment has to be updated with this new compiled Dll-Binary.
..(since the TypeLib-Infos in your "consuming Exe" are still compatible with the new Dlls Interface).
MyCOMLib.vbp being at "Project compatibility" (or "no-compatibility") in its project-settings:
- the \Bin\ Subfolder in your deployment has to be updated with this new compiled Dll-Binary.
- your Executable-Project will need to be recompiled and the *.exe be placed in your deployment-folder too
..(since the TypeLib-Infos in your "consuming Exe" need to be made "newly aware" with the new Dlls Interface).
Looks pretty cool. I've been looking for something like this, but I need to know if I can SET the size of the picturebox, so that the size of the tooltip is somewhat consistent?