|
Da geben Sie sich so viel Mühe, die Spaltenbreiten eines ListView-Steuerelements im Report-Modus an ideale Maße anzupassen - und schon kommt der liebe (oder böse?) Anwender daher und ändert in den Spaltenköpfen mit der Maus die Breite der Spalten... Mein Vorschlag zur Abhilfe: Blenden Sie die Spaltenköpfe doch einfach aus, indem Sie die Eigenschaft HideColumnHeaders auf True setzen. Nein, nicht? Das ListView-Dings soll doch unbedingt Spaltenköpfe haben? Na gut: Fügen Sie doch eigene Spaltenköpfe hinzu.
Eine Möglichkeit dazu bietet ein Feld (Control-Array) von simplen CommandButtons, die Sie entsprechend über dem ListView und den jeweiligen Spalten platzieren und entsprechend in der Breite anpassen. Sie brauchen nur den ersten CommandButton (Name etwa: ColumnHeader) des Control-Arrays mit dem Index 1 anzulegen. Die übrigen Buttons werden von der folgenden Prozedur selbsttätig nachgeladen, positioniert und mit dem Text des eigentlichen ColumnHeaders versehen.
Public Sub LvwFixColumnHeaders(ListView As ListView, _
ColumnHeader As Object)
Dim i As Integer
With ListView
ColumnHeader(1).Top = .Top
.Height = .Height - 14 * Screen.TwipsPerPixelY
.Top = .Top + 14 * Screen.TwipsPerPixelY
ColumnHeader(1).Height = 17 * Screen.TwipsPerPixelY
ColumnHeader(1).Left = .Left + 2 * Screen.TwipsPerPixelX
ColumnHeader(1).ZOrder 0
With .ColumnHeaders
ColumnHeader(1).Caption = .Item(1).Text
ColumnHeader(1).Width = .Item(1).Width + _
2 * Screen.TwipsPerPixelX
For i = 2 To .Count
Load ColumnHeader(i)
ColumnHeader(i).Caption = .Item(i).Text
ColumnHeader(i).Left = ColumnHeader(i - 1).Left + _
ColumnHeader(i - 1).Width
ColumnHeader(i).Width = .Item(i).Width
ColumnHeader(i).Visible = True
ColumnHeader(i).ZOrder 0
Next 'i
End With
.HideColumnHeaders = True
End With
End Sub
Sie rufen diese Prozedur am besten im Load-Ereignis des betreffenden Forms auf und übergeben ihr als Parameter das ListView und das Control-Array (ohne Index!):
LvwFixColumnHeaders ListView1, ColumnHeader
Im "unberührten" Zustand sieht das Ergebnis fast hundertprozentig aus wie das Original. Etwas unschön, aber sicher nicht gravierend nachteilig, ist das Aussehen beim Anklicken eines der neuen Spaltenköpfe. Denn ein CommandButton kann ja den Fokus erhalten - und zeigt daher auch das gepunktete Fokus-Rechteck. Um den Effekt etwas abzumildern können Sie im Click-Ereignis des Button-Control-Arrays den Fokus an das ListView weiterreichen. Zugleich können Sie natürlich das Click-Ereignis auch auswerten, um wie gewohnt Funktionen bezüglich der Spalte auszulösen, etwa eine Sortierung und dergleichen. Den Index der betreffenden Spalte erhalten Sie ja über den Index des Control-Arrays:
Private Sub ColumnHeader_Click(Index As Integer)
ListView1.SetFocus
' Aktion für Spalte Nr. 'Index'
End Sub
Eine andere Möglichkeit zum Erhalt eigener Spaltenköpfe bietet die Verwendung einer StatusBar. Diese muss ja nicht unbedingt am unteren Rand eines Forms angedockt sein, sondern kann auch frei positioniert werden (Align-Eigenschaft auf '0 - vbAlignNone' setzen). Für jede Spalte wird ein Panel in der entsprechenden Breite angelegt und mit dem Text der Spalte beschriftet. Die Eigenschaft Bevel der Panels wird auf sbrRaised (erhaben) eingestellt:
Public Sub LvwFixColumnHeaders2(ListView As ListView, _
ColumnHeaders As StatusBar)
Dim i As Integer
Dim nPanel As Panel
With ListView
.HideColumnHeaders = True
ColumnHeaders.ZOrder 0
ColumnHeaders.Align = vbAlignNone
ColumnHeaders.Top = .Top - Screen.TwipsPerPixelY
.Height = .Height - 14 * Screen.TwipsPerPixelY
.Top = .Top + 14 * Screen.TwipsPerPixelY
ColumnHeaders.Height = 18 * Screen.TwipsPerPixelY
ColumnHeaders.Left = .Left + 2 * Screen.TwipsPerPixelX
ColumnHeaders.Width = .Width
With .ColumnHeaders
ColumnHeaders.Panels(1).Text = .Item(1).Text
ColumnHeaders.Panels(1).Width = .Item(1).Width
For i = 2 To .Count
Set nPanel = ColumnHeaders.Panels.Add(, , .Item(i).Text)
nPanel.Width = .Item(i).Width - Screen.TwipsPerPixelX
nPanel.Bevel = sbrRaised
Next 'i
End With
End With
End Sub
Das sieht zwar nicht mehr ganz so aus wie beim Original, aber doch irgendwie eleganter und feiner. Zudem könnte die feinere Optik dem Anwender nebenbei auch signalisieren, dass die Spaltenbreiten nun nicht mehr manipulierbar sind.
Den optischen Klick-Effekt auf einen Spaltenkopf erhalten Sie, indem Sie im MouseDown-Ereignis des StatusBars die Bevel-Eigenschaft des betroffenen Panels auf sbrInset setzen, und im nachfolgenden MouseUp-Ereignis wieder auf sbrRaised zurück setzen:
Private Sub ColumnHeaders_MouseDown(Button As Integer, _
Shift As Integer, x As Single, y As Single)
Dim i As Integer
With ColumnHeaders
For i = 1 To .Panels.Count
Select Case x
Case .Panels(i).Left To .Panels(i).Left + _
.Panels(i).Width
.Panels(i).Bevel = sbrInset
.Tag = i
Exit For
End Select
Next
End With
End Sub
Private Sub ColumnHeaders_MouseUp(Button As Integer, _
Shift As Integer, x As Single, y As Single)
Dim nPanelIndex As Integer
With ColumnHeaders
nPanelIndex = .Tag
.Panels(nPanelIndex).Bevel = sbrRaised
End With
End Sub
Die Aktionsmöglichkeit erhalten Sie über die Ereignisse PanelClick bzw. sogar PanelDblClick:
Private Sub ColumnHeaders_PanelClick _
(ByVal Panel As MSComctlLib.Panel)
' Aktion für Spalte Nr. 'Panel.Index'
End Sub
Private Sub ColumnHeaders_PanelDblClick _
(ByVal Panel As MSComctlLib.Panel)
' Aktion für Spalte Nr. 'Panel.Index'
End Sub
Einen kleinen Haken haben diese Spaltenkopf-Alternativen allerdings: Die Spaltenköpfe können nicht mitrollen, wenn das ListView horizontal gerollt wird. Dies zu berücksichtigen würde den Aufwand erheblich erhöhen. Wenn Sie jedoch mit festen Spalten, die sich alle im sichtbaren Bereich befinden, zufrieden sein können, stellen die beiden vorgestellten Alternativen bestimmt eine schlichte, effektive Lösung dar.
|