3つあるListBoxのスクロール(TopIndexの増減)を同時に行おうと
スクロールバーのPosionを使って下記のようにしました。
ListBox1.TopIndex := ScrollBar1.Position;
ListBox2.TopIndex := ScrollBar1.Position;
ListBox3.TopIndex := ScrollBar1.Position;
(イベントはスクロールバーのOnChangeです)
ですが、1回目のスクロールの際
ListBox1からListBox3まで順番にカタンカタンカタンといった感じに
スクロールしてしまいます。
2回目以降のスクロールでは3つとも同時にスクロールしてくれるのですが
どうしても1回目だけが同時にスクロールしてくれなくて困っています。
あと上ではスクロールバーを使っていますが
ListBoxに表示されるスクロールバーを使って同じことができないでしょうか?
ListBoxでのスクロールバーのOnChangeに当たるイベントが分かりません。
宜しくお願いいたします。
ちょっと裏技的ですが、こんな方法もあります。
procedure TForm1.ScrollBar1Change(Sender: TObject);
var
Value: integer;
begin
Value := ScrollBar1.Position;
// 描画の禁止
ListBox1.Perform(WM_SETREDRAW, 0, 0);
ListBox2.Perform(WM_SETREDRAW, 0, 0);
ListBox3.Perform(WM_SETREDRAW, 0, 0);
SendMessage(ListBox1.Handle, LB_SETTOPINDEX, Value, 0);
SendMessage(ListBox2.Handle, LB_SETTOPINDEX, Value, 0);
SendMessage(ListBox3.Handle, LB_SETTOPINDEX, Value, 0);
// 描画の許可(まだ描画しない)
ListBox3.Perform(WM_SETREDRAW, 1, 0);
ListBox2.Perform(WM_SETREDRAW, 1, 0);
ListBox1.Perform(WM_SETREDRAW, 1, 0);
// 再描画
ListBox3.Invalidate;
ListBox2.Invalidate;
ListBox1.Invalidate;
end;
失敗です。
スクロールバーまで再描画していませんでした。
# 最後までスクロールしてもスクロールバーは一番上のまま(実際は一番下)でした。
もうちっと調べます。
少しだけ改良。
何も考えずに作ったので、もっと簡単な方法があるかもしれません。
ScrollBarの更新部分で、もしかしたらTopIndexと同じ値ではダメかもしれません。
その場合は、GetScrollInfoで範囲を取得し、正しい値を入れてやってください。
procedure TForm1.ScrollBar1Change(Sender: TObject);
var
Value: integer;
begin
Value := ScrollBar1.Position;
// 描画の禁止
ListBox1.Perform(WM_SETREDRAW, 0, 0);
ListBox2.Perform(WM_SETREDRAW, 0, 0);
ListBox3.Perform(WM_SETREDRAW, 0, 0);
//値の設定
SendMessage(ListBox1.Handle, LB_SETTOPINDEX, Value, 0);
SendMessage(ListBox2.Handle, LB_SETTOPINDEX, Value, 0);
SendMessage(ListBox3.Handle, LB_SETTOPINDEX, Value, 0);
// 描画の許可(まだ描画しない)
ListBox3.Perform(WM_SETREDRAW, 1, 0);
ListBox2.Perform(WM_SETREDRAW, 1, 0);
ListBox1.Perform(WM_SETREDRAW, 1, 0);
// 再描画(スクロール部分は再描画されない)
InvalidateRect(ListBox1.Handle, nil, TRUE);
InvalidateRect(ListBox2.Handle, nil, TRUE);
InvalidateRect(ListBox3.Handle, nil, TRUE);
// スクロールバーを更新
SetScrollPos(ListBox1.Handle, SB_VERT, Value, TRUE);
SetScrollPos(ListBox2.Handle, SB_VERT, Value, TRUE);
SetScrollPos(ListBox3.Handle, SB_VERT, Value, TRUE);
end;
おーキレイにスクロールしてます!
このような方法があるんですね。
正直なところよく理解できてませんが・・・
今から、自分なりに消化して理解しようと思います。
やっぱりプログラム組むのは奥が深くて面白いです。
にしのさん、本当にありがとうございました。
Halbow です。
>あと上ではスクロールバーを使っていますが
>ListBoxに表示されるスクロールバーを使って同じことができないでしょうか?
ローカルフックで解決できます。新規で以下のコードを試してみてください。
3つの ListBox のどのスクロールバーを動かしても、他の二つが追随します。
矢印キーによるスクロールには対応していません。(できますが)
type
TForm1 = class(TForm)
ListBox1: TListBox;
ListBox2: TListBox;
ListBox3: TListBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private 宣言 }
public
procedure ProcessMessage(hWindow:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
var
Hook: HHOOK;
function CallWndRetProc(code:integer;wparam:WPARAM;lparam:LPARAM):LRESULT;stdcall;
var
pCWPR:PCWPRetStruct;
begin
if (code < 0) then begin
result := CallNextHookEx(Hook,code,wparam,lparam);
exit;
end;
if (Code = HC_ACTION) then begin
pCWPR := PCWPRetStruct(lParam);
Form1.ProcessMessage(pCWPR^.hwnd,pCWPR^.message,pCWPR^.wParam,pCWPR^.lParam);
end;
result := CallNextHookEx(Hook,code,wparam,lparam);
end;
procedure TForm1.ProcessMessage(hWindow:HWND;Msg:UINT;wParam:WPARAM;lParam:LPARAM);
begin
if Msg <> WM_VSCROLL then exit;
if hWindow = ListBox1.Handle then begin
ListBox2.Perform(Msg,wParam,lparam);
ListBox3.Perform(Msg,wParam,lparam);
end else
if hWindow = ListBox2.Handle then begin
ListBox1.Perform(Msg,wParam,lparam);
ListBox3.Perform(Msg,wParam,lparam);
end else
if hWindow = ListBox3.Handle then begin
ListBox1.Perform(Msg,wParam,lparam);
ListBox2.Perform(Msg,wParam,lparam);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Hook := SetWindowsHookEx(WH_CALLWNDPROCRET,CallWndRetProc,0,GetCurrentThreadID);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
UnHookWindowsHookEx(Hook);
end;
ツイート | ![]() |