#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/gdicmn.h> // wxPointに必要
#include <wx/frame.h> // wxFrameに必要
// wxBufferedPaintDC のinclude
#include <wx/dcbuffer.h>
/////////////////////////////////////
/////////////////////////////////////
/////////////////////////////////////
#include <string>
#include <memory>
#include <unordered_map>
// リストボックスが一度に表示可能なアイテム数を取得
int GetVisibleItemCount(wxListBox * listBox)
{
// リストボックスのDCを使って一行の高さを取得し
// リストボックスのクライアントサイズから表示可能なアイテム数を計算する
// リストボックスのクライアントサイズを取得
wxSize clientSize = listBox->GetClientSize();
// wxClientDCを使用してデフォルトのアイテム高さを取得
wxClientDC dc(listBox);
wxCoord textWidth, textHeight;
// 指定した文字列の幅と高さを取得
dc.GetTextExtent("TEXT", &textWidth, &textHeight);
// 表示可能なアイテム数を計算
int visibleItemCount = clientSize.GetHeight() / textHeight;
return visibleItemCount;
}
// スクロールバー付きリスト
class ExList : public wxPanel {
int itemCount = 100; // アイテム数
int visibleItemCount;// 一度に表示できるアイテム数
wxBoxSizer* mainSizer;
wxScrollBar* scrollBar;
// リストコントロール
wxListBox* listBox;
void PostCreate() {
visibleItemCount = GetVisibleItemCount(listBox);
// スクロールバーの範囲とサムサイズを設定
scrollBar->SetScrollbar(0, visibleItemCount, itemCount, 5, true);
disp();
}
public:
// コンストラクタ
ExList(wxWindow* parent) : wxPanel(parent, wxID_ANY) {
// メインSizer
mainSizer = new wxBoxSizer(wxHORIZONTAL);
this->SetSizer(mainSizer);
// リストコントロール
listBox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr);
mainSizer->Add(listBox, 1, wxEXPAND | wxALL, 5);
// スクロールバー
scrollBar = new wxScrollBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL);
mainSizer->Add(scrollBar, 0, wxEXPAND | wxALL, 5);
this->Layout();
CallAfter(&ExList::PostCreate);
// スクロールバーのイベント
scrollBar->Bind(wxEVT_SCROLL_PAGEUP, &ExList::OnScrollPageUp, this);
scrollBar->Bind(wxEVT_SCROLL_PAGEDOWN, &ExList::OnScrollPageDown, this);
scrollBar->Bind(wxEVT_SCROLL_THUMBTRACK, &ExList::OnScrollThumbTrack, this);
scrollBar->Bind(wxEVT_SCROLL_LINEUP, &ExList::OnScrollUp, this);
scrollBar->Bind(wxEVT_SCROLL_LINEDOWN, &ExList::OnScrollDown, this);
// サイズイベント
this->Bind(wxEVT_SIZE, &ExList::OnSize, this);
}
void disp() {
listBox->Clear();
int offset = scrollBar->GetThumbPosition();
// デバッグにposを表示
std::string debugMessage = "pos: " + std::to_string(offset) + "\n";
OutputDebugStringA(debugMessage.c_str());
/////////////////////////////////////////////
// 現在の表示範囲のアイテムを追加
for (int i = 0; i < visibleItemCount; i++) {
int item_id = offset + i;
// 番外のアイテムは *** で表示
if (item_id >= itemCount) {
listBox->Append("***");
continue;
}
listBox->Append(wxString::Format("Item %d", item_id));
}
}
void OnScrollPageUp(wxScrollEvent& event) {
disp();
}
void OnScrollPageDown(wxScrollEvent& event) {
disp();
}
void OnScrollThumbTrack(wxScrollEvent& event) {
disp();
}
// 下方向クリック
void OnScrollDown(wxScrollEvent& event) {
disp();
}
// 上方向クリック
void OnScrollUp(wxScrollEvent& event) {
disp();
}
void OnSize(wxSizeEvent& event) {
// イベントを処理済みにする
event.Skip();
}
};
// ウィンドウ作成
class MyFrame : public wxFrame
{
wxBoxSizer* mainSizer;
ExList* exList; // スクロールバー付きリスト
public:
void PostCreate() {
this->Layout(); // レイアウトの更新
}
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame(NULL, wxID_ANY, title, pos, size)
{
// メインSizer
mainSizer = new wxBoxSizer(wxHORIZONTAL);
this->SetSizer(mainSizer);
// リストコントロール
exList = new ExList(this);
mainSizer->Add(exList, 1, wxEXPAND | wxALL, 5);
// CallAfter : 現在処理中のイベントが終わったらPostCreateを実行
// コンストラクタはウィンドウ生成イベント扱い
CallAfter(&MyFrame::PostCreate);
}
private:
};
/////////////////////////////////////
/////////////////////////////////////
/////////////////////////////////////
// wxWidgetsのアプリケーション作成
class MyApp : public wxApp {
public:
virtual bool OnInit() {
MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340));
frame->Show(true);
return true;
}
};
/////////////////////////////////////
/////////////////////////////////////
/////////////////////////////////////
// WinMainをマクロで定義
wxIMPLEMENT_APP(MyApp);