![]() |
Mehrere Listboxen synchronisieren
Guten Morgen,
ich habe auf Basis eines älteren Forenbeitrags ein Prog geschrieben, bei dem zwei Listboxen immer synchron sind. Ich müsste das irgendwie so ergänzen, dass das auch mit drei oder mehr Listboxen klappt (haben alle immer exakt dieselbe Anzahl von items). Leider komme ich nicht weiter. Kann mir bitte jemand einen Tipp geben? Das ist der Code für zwei Listboxen:
Delphi-Quellcode:
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, StdCtrls; type TMyListbox = class(TListbox) private Fref : TCustomListbox; procedure WMMouseWheel (var Message: TWMMouseWheel); message WM_Mousewheel; procedure WMHScroll(var Message: TWMHScroll); message WM_HScroll; procedure WMVScroll(var Message: TWMVScroll); message WM_VScroll; public constructor Create(AOwner: TComponent); override; published property Reference: TCustomListbox read FRef write FRef; end; TForm1 = class(TForm) ListBox1: TListBox; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } LBox : TMyListbox; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); var i: Integer; begin Listbox1.Touch.InteractiveGestures := []; LBox := TMyListbox.Create(self); with LBox do begin Parent := self; visible := true; top := 8; Left := 248; Width := 217; Height := Listbox1.height; Reference := Listbox1; end; for i := 0 to 1000 do begin Listbox1.Items.Add(inttostr(i)); LBox.Items.Add(Inttostr(i)); end; end; constructor TMyListbox.Create(AOwner: TComponent); begin inherited; FRef := nil; end; procedure TMyListbox.WMMouseWheel(var Message: TWMMouseWheel); begin inherited; If Assigned(FRef) then FRef.TopIndex := Topindex; end; procedure TMyListbox.WMHScroll(var Message: TWMScroll); begin inherited; end; procedure TMyListbox.WMVScroll(var Message: TWMScroll); begin inherited; if assigned(FRef) then FRef.TopIndex := Topindex; end; procedure TForm1.FormDestroy(Sender: TObject); begin LBox.Free; end; end. |
AW: Mehrere Listboxen synchronisieren
Zitat:
Delphi-Quellcode:
Das ist eine Liste von ListBoxen, die kann man in einer Schleife durchlaufen. Oder man benutzt gleich das Observer-Pattern :-)
property References: TList<TCustomListbox> //oder auch TObjectList<TCustomListbox>
read FReferences; |
AW: Mehrere Listboxen synchronisieren
Wie wäre es ganz simpel mit einer Listview?
|
AW: Mehrere Listboxen synchronisieren
Eventuell kannst du ja auch mit einer einzigen Listbox, mit mehreren Spalten arbeiten, das geht eigentlich sehr elegant und du kannst sortieren etc. ohne etwas zu "verwirbeln" :-)
|
AW: Mehrere Listboxen synchronisieren
So:
Code:
Entsprechend dann für ListBox2.
if (Msg.Msg=WM_VSCROLL) then
begin i:=GetScrollPos(ListBox1.Handle, SB_VERT); PostMessage(ListBox2.Handle, WM_VSCROLL, MakeLong(LOWORD(SB_THUMBPOSITION), i), 0); Application.ProcessMessages; ... end else if (Msg.Msg=WM_MOUSEWHEEL) then begin i:=GetScrollPos(ListBox1.Handle, SB_VERT); PostMessage(ListBox2.Handle, WM_VSCROLL, MakeLong(LOWORD(SB_THUMBPOSITION), i), 0); Application.ProcessMessages; ... end; |
AW: Mehrere Listboxen synchronisieren
Vielen Dank Euch allen für die wertvollen Hinweise!
Die Vorschläge von Detlef und tomkupitz sind für einen Hobby-Feierabend-Programmierer wie mich starker Tobak, da muss ich mich erstmal reinfuchsen. (tomkupitz: wo würde Dein Code aufgerufen und was müsste bei den Platzhaltern "....." noch ergänzt werden?) Sebastian, danke für den Hinweis. Mit Listview hatte ich es schon mal versucht, hatte dabei aber den Eindruck gewonnen, dass die Listview eher zeilenmäßig aufgebaut ist mit Caption, item, subitem usw. Ich fand das auch derart unübersichtlich dass ich es wieder gelassen habe, aber vielleicht ist Listview in der Tat das Richtige. Das Problem bei Listview ist aber, dass ich immer nur ein paar Spalten brauche und die dann je nach Bedarf ein und ausschalten will (ich hätte die verschiedenen Listboxen dazu auf mehrere Seiten eines PageControls gepackt) Dacoda, ich wusste nicht, dass es mehrere Spalten in einer Listbox gibt und habe dazu auch nichts gefunden. Oder meintest Du eine Listview? LG, Stephan. |
AW: Mehrere Listboxen synchronisieren
Du legst eine TApplicationEvents-Komponente auf die Form. Im TApplicationEvents.OnMessage Event fängst du die Windows-Messages ab. Dann achtest du auf TMsg:
hwnd: HWND; ist die entsprechende ListBox (if ListBox1.Handle=hwnd then ...) message: UINT; ist die zugehörige Windows-Message (if message=WM_VSCROLL oder message=WM_MOUSEWHEEL then) Die Pünktchen bedeuten erstmal garnichts. |
AW: Mehrere Listboxen synchronisieren
Zitat:
Zitat:
Ich würde dir zur ![]() Zitat:
![]() |
AW: Mehrere Listboxen synchronisieren
Zitat:
Inzwischen habe ich aber eine Lösung mit Listboxen gefunden, die ich Euch nicht vorenthalten möchte. Bisschen pfuschig vielleicht, funktioniert aber:
Delphi-Quellcode:
private
procedure SyncLBs(Sender: TObject; var Done: Boolean); { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; activelb: Integer; implementation {$R *.dfm} procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean); var i: Integer; wnd: hwnd; begin wnd := msg.hwnd; if listbox1.handle = wnd then activelb := 1 else if listbox2.handle = wnd then activelb := 2 else if listbox3.handle = wnd then activelb := 3; end; procedure TForm1.SyncLBs(Sender: TObject; var Done: Boolean) ; var lb: TListBox; begin if activelb = 1 then begin Listbox2.TopIndex:= listbox1.TopIndex; Listbox3.TopIndex:= listbox1.TopIndex; end else if activelb = 2 then begin listbox1.TopIndex:= Listbox2.TopIndex; Listbox3.TopIndex:= listbox2.TopIndex; end else if activelb = 3 then begin listbox1.TopIndex:= Listbox3.TopIndex; Listbox2.TopIndex:= listbox3.TopIndex; end else end; procedure TForm1.FormCreate(Sender: TObject); var i: Integer; begin Application.OnIdle := SyncLBs; end; |
AW: Mehrere Listboxen synchronisieren
Für die globale Variable bekommst'e erstmal den Popo verhauen.
Wieso hörst du nicht auf den Compiler? z.B. [dcc32 Hinweis] H2164 Variable 'i' wurde deklariert, aber in 'TForm1.FormCreate' nicht verwendet Warum einmal OnMessage über TApplicationEvents auf der Form, aber dann abweichend OnIdle über das globale Application? Wenn, dann am Besten beides einheitlich über TApplicationEvents.
Delphi-Quellcode:
oder einfach alles direkt und umgehend
public
ActiveLB: TListBox; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean); begin if ListBox1.Handle = msg.hwnd then ActiveLB := ListBox1 else if ListBox2.Handle = msg.hwnd then ActiveLB := ListBox2 else if ListBox3.Handle = msg.hwnd then ActiveLB := ListBox3; end; procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean); begin if Assigned(ActiveLB) then begin if ActiveLB <> ListBox1 then ListBox1.TopIndex := ActiveLB.TopIndex; if ActiveLB <> ListBox2 then ListBox2.TopIndex := ActiveLB.TopIndex; if ActiveLB <> ListBox3 then ListBox3.TopIndex := ActiveLB.TopIndex; ActiveLB := nil; // einmal abgearbeitet, dann abschalten, sonst triggert sich das auf ewig immer wieder selbst. // in LB1 scrollen löst Scrollen in LB2 und LB3 aus, was wiederum Messages in diesen auslöst usw. // Du hast echt Glück, dass im Setter von TopIndex ein "if GetTopIndex <> Value then" steht und es schnell endet // // PS: also können die "if ActiveLB <> ListBox1 then" weg (ähnlich dem nachfolgenden Beispiel) end; end;
Delphi-Quellcode:
oder am Besten garnicht ganz global, sondern direkt nur in den ListBoxen, also anstatt OnMessage
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
var C: TWinControl; //L: TListBox absolute C; begin C := FindControl(msg.hwnd); if (C is TListBox) and C.Focused then begin // bzw. falls weitere ListBoxen :: if C.Focused and ((C = ListBox1) or (C = ListBox2) or (C = ListBox3)) then //if (ListBox1 <> L) and (ListBox1.TopIndex <> L.TopIndex) then ListBox1.TopIndex := L.TopIndex; //if (ListBox2 <> L) and (ListBox2.TopIndex <> L.TopIndex) then ListBox2.TopIndex := L.TopIndex; //if (ListBox3 <> L) and (ListBox3.TopIndex <> L.TopIndex) then ListBox3.TopIndex := L.TopIndex; // jupp, die Prüfungen weg, siehe Setter von TopIndex ListBox1.TopIndex := TListBox(C).TopIndex; ListBox2.TopIndex := TListBox(C).TopIndex; ListBox3.TopIndex := TListBox(C).TopIndex; end; end;
Delphi-Quellcode:
type
TListBox = class(Vcl.StdCtrls.TListBox) protected // im StandardHandler // WM_VSCROLL // CN_VSCROLL procedure WndProc(var Message: TMessage); override; // oder gezielt die gewünschte(n) Message(s) und Notification(s) procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL; // oder CN_VSCROLL end; TForm1 = class(TForm) ListBox1: TListBox; ListBox2: TListBox; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz