|
![]() |
MathiasSimmack
Quasi als DP-Exklusivveröffentlichung (wenn ihr so wollt) gibt´s hier die VCL-Variante der o.g. neuen XP-Gimmicks. Meine Ausführungen beziehen sich aber hauptsächlich auf Delphi vor Version 7. Ich nehme an bzw. hoffe, dass D7 diese Neuheiten bereits eingebaut hat. Also zeige ich hier, wie Besitzer von Delphi 5 (wie in meinem Fall) diese neuen Sachen nutzen können.
Für alle, deren Delphi nicht aktuell genug ist, liegt im Anhang meine Unit "CommCtrl_Fragment.pas", die die notwendigen Deklarationen usw. enthält. Sie ist kein Ersatz für die CommCtrl von Borland; sie ist also zusätzlich anzugeben! Achtung! Für alle drei Sachen, die nachfolgend besprochen werden, ist die Manifestdatei erforderlich! Das gilt auch, wenn man WinXP im Klassik-Look laufen lässt. Sagt hinterher nicht, ich hätte es nicht erwähnt. Das Manifest, ob nun beiliegend (Dateiname.exe.manifest) oder in den Ressourcen, sorgt dafür, dass die Common Controls 6.0 benutzt werden. Und nur damit funktioniert alles! |
MathiasSimmack |
MathiasSimmack
|
#2
Um z.B. den neuen Tile-Modus nutzen zu können, solltet ihr unter Win XP nach Möglichkeit die neue Nachricht "LVM_SETVIEW" bzw. die Funktion "ListView_SetView" benutzen, für die es die folgenden Werte gibt:
Code:
Also, z.B.
LV_VIEW_ICON
LV_VIEW_SMALLICON LV_VIEW_LIST LV_VIEW_DETAILS LV_VIEW_TILE ListView_SetView(lv1.Handle,LV_VIEW_TILE); Ich sag´s lieber noch einmal: A) diese Anweisung funktioniert nur unter Windows XP, und B) auch nur, wenn ein Manifest für die Common Controls 6.0 vorhanden ist. Soll eure Anwendung also unter allen Windows-Version laufen, unter XP aber diese zusätzlichen Features benutzen, dann müsst ihr (Non-VCL) sowohl den alten als auch den eben gezeigten neuen Weg zum Wechseln der Ansicht einbauen. Ich hoffe, Delphi 7 unterstützt (wenn überhaupt) beides, so dass es mit der D7-VCL leichter ist. Zu Nachricht und Funktion gibt es natürlich auch die Gegenstücke: "LVM_GETVIEW" und "ListView_GetView", mit denen man ermitteln kann, welche Ansicht momentan aktiv ist. |
![]() |
MathiasSimmack
|
#3
Das einfachste zuerst: Ihr kennt sicher den Effekt aus dem Explorer von Windows XP, bei dem die aktuelle Spalte grau markiert wird. Dazu ist keine Zeichenfunktion erforderlich, das OS stellt mit der Nachricht "LVM_SETSELECTEDCOLUMN" (bzw. "ListView_SetSelectedColumn") die notwendige Funktionalität zur Verfügung.
Man übergibt lediglich den Index der gewünschten Spalte; beim Start des Programms bspw.: ListView_SetSelectedColumn(TListview1.Handle,0); Wenn man eine Sortierfunktion hat, bietet sich natürlich das "OnColumnClick"-Ereignis an, um die Spaltenmarkierung zu wechseln:
Delphi-Quellcode:
Anders herum geht´s auch: mit "LVM_GETSELECTEDCOLUMN" oder "ListView_GetSelectedColumn" könnt ihr ermitteln, welche Spalte sozusagen den Fokus hat.
procedure TForm1.lv1ColumnClick(Sender: TObject; Column: TListColumn);
begin { ... sortieren ... } // sortierte Spalte kennzeichnen ListView_SetSelectedColumn(lv1.Handle,Column.Index); end; Soviel dazu. |
![]() |
MathiasSimmack
|
#4
Der Tile-Modus ist ebenfalls aus dem Explorer bekannt. Man sieht dabei das Icon, und rechts daneben steht der Dateiname, und darunter (abhängig vom Typ) noch zusätzliche Infos. Zur Benutzung müssen wir der List-View erst mitteilen, wie wir uns den Kachelmodus vorstellen. Dazu gibt´s das Record TLVTileViewInfo, das wir am besten im "OnCreate" der Form füllen:
Delphi-Quellcode:
Wichtig erscheint mir diese Zeile:
procedure TForm1.FormCreate(Sender: TObject);
var tileview : TLVTileViewInfo; // CommCtrl_Fragment.pas begin // Recordgröße initialisieren tileview.cbSize := sizeof(TLVTileViewInfo); // was wollen wir beeinflussen? die Anzahl der zusätzlichen Zeilen tileview.dwMask := LVTVIM_COLUMNS; // die Tiles sollen sich möglichst automatisch anpassen tileview.dwFlags := LVTVIF_AUTOSIZE; // wie viele zusätzliche Zeilen sollen es denn sein? tileview.cLines := 2; // und ab damit zur List-View ListView_SetTileViewInfo(lv1.Handle,tileview); end; tileview.cLines := 2; Damit wird der List-View mitgeteilt, wie viele zusätzliche Zeilen im Kachelmodus zu sehen sein sollen. Das bedeutet: zusätzlich zum Itemnamen (TListItem.Caption), der ja sowieso und in jedem Darstellungsmodus angezeigt wird! Nehmen wir als Beispiel einen kleinen Explorer, der die Dateien des aktuellen Ordners anzeigt. Im Reportmodus zeigt er außerdem in der Spalte #1 die Dateigröße und in Spalte #2 das Datum. Was wir davon im Kachelmodus sehen, hat ursächlich mit diesen Spalten im Reportmodus zu tun. Anzumerken ist noch, dass der Kachelmodus für jedes Item separat eingestellt werden muss. Das hört sich umständlich an, bietet aber auch den Vorteil, die Ansicht direkt zu beeinflussen. Ich zeige ein Mini-Beispiel aus dem "OnCreate" der Form:
Delphi-Quellcode:
Wichtig hierbei ist diese Anweisung:
res := FindFirst(ExtractFilePath(paramstr(0)) + '*.*',
faAnyFile,ds); while(res = 0) do begin if(ds.Attr and faDirectory = 0) then begin // wie gehabt, füllen wir die List-View lv := lv1.Items.Add; lv.Caption := ds.Name; lv.ImageIndex := 0; lv.SubItems.Add(inttostr(ds.Size) + ' Bytes'); lv.SubItems.Add(FormatDateTime('',FileDateToDateTime(ds.Time))); // JETZT KOMMT DER TILE-MODUS --> // wir initialisieren das TLVTileInfo-Record tile.cbSize := sizeof(TLVTileInfo); // welches Item ist´s? tile.iItem := lv1.Items.Count - 1; // wie viele zusätzliche Zeilen sollen es für // dieses spezielle Item sein? tile.cColumns := 2; // welche Spalten sollen angezeigt werden? tile.puColumns := @ca[0]; // an die List-View übergeben ListView_SetTileInfo(lv1.Handle,tile); end; res := FindNext(ds); end; FindClose(ds); tile.puColumns := @ca[0]; "ca" ist dabei ein Integer-Array, das die Indexwerte der anzuzeigenden Spalten enthält:
Delphi-Quellcode:
Wenn wir davon ausgehen, dass -wie oben erwähnt!- die erste Spalte die Dateigröße und die zweite das Datum enthält, dann würden wir im Tile-Modus also auch unter dem Dateinamen erst die -größe und dann das Datum sehen. Tauschen wir die Angabe um, etwa
var
ca : array[0..1]of integer = (1,2);
Delphi-Quellcode:
dann sähen wir erst das Datum und dann die Größe. Abhängig von den Spalten, die ihr im Reportmodus habt (oder generell: falls ihr versteckte Subitems habt, die in keiner Spalte auftauchen!), könnt ihr mit dem Array beeinflussen, was im Tile-Modus zu sehen sein soll.
var
ca : array[0..1]of integer = (2,1); That's all. (PS: Fehler mit "Code" vs. "Delphi" im Text gefixt.) |
![]() |
MathiasSimmack
|
#5
Das Schwierigste zuletzt; ´s hat mich auch am meisten Nerven gekostet. Das Wichtigste hierbei ist, dass man die Gruppen (leider) selbst bilden muss. Diese Arbeit nimmt einem das System nicht ab. Die WinXP-Benutzer unter euch kennen den Effekt, den ich persönlich für recht nützlich halte. Aktiviert im Explorer einfach mal die Option "in Gruppen anzeigen".
Der Explorer sortiert die Dateien dann z.B. alfabetisch. Klickt ihr aber auf die Spalte mit der Dateigröße, dann heißen die Gruppen plötzlich "Sehr klein", "Klein", usw., und die Dateien werden entsprechend zugeordnet. All das muss man, wie gesagt!, selbst machen. Auf der anderen Seite hat man dadurch die Freiheit, die Gruppen an die jeweilige Anwendung anzupassen. Ich erstelle als Beispiel eine einzige Gruppe, der alle Dateien zugeordnet werden. Dazu brauchen wir das Record TLVGroup, das auch erst mal initialisiert werden muss: group.cbSize := sizeof(TLVGroup); Da wir einen Gruppennamen und eine ID für die Gruppe vergeben (müssen), sind die entsprechenden Flags zu setzen: group.mask := LVGF_HEADER or LVGF_GROUPID; Nun kommt der Name unserer Gruppe, der als PWideChar zu übergeben ist:
Delphi-Quellcode:
Und die ID unserer Gruppe:
group.pszHeader := pwidechar(widestring('Testgruppe'));
group.cchHeader := lstrlenW('Testgruppe'); group.iGroupId := 1; Das ganze reichen wir an die List-View weiter, wobei wir als zweiten Parameter (laut PSDK: Itemindex) -1 angeben, damit die neue Gruppe an das Ende des internen Gruppenarrays der List-View gesetzt wird: ListView_InsertGroup(lv1.Handle,-1,group); Nun müssen die Items noch irgendwie in die Gruppe rein. Ich hatte meine ersten Versuche dazu mit der Nachricht "LVM_MOVEITEMTOGROUP" (respektive "ListView_MoveItemToGroup") begonnen, aber diese Nachricht hat entweder einen vollkommen anderen Sinn, oder sie funktioniert nicht. Tatsächlich brauchen wir das erweiterte TLVItem-Record, das man im PSDK und in der Unit "CommCtrl_Fragment.pas" (s. Anhang im ersten Beitrag) finden kann. Dieses erweiterte Record besitzt u.a. die neue Membervariable iGroupId, die wir nun brauchen. Das heißt, wir nehmen eine for-Schleife und laden nacheinander alle Items der List-View:
Delphi-Quellcode:
Bitte nicht wundern: um Probleme mit dem Originalrecord zu vermeiden, habe ich in meiner Unit den erweiterten Typ als TVLItem60 deklariert.
for i := 0 to lv1.Items.Count - 1 do begin
// Record leeren ZeroMemory(@lv60,sizeof(TLVItem60)); // Flag setzen, weil wir die Gruppen-ID ändern wollen lv60.mask := LVIF_GROUPID; // von welchem Item? lv60.iItem := i; // wie lautet die ID? lv60.iGroupId := 1; // und ab dafür SendMessage(lv1.Handle,LVM_SETITEM,0,LPARAM(@lv60)); end; So, nun können wir die Gruppenansicht einschalten. Dazu gibt´s "LVM_ENABLEGROUPVIEW" bzw. die Funktion:
Delphi-Quellcode:
Diese Funktion zeigt auch gleich noch das toggeln der Ansicht mit Hilfe von "ListView_IsGroupViewEnabled" (bool-Funktion).
ListView_EnableGroupView(lv1.Handle,
not ListView_IsGroupViewEnabled(lv1.Handle)); Ja, das war´s auch schon. Ich bitte um Verständnis, dass ich ein paar Sachen für das nächste Update der Win32-API-Tutorials aufgehoben habe. Dort zeigt euch die neue List-View-Demo dann, wie man z.B. mehrere Gruppen erstellt, wie man prüft, ob es eine Gruppe evtl. schon gibt, und wie man die Gruppen ändert, wenn man die Items nach anderen Kriterien sortieren lässt. Wer nicht so lange warten möchte, hier die Kurzform für die alfabetische Sortierung:
Gruß, und viel Spaß damit. Mathias. |
![]() |
Delphi 2006 Professional |
#6
Pack ruhig noch ein paar Screenshots rein, damit die Leute auch wissen, von was du redest.
Michael
|
![]() |
MathiasSimmack
|
#7
Hier also ein Screenshot, der sowohl den Tile-Modus als auch die Gruppierung von Items zeigt:
[i]Bild Link auf Wunsch entfernt, da Bild nicht mehr vorhanden. Wie gesagt, es handelt sich dabei um eine normale List-View. Es ist keine spezielle Komponente. Einzig WinXP läuft, und die Anwendung benutzt eine Manifest-Ressource. [edit=Luckie]Bild Link entfernt. Mfg, Luckie[/edit] |
![]() |
|
#8
Weiß irgendwer ob man den Group - View Style auch auf Virtuelle Listviews anwenden kann? d.h. wenn man LVS_OWNERDATA setzt und die OnDispInfo Notification abfängt?
Bei mir scheint die LVM_ENABLEGROUPVIEW hierbei nicht zu funktionieren! danke im vorraus .. stefan mairhofer |
![]() |
Delphi 7 Personal |
#9
Hi,
Ich habe das nun mal Versucht in Delphi 7 mit XPMan Komponente und VCL umzusetzen. Das Hervorheben von Spalten funktioniert wunderbar. Allerdings die Gruppenansicht verweigert komplett die Darstellung.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var i:integer; group:TLVGroup; lvItem: TLVItem60; begin SetLength(dataset, 0); for i:=0 to 99 do begin SetLength(dataset, length(dataset)+1); dataset[length(dataset)-1].Name:='Wert '+inttostr(i+1); dataset[length(dataset)-1].Value:=AValue(random(10)+10, 0); dataset[length(dataset)-1].Mode:=random(2)+1; end; lv.Items.Count:=length(Dataset); // Spalte Name Grau hinterlegen ListView_SetSelectedColumn(lv.Handle,1); // Gruppen "Modus 1" anlegen group.cbSize := sizeof(TLVGroup); group.mask := LVGF_HEADER or LVGF_GROUPID; group.pszHeader := pwidechar(widestring('Modus 1')); group.cchHeader := lstrlenW('Modus 1'); group.iGroupId := 1; ListView_InsertGroup(lv.Handle,-1,group); // Gruppe speichern // Items den Gruppen zuordnen for i := 0 to lv.Items.Count - 1 do begin // Record leeren ZeroMemory(@lvItem,sizeof(TLVItem60)); // Flag setzen, weil wir die Gruppen-ID ändern wollen lvItem.mask := LVIF_GROUPID; // von welchem Item? lvItem.iItem := i; if Dataset[i].Mode = 1 then begin// wie lautet die ID? lvItem.iGroupId := Dataset[i].Mode; end; // und ab dafür SendMessage(lv.Handle,LVM_SETITEM,0,LPARAM(@lvItem)); end; // Gruppen aktivieren ListView_EnableGroupView(lv.Handle, true); lv.Repaint; end; Gibt es dafür einen Grund? Vielen Dank schonmal für jede Antwort. Suche schon ewig nach dieser Darstellungsart. |
![]() |
CCRDude
|
#10
Ist zwar schon ein etwas älterer Beitrag, aber da ich heute gerade nach längerer Suche drüber gestolpert bin und hier die Screenshots inzwischen fehlen, und mir das perfekt für das erste Rumspielen mit einem class helper erschien, hab ich mal eben zwei davon zusammengeschustert und mitsamt Screenshots hier angehängt.
Funktionabel ab BDS X (hier Version einsetzen, ab der es class helper gibt... 2005 oder 2006?), alternativ stehen zumindest 8 Wrapper-Funktionen für dieselben Aktionen zur Verfügung. Die CommCtrl_Fragment.pas ist ebenfalls noch nötig, wollte nicht so frech sein und die als meine Arbeit ausgeben, ich habs ja bloß nochmal in Schönschrift abgeschrieben ![]() Beispiel für die Anwendung:
Delphi-Quellcode:
procedure TForm1.AddSomeGroupedThings;
begin ListView1.AddGroup('Eigene Dateien', 1); // neu ListView1.AddGroup('Downloads', 2); ListView1.ViewStyleEx := vsTile; // neu with ListView1.Items.Add do begin Caption := 'Hallo Welt.txt'; GroupId := 1; // neu SetMinimumSubItemCount(2, '?'); // neu SubItems[0] := '11 B'; SubItems[1] := IntToStr(GroupId); SetTileViewColumns(2, [1]); // neu end; with ListView1.Items.Add do begin Caption := 'snlListView.pas'; GroupId := 1; SetMinimumSubItemCount(2, '?'); SubItems[0] := '10 KB'; SubItems[1] := IntToStr(GroupId); SetTileViewColumns(2, [1]); end; with ListView1.Items.Add do begin Caption := 'Screenshot.png'; GroupId := 2; SetMinimumSubItemCount(2, '?'); SubItems[0] := '183 KB'; SubItems[1] := IntToStr(GroupId); SetTileViewColumns(2, [1]); end; ListView1.TileViewLines := 1; // neu ListView1.GroupViewEnabled := true; // neu end; |
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |