Microsoft Visual C++ 2008 で、恐らく最良解決な2つのListViewの同期スクロール
System::Windows::Forms::ListViewには、2つのListViewの同期スクロール機能がありません。
そこで、ListViewを継承してカスタムコントロールを作るわけですが、スクロールイベントを拾っても、どこかで動作がおかしかったり、うまく同期しなかったりと、腹を立てることになります。
というわけで、Viewプロパティが、System::Windows::Forms::View::Details限定ならば、次のようなコードでうまく動作するという事例をご紹介(納品した製品でうまく動いているのでOKだと思います)。
#pragma once #define WIN32_LEAN_AND_MEAN #pragma comment(lib, "user32.lib") #include <windows.h> #include <CommCtrl.h> using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Collections::Generic; using namespace System::Windows::Forms; namespace MyControls { public ref class MyListView : public System::Windows::Forms::ListView { public: // コンストラクタ MyListView() { View = System::Windows::Forms::View::Details; // Details限定 mVScrollSynchronizedListView = nullptr; mOldScrollY = 0; mSyncScroll = false; } // 垂直スクロールを同期させるリストビュー [CategoryAttribute("特殊")] [DescriptionAttribute("垂直スクロールを同期させるリストビューを指定します")] property MyListView^ VScrollSynchronizedListView { MyListView^ get() { return mVScrollSynchronizedListView; } void set(MyListView^ x) { mVScrollSynchronizedListView = x; } } // 垂直スクロールの旧位置 [BrowsableAttribute(false)] property int OldScrollY { int get() { return mOldScrollY; } void set(int x) { mOldScrollY = x; } } // 連動スクロール開始 [BrowsableAttribute(false)] property bool SyncScroll { bool get() { return mSyncScroll; } void set(bool x) { mSyncScroll = x; } } protected: // 連動スクロール用イベント処理 virtual void WndProc(Message %m) override { ListView::WndProc(m); if(mSyncScroll && m.Msg==WM_PAINT) { SCROLLINFO si; ZeroMemory(&si,sizeof(SCROLLINFO)); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS; if(Items->Count && ::GetScrollInfo((HWND)Handle.ToPointer(),SB_VERT,&si)) { if(mOldScrollY!=si.nPos) { if(mVScrollSynchronizedListView) { int dx = 0; int dy = (si.nPos - mOldScrollY) * Items[0]->Bounds.Height; mVScrollSynchronizedListView->OldScrollY = si.nPos; ::SendMessage((HWND)mVScrollSynchronizedListView->Handle.ToPointer(),LVM_SCROLL,(WPARAM)dx,(LPARAM)dy); } } mOldScrollY = si.nPos; } } } private: MyListView^ mVScrollSynchronizedListView; bool mSyncScroll; int mOldScrollY; }; }
もう、描画イベントを全部キャプチャして無理矢理スクロールしてしまえということです。
このコントロールをフォームに2つ貼り付けて…。
listView1->VScrollSynchronizedListView = listView2; listView2->VScrollSynchronizedListView = listView1; listView1->SyncScroll = true; listView2->SyncScroll = true;
とすれば、listView1とlistView2の垂直スクロールが同期します。
勿論、水平スクロールの同期もこのコードをちょっと改造すれば対応可能です。