このサイトでは、分析、カスタマイズされたコンテンツ、および広告に Cookie を使用します。このサイトを引き続き閲覧すると、Cookie の使用に同意するものと見なされます。
Hi, Developers,
straightapps.com ロゴ
作成 December 17, 2022、一部更新 May 16, 2024
トップページ > Windows トップ > リストボックスの横スクロールバーを実装する
line
Windows 開発
line

ここでは、リストボックスの横スクロールバーを実装する方法について、書いています。

Natural Intelligence による記事要点まとめ
・横スクロールバーを有効にするため、まずプロパティを設定する。
・横スクロールバーを表示するため、設定を行う。
・適切なサイズでスクロールさせるため、内容のサイズを計算する。

Visual C++ でダイアログを作成し、リストボックスを設置しても、プロパティ設定だけでは 横スクロールができません ( できそうな名前のプロパティがありますので、余計に混乱します。 ) 。 文字が右にはみだしても、横スクロールバーは自動表示されることはなく、表示できてもグレーのまま有効にはなりません

SetHorizontalExtent 関数 で横幅を指定することで横スクロールバーを有効にすることはできますが、 設定された文字列の長さに合わせて変更されることはなく、 設定する値によってはスクロールが不足してテキストの末尾まで見えなかったり、 あるいはスクロールが多すぎて右側に広い空白ができてしまったりします。

ここではこの問題を解決する方法について検討しています。

アイコン リストボックスの文字サイズやフォントを変える
Visual C++ では、リストボックスの文字サイズをプロパティで変更することはできません。 ここでは自由な文字サイズに変更したり、別のフォントにしたりしています。



コードは Windows 10、Visual Studio 2022 で作成、確認したものです。 MFC ( Microsoft Foundation Class、マイクロソフトが提供する、便利なクラスライブラリです。 ) のクラスを使用していますが、MFC を使用しなくても同様のコードに置き換えれば動作すると思います。

▼ セクション一覧

横スクロールバーを表示させる
横スクロールバーを有効にする
テキストの長さを調べて調整する

なお、本サイトのご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。


横スクロールバーを表示させる

投稿 December 17, 2022

とりあえず横スクロールバーを表示できるまで進めてから検討に入ります。

テストのために、ダイアログベースの MFC アプリを作成しました。 プロジェクト名は LBTextExtent としています。 以降、この文字列は関数名等ではなくプロジェクト名ですので、ご注意ください。

作成したダイアログに、リストボックスを配置します。 コントロール ( ダイアログに配置できる、ボタンやエディット、その他いろいろなものをコントロールと呼んでいます。 ) ID を、IDC_LIST にしています。 もちろん自由な ID を付けていただいて構いません。

横スクロールバーを有効にするには、リストボックスのプロパティ 「水平スクロール」を True に設定します。

リストボックスのプロパティ

このあとリストボックスにデータを追加するため、エディットコントロール IDC_TEXT も追加しておきました。

実行するにあたり、毎回たくさんデータを追加するのは面倒ですから、 ダイアログの初期化関数 OnInitDialog() で、適当に初期データを設定しておきます。 OnInitDialog 関数は、ダイアログクラス内に、 BOOL CLBTextExtentDlg::OnInitDialog() のように実装されています。

	// リストボックスに初期データを入れておきます。
	CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST);
	pList->ResetContent();
	pList->AddString(_T("アリゾナ・カージナルス"));
	pList->AddString(_T("シアトル・シーホークス"));
	pList->AddString(_T("サンフランシスコ・フォーティーナイナーズ"));
	pList->AddString(_T("ロサンゼルス(セントルイス)・ラムズ"));
	pList->AddString(_T("ラスベガス・レイダース"));
	pList->AddString(_T("ニューイングランド・ペイトリオッツ"));

	SetDlgItemText(IDC_TEXT, _T("ロサンゼルス(サンディエゴ)・チャージャース"));

実行すると、このようになりました。

リストボックスの例

収まりきらないテキストがありますが、横スクロールバーは表示されていません。 「水平スクロール」のプロパティをセットしているのに、です。 ちなみにはみでているのは上から 2 つ目の「サンフランシスコ・フォーティーナイナーズ」です。

リストボックスのプロパティで「スクロールなしの無効化」を True にする必要がありました。

リストボックスのプロパティ

大変わかりにくい日本語訳になっていますから、だったら英語のままで良かったんですけど。

リストボックスの例

縦スクロールバーも同時に表示されてしまいましたが、横スクロールバーは使えません。

▲ページ先頭へ

横スクロールバーを有効にする

投稿 December 17, 2022

横スクロールバーを有効にするために、 ダイアログの初期化 OnInitDialog() で、リストボックスの横方向のピクセル数を指定します。

一連の pList-AddString 呼び出し の次に、 SetHorizontalExtent 関数 呼び出しを追加します。 なお、ここで与えている値 500 は適当です。 ただじゅうぶんに大きな値を指定したというだけで、何か意味がある数字ではありません。

	pList->SetHorizontalExtent(500);

横スクロールバーが有効なリストボックスの例

無事に横スクロールできましたが、とてもたくさんスクロールして無駄な感じです。 上のイメージの横スクロールバーにある サム ( スクロールを制御する、「つまみ」の部分をこう呼ぶようです。 ) をみると、まだまだ右にスクロールできてしまうことがわかります。

500 より小さい値を指定すればだいたい合わせることはできますが、実行環境によって最適な値が異なる可能性も高いです。 しかし、水平スクロールバーのサイズは自動計算されません

どうにかならないものでしょうか?

▲ページ先頭へ

テキストの長さを調べて調整する

投稿 December 17, 2022

リストボックスの文字サイズやフォントを変える」で、 リストボックスに設定されているフォントを取得できていますので、設定されているテキストのサイズを知ることができそうです。

つまり、リストにある項目を 1 つずつ調べて、一番長いテキストにあわせて SetHorizontalExtent 関数を呼び出します。

ダイアログのヘッダに、関数と変数を追加します。

private:

	/* リストボックスの横幅を計算して設定 */
	bool AdjustListBoxWidth(void);

protected:

	/* 現在のリストボックスの幅 */
	int m_nLBWidth;

それぞれの意味は、上記コメントの通りです。

現在のリストボックスの幅 m_nLBWidth は初期状態 0 としたいので、 ダイアログの初期化関数 OnInitDialog() の最後で設定し、 そのあと AdjustListBoxWidth 関数を呼び出すようにします。

先ほど適当な値を設定していた pList->SetHorizontalExtent(500) は、混乱がないように削除、またはコメントアウトします。

	// リストボックスの幅を決定します。
	m_nLBWidth = 0;
	AdjustListBoxWidth();

リストボックスの最適な横幅を設定する関数 AdjustListBoxWidth は、次のようにしました。

bool CLBTextExtentDlg::AdjustListBoxWidth(void)
{
	CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST);
	int n = pList->GetCount();			// リストボックスのデータ数

ダイアログに配置したリストボックスを取得し、リストボックスにあるデータの数を取得しています。

	CFont* pFont = pList->GetFont();
	CDC memDC;
	memDC.CreateCompatibleDC(NULL);
	CFont* pMemFont = memDC.SelectObject(pFont);

リストボックスに設定されているフォントを取得し、互換性のあるメモリ DC を作成して選択します。 「リストボックスの文字サイズやフォントを変える」で少し詳しく見ています。 なお、CreateCompatibleDC 関数に NULL を渡すと、システムで使用している DC と互換の DC ができる、ということです。

	CString str;
	CSize sz;
	int nMax = 0;

	for (int i = 0; i < n; i++) {
		pList->GetText(i, str);
		sz = memDC.GetTextExtent(str);
		nMax = max(nMax, sz.cx);
	}

リストボックスに設定されているテキストを 1 つずつ取得し、 CDC クラスGetTextExtent 関数 で、現在の設定で描画される場合の使用領域(サイズ)を計算してもらいます。

計算された横サイズと nMax を比較し、最大の横サイズを nMax に設定することになります。 max マクロは、指定した 2 つの引数のうち、大きいほうの値を返してくれるものです。

	memDC.SelectObject(pMemFont);
	//memDC.DeleteDC();

使い終わったメモリ DC をもとに戻します。

なお、使い終わったメモリ DC を DeleteDC 関数で削除したいところでしたが、 DeleteDC 関数 の説明に「デストラクタが削除するので通常は呼び出さないように」と書かれていますので、呼び出さないほうがいいようです。

	// 今だと横幅が狭すぎる場合
	//     ※ アイテムを削除して小さくなる場合も考慮が必要です。
	if (nMax > m_nLBWidth) {
		m_nLBWidth = nMax;
		pList->SetHorizontalExtent(m_nLBWidth);
		return true;
	}

	// 変える必要がありませんでした。
	return false;
}

現在の幅より広くなった場合のみ、SetHorizontalExtent 関数を呼び出しています。 初期状態で m_nLBWidth が 0 ですので、初回は必ず設定されることになります。

実行すると、右端ぴったりになりました。

横スクロールバーが有効なリストボックスの例

ダイアログの OK ボタンで、 エディットコントロール IDC_TEXT に設定された文字列をリストボックスに追加することとし、 AdjustListBoxWidth 関数を呼び出して横幅を合わせてみます。

なお、AdjustListBoxWidth 関数のコメントに書いているように、nMax > m_nLBWidth のときのみ横幅指定をしていますから、 大きくなる方向にのみ対応しています。 リスト項目を削除して小さくなるような場合は、nMax != m_nLBWidth にするとよさそうです。

また、項目数が多くなると無駄が大きくなりますから、追加したり、削除した項目のみを調べて更新するほうが良さそうです。

void CLBTextExtentDlg::OnBnClickedOk()
{
	//CDialogEx::OnOK();

	CString str;
	GetDlgItemText(IDC_TEXT, str);

	if (!str.IsEmpty()) {
		CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST);
		pList->SetCurSel(pList->AddString(str));
		AdjustListBoxWidth();
	}
}

上記コードを追加して実行し、OK ボタンをクリックすると、すぐ上のエディットコントロールにある文字列がリストに追加されます。 長い文字列を追加すればそれにあわせてスクロールサイズが変わります。

横スクロールバーが有効なリストボックスの例

短い文字列の場合は、何も変わりません。

横スクロールバーが有効なリストボックスの例

項目をたくさん追加すると、縦スクロールバーもアクティブになります。 こちらは特に設定しなくてもちゃんと動作します。

縦スクロールバーが有効なリストボックスの例




リストボックス スタイル「スクロールなしの無効化」プロパティは LBS_DISABLENOSCROLL のようです。 この説明には「このスタイルが設定されていないと、項目が少なくてスクロールする必要がない場合、スクロール バーは表示されません。」と書かれています。

正しい横幅を指定している今、これを False にしても問題ないのではないでしょうか?

リストボックスのプロパティ

初期状態で縦スクロールバーは非表示になり、横スクロールバーはちゃんと表示されました

横スクロールバーのみ有効なリストボックスの例

項目を追加していくと、必要になった時点ではじめて、縦スクロールバーが表示されました。

縦スクロールバーも有効なリストボックスの例

これで便利に使えそうです。

▲ページ先頭へ
line
関連トピックス
line

リストボックスの文字サイズやフォントを変える

Visual C++ では、リストボックスの文字サイズをプロパティで変更することはできません。 ここでは自由な文字サイズに変更したり、別のフォントにしたりしています。

マルチモニタを制御

Windows PC で 2 台のモニタを接続している場合、2 台接続を検出し、座標を特定するためのコードについて書いています。

FTP でファイルをアップ&ダウンロード

Visual C++/MFC で、サーバーに FTP 接続してファイルをアップロード、ダウンロードするコードを書いています。

タイムスタンプを自由に変更する

Windows のファイルにある 3 種類のタイムスタンプ、作成日時、更新日時とアクセス日時を書き換えられるコードについて、書いています。

_sprintf でリンクエラーを回避する

古い Visual C++ プロジェクトから新しい環境に移行したとき、_sprintf でエラーが出る場合の回避方法について、書いています。

VS Community 2022 をインストールする

すでにインストールされている VS 2019 をアンインストールし、VS Community 2022 をインストールしなおしています。

line
その他のおすすめ
line

Android 開発トップ

Android 開発関連の情報を、書いています。

Windows 開発トップ

Windows 開発関連の情報を、書いています。



© 2017-2024 StraightApps.com 無断転載を禁じます。No reproduction without permission.