Übersicht
- Common Controls 5.0 oder 6.0 - neuer ist nicht besser!
- 0001 ListView mit optimaler Spaltenbreite
- 0002 TabStrip-Registerkarte zur Laufzeit umschalten
- 0003 Tooltip-Text des Slidercontrols ausschalten
- 0004 ListView mit einstellbaren Icon-Abständen (LVM_SETICONSPACING = &H1035&)
- 0005 ListView Spaltenreihenfolge speichern und wiederherstellen
- 0006 Explorer-Theme für ListView und TreeView Controls (ab Windows XP)
- 0007 ListView Watermark - erstmalige VB6-Lösung im Internet!!!
Common Controls 5.0 oder 6.0 - neuer ist nicht besser!
Was man wissen muss: Timo Kunze, der Vater der VB6 Unicode-Controls, hat es einmal gut erklärt (Zitat): "Die 5er greifen auf die comctl32.dll zurück, d. h. sie sind nur eine COM-Hülle um die nativen Controls von Windows (eben so wie meine Controls). Diese COM-Hülle der 5er Controls mag über 10 Jahre alt sein, aber die Unterlage, also die comctl32.dll ist brandaktuell. Deshalb funktioniert mit den 5ern bspw. auch das Theming. Bei den 6er Controls ist Microsoft dagegen einen anderen Weg gegangen. Man hat 1998 oder so den Quellcode der comctl32.dll genommen und ihm ein COM-Interface verpasst. Das Ergebnis war die mscomctl.ocx, die nicht mehr von der comctl32.dll abhängt. Vorteil: Die Controls verhalten sich auf allen Windows-Versionen gleich. Um also optisch und funktionell mit VB6 Programme für Vista und Windows 7 zu schreiben empfiehlt es sich die Microsoft Windows Common Controls 5.0 zu verwenden - besonders dann, wenn ListView und/oder TreeView Controls zum Einsatz kommen. Einige der folgenden Tipps setzen den Einsatz der 5er Controls voraus... |
0001 ListView mit optimaler Spaltenbreite
Leider stellt das ListView-Control von Hause aus keine Methode zum Optimieren der Spaltenbreite in der Reportansicht zur Verfügung. Diese Funktion läßt sich aber wieder einmal mit einem API-Aufruf nachbilden, und zwar mit dem SendMessage Befehl. Übrigens - auch der Windows Explorer unterstütz diese Funktion: öffnen Sie ein Explorerfenster in der Detailansicht, halten Sie die <Strg>-Taste gedrückt und betätigen die <+>-Taste des Ziffernblocks... ' Deklaration: Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long ' Funktion: Public Sub lvwSetColumnWidth(lstView As ListView, ByVal colIdx As Long) Const LV_SETCOLUMNWIDTH As Long = &H101E With lstView ' Prüfen, ob das Listview in der Ansicht "Report" ist If .View = lvwReport Then If colIdx > 0 And colIdx <= .ColumnHeaders.Count Then SendMessage .hwnd, LV_SETCOLUMNWIDTH, colIdx - 1, -2 End If End If End With End Sub ' Aufruf für alle Spalten eines ListView: For i = 1 To ListView1.ListItms.Count lvwSetColumnWidth ListView1, i Next i | |
Autor: ralf schlegel |
0002 TabStrip-Registerkarte zur Laufzeit umschalten
Das TabStrib-Control und seine Registerkarten wird in den meisten Anwendungen zum Beispiel in der Auswahl der Programmeigenschaften eingesetzt. Leider, so scheint es, gibt es keine Methode um eine bestimmte Registerkarte zur Laufzeit zu aktivieren. Und dennoch läßt sich diese Eigenschaft mit einer einzigen Codezeile realisieren: TabStrip1.Tabs(Index).Selected = True Wobei 'Index' für die gewünschte Registerkarte steht. | |
Autor: ralf schlegel |
0003 Tooltip-Text des Slidercontrols ausschalten
Wenn Sie den Slider der Standard-Controls mit der Maus verschieben, so erscheint grundsätzlich der Wert (value) des Controls als ToolTip-Text. Das ist nicht immer sinnvoll und kann mit zwei einfachen SendMessage Aufrufen unterbunden werden. Kopieren Sie die unten stehende Funktion in ein Programm-Modul und rufen Sie sie einmal (zum Beispiel in der Load-Anweisung der Parent-Form) auf. Übergeben Sie der Funktion das Handle des Sliders: ' Deklaration: Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long ' Funktion: Public Sub sliderToolTipOff(ByVal hwnd As Long) Dim ret As Long ret = SendMessage(hwnd, &H41E, 0&, ByVal 0&) SendMessage ret, &H401, 0&, ByVal 0& End Sub | |
Autor: ralf schlegel |
0004 ListView mit einstellbaren Icon-Abständen (LVM_SETICONSPACING = &H1035&)
Mit dem Standard ListView-Control die Abstände der Icons einstellen... Hintergrund: PostMessage arbeitet fast genauso wie SendMessage - setzt die Nachricht in die Warteschlange von Windows, kehrt aber sofort zurück, während SendMessage auf einen Rückgabewert wartet! Das scheint in VB Probleme zu verursachen. Also nutzen Sie die Post und vertrauen darauf, dass die Zustellung auch erfolgt! :-) Was Sie sonst noch wissen sollten:
' Deklaration: Public Declare Function PostMessage Lib "user32" Alias" PostMessageA" (ByVal hWnd As Long, _ ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long ' Funktion: ' Setzt den Abstand der Icons im ListView-Control in Pixel ' Minimaler Wert ist 4Pixel! wSpace/hSpace = Icongröße+Abstand in Pixel! Public Function ListViewSetIconSpace(ByVal hWnd As Long, _ ByVal wSpace As Integer, ByVal hSpace As Integer) As Long Dim isp As Long isp = (wSpace And &HFFFF&) Or (hSpace * &H10000) ' MakeLong ListViewSetIconSpace = PostMessage(hWnd, &H1035&, 0, isp) End Function | |
Autor: ralf schlegel |
0005 ListView Spaltenreihenfolge speichern und wiederherstellen
Zum Speichern und Wiederherstellen der Spaltenreihenfolge stellt Microsoft im ListView API die Methoden LVM_SETCOLUMNORDERARRAY und LVM_GETCOLUMNORDERARRAY zur Verfügung, die wir in VB6 mit der SendMessage Funktion leicht implementieren können: ' Konstanten: Private Const LVM_FIRST As Long = &H1000& Private Const LVM_SETCOLUMNORDERARRAY As Long = (LVM_FIRST + 58) Private Const LVM_GETCOLUMNORDERARRAY As Long = (LVM_FIRST + 59) ' Declaration Systemfunktionen: Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _ ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long Private Declare Function SendMessageLong Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _ ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Private Function pSetColumnOrderArray(ByVal hwnd As Long, ByVal iCount As Long, _ ByRef lpiArray As Long) As Boolean pSetColumnOrderArray = SendMessage(hwnd, LVM_SETCOLUMNORDERARRAY, ByVal iCount, lpiArray) End Function Private Function pGetColumnOrderArray(ByVal hwnd As Long, ByVal iCount As Long, _ ByRef lpiArray() As Long) As Boolean ReDim lpiArray(iCount - 1) pGetColumnOrderArray = SendMessage(hwnd, LVM_GETCOLUMNORDERARRAY, ByVal iCount, lpiArray(0)) End Function Es bietet sich nun an, diese Information in der Registry zu speichern. Wie man den Funktionen aber entnehmen kann, arbeitet Microsoft hierbei mit einem LongArray! Um nun dieses LongArray mit den VB Funktionen GetSetting und SaveSetting verarbeiten zu können, muss dieses Array in einen String gewandelt werden. Dafür benötigen wir 2 Hilfsfunktionen: ' Wandelt ein LongArray in einen String, ' wobei das Trennzeichen optional gewählt werden kann: Private Function pLongArrayToString(ByRef lArray() As Long, _ Optional delimiter As String = ";") As String Dim i As Long If IsArray(lArray) Then For i = LBound(lArray) To UBound(lArray) pLongArrayToString = pLongArrayToString & CStr(lArray(i)) & delimiter Next End If End Function ' Zerlegt den übergebenen String gemäß Trennzeichen und ' gibt die Werte as LongArray zurück Private Function pStringToLongArray(ByVal s As String, _ Optional delimiter As String = ";") As Long() Dim i As Long Dim fld() As Long Dim fields() As String fields = Split(s, delimiter) ReDim fld(UBound(fields)) For i = 0 To UBound(fields) fld(i) = Val(fields(i)) Next i Erase fields pStringToLongArray = fld End Function Kommen wir nun zu den eigentlichen Funktionen: lvwLoadColumnOrder und lvwSaveColumnOrder. Public Sub lvwLoadColumnOrder(ByVal lstView As Object) Dim nr As Long, cols() As Long Dim regString As String With lstView nr = .ColumnHeaders.Count If nr = 0 Then Exit Sub regString = GetSetting(App.Title, "Settings", .Parent.Name & "." & .Name & "_Columns", "0;") cols = pStringToLongArray(regString) If UBound(cols) > nr Then ReDim Preserve cols(nr) pSetColumnOrderArray .hwnd, UBound(cols), cols(0) End With End Sub Public Sub lvwSaveColumnOrder(ByVal lstView As Object) Dim nr As Long, cols() As Long Dim regString As String With lstView nr = .ColumnHeaders.Count If nr = 0 Then Exit Sub pGetColumnOrderArray .hwnd, nr, cols regString = pLongArrayToString(cols) SaveSetting App.Title, "Settings", .Parent.Name & "." & .Name & "_Columns", regString End With End Sub Damit Sie nicht alles abtippen oder kopieren müssen, finden Sie hier ein kleines Demoprojekt zum Download: | |
Autor: ralf schlegel |
0006 Explorer-Theme für ListView und TreeView Controls (ab Windows XP)
Wie man den XP-Style und die Windows-Themes ins eigene Projekt mit Hilfe einer Manifestdatei einbindet, wird ja bereits in zahlreichen Tipps im Internet beschrieben. Leider geht man hierbei aber immer nur auf die Standard-Controls ein. Voraussetzungen / Einschränkungen:
Da der Quellcode etwas umfangreicher ist schauen Sie sich bitte das Beispielprojekt an und kopieren die benötigten Dateien oder Funktionen dann in Ihr Projekt. Das Beispiel sollte ausreichend dokumentiert sein: alles zur Erweiterung der Styles findet in der 'Form_Load' Prozedur statt. Die Manifestdatei wurde per Resource eingebunden. | |
Autor: ralf schlegel |
0007 ListView Watermark - erstmalige VB6-Lösung im Internet!!!
Ein Hintergrundbild als Wasserzeichen LVBKIF_TYPE_WATERMARK im ListView zu implementieren, ist in VisualBasic 6 nicht so einfach möglich!
Hier also erst einmal die Funktion, die aus einem beliebigen Picture-Objekt eine Bitmap-Kopie erzeugt und das Handle zurückgibt: Private Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" ( _ ByVal hObject As Long, ByVal nCount As Long, ByRef lpObject As Any) As Long Private Declare Function CreateDCAsNull Lib "gdi32" Alias "CreateDCA" (ByVal lpDevName As String, _ lpDeviceName As Any, lpOutput As Any, lpInitData As Any) As Long Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, _ ByVal nWidth As Long, ByVal nHeight As Long) As Long Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, _ ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, _ ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long Private Type BITMAP bmType As Long bmWidth As Long bmHeight As Long bmWidthBytes As Long bmPlanes As Long bmBitsPixel As Integer bmBits As Long End Type Private Function pBitmapHandleFromPicture(ByVal iPic As IPicture) As Long Dim hDCDesktop As Long, hBMP As Long Dim hDC1 As Long, hBmpOld1 As Long Dim hDC2 As Long, hBmpOld2 As Long Dim tBMP As BITMAP If iPic Is Nothing Then Exit Function GetObjectAPI iPic.Handle, Len(tBMP), tBMP hDCDesktop = CreateDCAsNull("DISPLAY", ByVal 0&, ByVal 0&, ByVal 0&) If hDCDesktop Then hDC1 = CreateCompatibleDC(hDCDesktop) If hDC1 Then hBmpOld1 = SelectObject(hDC1, iPic.Handle) hDC2 = CreateCompatibleDC(hDCDesktop) If hDC2 Then hBMP = CreateCompatibleBitmap(hDCDesktop, tBMP.bmWidth, tBMP.bmHeight) If hBMP Then hBmpOld2 = SelectObject(hDC2, hBMP) BitBlt hDC2, 0, 0, tBMP.bmWidth, tBMP.bmHeight, hDC1, 0, 0, vbSrcCopy SelectObject hDC2, hBmpOld2 pBitmapHandleFromPicture = hBMP End If ' hBMP DeleteDC hDC2 End If ' hDC2 SelectObject hDC1, hBmpOld1 DeleteDC hDC1 End If ' hDC1 DeleteDC hDCDesktop End If ' hDCDesktop End Function Kommen wir nun zum eigentlichen Funktionsaufruf lvwSetWatermark. Dieser Funktion übergeben wir das ListView-Handle, sowie ein beliebiges Bildobjekt. Das kann eine Picturebox, oder ein Bild aus einer ImgaeList sein. Wichtig ist, das ein evtl. bereits geladenes Hintergrundbild erst einmal gelöscht wird LVBKIF_SOURCE_NONE, sonst funktioniert es nicht! Zum Ende der Funktion setzten wir noch den Text mit LVM_SETTEXTBKCOLOR auf transparenten Hintergrund, damit er die Grafik nicht zerstückelt. Hier die dafür benötigten Constanten, Deklarationen und Typen: ' Constants: Public Const LVM_FIRST As Long = &H1000& Public Const LVM_SETTEXTBKCOLOR As Long = (LVM_FIRST + 38) Public Const LVM_SETBKIMAGE As Long = (LVM_FIRST + 68) ' LVM_SET/GETBKIMAGE Flags Private Const LVBKIF_SOURCE_NONE As Long = &H0 Private Const LVBKIF_SOURCE_HBITMAP As Long = &H1 ' >= WinXP, only visible in compiled mode Private Const LVBKIF_SOURCE_URL As Long = &H2 Private Const LVBKIF_SOURCE_MASK As Long = &H3 Private Const LVBKIF_STYLE_NORMAL As Long = &H0 Private Const LVBKIF_STYLE_TILE As Long = &H10 Private Const LVBKIF_TYPE_WATERMARK As Long = &H10000000 ' >= WinXP, only visible in compiled mode Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, _ ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long Private Declare Function SendMessageLong Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, _ ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Private Type LVBKIMAGE ulFlags As Long ' LVBKIF_* hBM As Long ' bitmap handle pszImage As String ' file name cchImageMax As Long ' size of max file name xOffsetPercent As Long ' x offset yOffsetPercent As Long ' y offset End Type Private Const CLR_DEFAULT = &HFF000000 ' default background color Private Const CLR_NONE = &HFFFFFFFF ' no background color (transparent) Public Sub lvwSetWatermark(ByVal lvHwnd As Long, ByVal iPic As IPicture) Dim bgi As LVBKIMAGE With bgi ' first clear up any background: .ulFlags = LVBKIF_SOURCE_NONE SendMessage lvHwnd, LVM_SETBKIMAGE, 0, bgi ' then set watermark image: .ulFlags = LVBKIF_TYPE_WATERMARK .hBM = pBitmapHandleFromPicture(iPic) SendMessage lvHwnd, LVM_SETBKIMAGE, 0, bgi SendMessageLong lvHwnd, LVM_SETTEXTBKCOLOR, 0&, -1& End With End Sub ACHTUNG: das Ganze funktioniert nur bei Verwendung der ListViews der Common Controls 5.0, Windows XP oder neuer und ist nur in compilierter EXE sichtbar! Ausserdem muß vor der Zuweisung des Wasserzeichens noch die Grafikpufferung durch den API-Aufruf LVS_EX_DOUBLEBUFFER aktiviert werden, was aus Platzgründen hier nicht angegeben ist! Der gesamte Quellcode ist im Demoprojekt zum Download enthalten... | |
Autor: ralf schlegel |