HSP3 あれこれ <オブジェクト 4>

Last Update : 2009/04/xx

◇ リストボックス (listbox命令)

 listbox命令で設置できるリストボックスオブジェクト。このページでは発展的なHSP3向けのサンプルスクリプトを掲載しています。基礎的な説明は、listbox命令の解説を参照。

 リストボックスについての詳細な説明として、Delphi言語向けですがHalbow資料館さんの該当ページをチェック!

↑TOP↑

リストボックスの項目追加や削除

 listbox命令の第3パラメータに項目として表示する文字列をあらかじめ指定しておきますが、設置後の文字列追加や削除を行うには、objprm命令を利用して項目全体を変更する方法が1つ。ここではsendmsg命令でいじってみます。

//	リストボックス項目追加&削除サンプル (by Kpan)

	objsize 150

	listbox a, 60, "ああ\nかか\nささ\nたた\nなな\nはは"
;	リストボックスのウィンドウハンドル取得
	hListbox = objinfo(stat, 2)

	button "追加", *add_item
	button "挿入", *ins_item
	button "削除", *del_item

	stop


*add_item
;	最後部に項目を追加します。(LB_ADDSTRING)
;	第4パラ(lparam値)に追加する文字列を指定。
	sendmsg hListbox, $180, , "★最後部に追加"
	stop

*ins_item
;	現在選択中のインデックス番号を取得。(LB_GETCURSEL)
;	statに選択状態のインデックス番号(0〜)が返ります。
	sendmsg hListbox, $188

;	特定位置に項目に挿入します。(LB_INSERTSTRING)
;	第3パラのwparam値に挿入するインデックス番号(0〜)を指定。
;	ここでは選択している項目の真下に挿入されます。
	sendmsg hListbox, $181, stat + 1, "●特定項目に挿入"
	stop

*del_item
	sendmsg hListbox, $188

;	特定の項目を削除します。(LB_DELETESTRING)
;	第3パラのwparam値に削除するインデックス番号(0〜)を指定。
;	全項目削除ならobjprm命令(第2パラ空欄)
	sendmsg hListbox, $182, stat
	stop

 ちなみに、複数個の項目を一気に追加したい場合は、項目数分のsendmsg命令を繰り返すことになります。

↑TOP↑

リストボックスにファイルをドラッグ&ドロップ

 上の項目追加の実践編といったところ? リストボックス内にファイル(フォルダも可)をドラッグ&ドロップして、ファイルのパスを項目として追加なサンプルソースです。

 ファイルのドラッグ&ドロップ処理自体については、HSP付属のサンプル「sample\new\dragdrop.hsp」(HSP 3.2〜では「sample\misc\dragdrop.hsp」)や、ちょくとさんの該当ページを参照あれー。なお、このサンプルでは、ドラッグファイル数は1つしか想定してません。

//	リストボックスにファイルをD&Dサンプルソース (by Kpan)

#include "shell32.as"

;	ファイルがドロップされた時 (WM_DROPFILES)
	oncmd gosub *dropfiles, $233

;	ファイルパス文字列用領域をあらかじめ確保
	sdim filepath, 512

	objsize 400
	listbox a, , ""
	hListbox = objinfo(stat, 2)

;	リストボックスにファイルドロップ受け入れ許可
	DragAcceptFiles hListbox, 1

	stop


*dropfiles
;	ドロップされたファイルパスを取得
;	(ここではfilepathという変数にファイルパスが返ってきます。
	DragQueryFile wparam, 0, varptr(filepath), 512

;	ドロップされたファイル情報を開放
	DragFinish wparam

;	ファイルパスを項目として追加 (LB_ADDSTRING)
	sendmsg hListbox, $180, , filepath

	return

 もし、リストボックスが複数ある場合は、ファイルがドラッグ&ドロップされた時のマウス座標位置を元に、真下にあるオブジェクトのハンドルを取得するWindowFromPoint関数を利用してテキトーに振り分けます。

//	複数個のリストボックスにファイルをD&Dサンプルソース (by Kpan)
//	(注) エディタの[HSP]メニュー→[HSP拡張マクロを使用する]を要有効。

#include "shell32.as"
#include "user32.as"

	oncmd gosub *dropfiles, $233

	sdim filepath, 512

	objsize 400

	listbox a, , ""
	hListbox.0 = objinfo(stat, 2)
	DragAcceptFiles hListbox.0, 1

	listbox b, , ""
	hListbox.1 = objinfo(stat, 2)
	DragAcceptFiles hListbox.1, 1

	stop

*dropfiles
	DragQueryFile wparam, 0, varptr(filepath), 512
	DragFinish wparam

;	カーソル位置の真下にあるウィンドウ(オブジェクト)のハンドル取得
;	statにハンドルが返る
	WindowFromPoint ginfo(0), ginfo(1)

	if stat = hListbox.0 {
		sendmsg hListbox.0, $180, , filepath
		return
	}

	if stat = hListbox.1 {
		sendmsg hListbox.1, $180, , filepath
		return
	}

	return

↑TOP↑

リストボックスの項目選択監視

 リストボックスは、第1パラメータの変数を確認することで選択しているインデックス番号(0〜)を取得できます。これをリアルタイムで監視するには、HSP2の場合、スクリプト内でループさせてこの変数を動きをチェックする手段をとったでしょうが、HSP3からはoncmd命令のお世話になりましょう。

 具体的には、リストボックスに変化があるとウィンドウメッセージ「WM_COMMAND」が通知されます。これを利用すれば、普通の選択(シングルクリック)とともに、ダブルクリック判定も可能です。ちなみに、コンボボックス(combox命令)も同じ感じです。

//	リストボックス監視サンプル (by Kpan)
//	普通の選択の場合

#define ctype HIWORD(%1) (%1 >> 16 & $FFFF)

;	WM_COMMAND
	oncmd gosub *command, $111

	objsize 100

	listbox a, 60, "胡瓜\n林檎\n人参\n葡萄\n茄子\n南瓜\n玉葱"
	hListbox = objinfo(stat, 2)

	stop


*command
;	lparamにはオブジェクトのウィンドウハンドルが返る
	if lparam = hListbox {
;		wparamの上位ワードに通知コードが返る
;		通知コード1の場合は選択状態変化 (LBN_SELCHANGE)
		if HIWORD(wparam) = 1 {
;			現在選択中のインデックス番号取得 (LB_GETCURSEL)
;			(変数aは利用しません)
			sendmsg hListbox, $188
			title "インデックス番号: "+stat

			return
		}
		return
	}

	return
//	リストボックス監視サンプル (by Kpan)
//	マウスのダブルクリックの場合

#define ctype HIWORD(%1) (%1 >> 16 & $FFFF)

;	WM_COMMAND
	oncmd gosub *command, $111

	objsize 100

	listbox a, 60, "亜米利加\n印度\n希臘\n独逸\n西班牙\n露西亜\n日本"
	hListbox = objinfo(stat, 2)

	stop


*command
	if lparam = hListbox {
;		通知コード2の場合はマウスのダブルクリック (LBN_DBLCLK)
		if HIWORD(wparam) = 2 : dialog "インデックス番号: "+a
		return
	}

	return

↑TOP↑

リストボックスの特定項目文字取得

 sendmsg命令を利用して特定項目の文字列を取得するサンプルコードです。(HSPのnote系命令を使わない方法

//	リストボックス項目文字列取得サンプル (by Kpan)

;	文字列が返る変数用の領域をあらかじめ確保
	sdim listbox_text

	objsize 100

	listbox a, 60, "蟷螂\n甲虫\n蟋蟀\n蜻蛉\n飛蝗\n蜘蛛"
	hListbox = objinfo(stat, 2)

	button "こんちゅう", *check
	stop


*check
;	特定の項目の文字列を取得 (LB_GETTEXT)
;	第3パラのwparam値にインデックス番号(0〜)、
;	第4パラのlparam値に取得した文字列を入れる変数ポインタを指定
	sendmsg hListbox, $189, a, varptr(listbox_text)

	mes ""+listbox_text

↑TOP↑

リストボックスの右クリック項目選択

 リストボックスの項目を選択するには、マウスの場合に当然ながら左クリックですが、逆に右クリックによる選択を実現するサンプルスクリプトです。マウスの位置から選択インデックスを取得するLBItemFromPt関数を利用します。

 左クリックで可能なものをわざわざ右クリックで行えるようにする必要性はないですが、たとえばポップアップメニューを表示するとか、項目を削除するとか、右クリック専用の特別な処理に応用できるかと思います。

//	リストボックスの右クリック項目選択 (by Kpan)
//	!エディタの[HSP]→[HSP拡張マクロを使用する]を要有効

#include "comctl32.as"

;	WM_CONTEXTMENUメッセージ
;	(ウィンドウ上で右クリックした時、正確にはクリックボタンを離した時)
	oncmd gosub *contextmenu, $7B

	listbox a, , "HSP\nリストボックス\nアイテム\n右クリック\nサンプル"
	hListbox = objinfo(stat, 2)

	stop

*contextmenu
;	wparamにリストボックスのハンドル
	if wparam = hListbox {
;		ポインタ位置からインデックス番号がstatに返る
		LBItemFromPt wparam, ginfo(0), ginfo(1), 0
		title "インデックス番号: "+stat

;		項目選択
		objprm 0, stat
		return
	}

	return

↑TOP↑

リストボックスの項目入れ替え

 リストボックスで選択した項目を上下に移動するサンプルです。(HSPのnote系命令+objprm命令を利用しない方法

 1発のsendmsg命令で入れ替えてくれる処理は存在しません。上のトピックスで登場した、(1)選択項目のインデックス番号取得、(2)その項目の文字列取得、(3)その項目削除、(4)取得した文字列を元に新たに項目挿入、(5)項目を選択状態に変更、というような作業を1つ1つ地味〜に行っていきます。ちなみに、(5)の項目選択は、sendmsg命令を使わないでobjprm命令で済ますことも可能。

//	リストボックス項目文字列入れ替えサンプル (by Kpan)

;	項目文字列取得用に確保
	sdim listbox_text

	pos 50, 50
	listbox a, 60, "1. あー\n2. いー\n3. うー\n4. えー\n5. おー"
	hListbox = objinfo(stat, 2)

	pos 120, 65
	button "上へ", *listup
	button "下へ", *listdown

	stop

;	上方向に入れ替え
*listup
;	選択項目のインデックス番号取得 (LB_GETCURSEL)
	sendmsg hListbox, $188
	if stat = 0 : stop	; 選択項目が先頭だった場合
	index = stat

;	選択項目の文字列取得 (LB_GETTEXT)
	sendmsg hListbox, $189, index, varptr(listbox_text)

;	選択項目の削除 (LB_DELETESTRING)
	sendmsg hListbox, $182, index

;	選択項目の1つ上に取得した文字列を挿入 (LB_INSERTSTRING)
	sendmsg hListbox, $181, index - 1, listbox_text

;	項目の選択 (LB_SETCURSEL)
;	第3パラのwparam値にインデックス番号を指定
	sendmsg hListbox, $186, index - 1
//	objprm 0, index - 1

	stop

;	下方向に入れ替え
*listdown
	sendmsg hListbox, $188
	if stat = 4 : stop	; 選択項目が最後部だった場合
	index = stat

	sendmsg hListbox, $189, index, varptr(listbox_text)

	sendmsg hListbox, $182, index

;	選択項目の1つ下に取得した文字列を
	sendmsg hListbox, $181, index + 1, listbox_text

	sendmsg hListbox, $186, index + 1
//	objprm 0, index + 1

	stop

↑TOP↑

リストボックスの文字色変更

 リストボックス内にある項目文字列の表示色を変更します。HSP3から登場したoncmd命令で、それなりに手軽に実装できます。なお、背景部分の色を変更する処理は用意していないので、デフォルト環境では白色になります。

//	リストボックス文字色変更サンプルソース (by Kpan)

#include "gdi32.as"
#include "user32.as"

;	RGBマクロ
#define ctype RGB(%1,%2,%3) (%1 | %2 << 8 | %3 << 16)

	objsize 100

	listbox a, , "赤\nレッド\nあか"
	hListbox.0 = objinfo(stat, 2)

	listbox b, , "青\nブルー\nあお"
	hListbox.1 = objinfo(stat, 2)

;	ウィンドウ背景色のブラシを取得 (リストボックス自体の背景色用)
	GetSysColorBrush 5
	hBrush = stat

;	ウィンドウメッセージ (WM_CTLCOLORLISTBOX)
	oncmd gosub *ctlcolorlistbox, $134

	stop


*ctlcolorlistbox
;	lparamにオブジェクトのウィンドウハンドルが返る
	if lparam = hListbox.0 {
;		テキスト色
		SetTextColor wparam, RGB($FF, $00, $00)
;		テキスト部分背景色 (透過)
		SetBkMode wparam, 1

;		リストボックス自体の背景色ブラシを返す
		return hBrush
	}

	if lparam = hListbox.1 {
		SetTextColor wparam, RGB($00, $00, $FF)
		SetBkMode wparam, 1

		return hBrush
	}

	return

 ちなみに、項目別に異なる文字色を指定したい場合は「オーナードロー」という処理が必要です。リストボックスの項目描画をすべて自前で行わないといけないので、かなりメンドーなことになります。(参照、HSP開発wiki

↑TOP↑

複数項目選択可能なリストボックスの表示

 listbox命令で設置できるリストボックスは、複数の選択肢の中から1項目しか選択できません。複数個の項目を選択できるリストボックスを作成してみます。

 で、作成するのに標準のlistbox命令は使えません。HSPのwinobj命令(今回のサンプル)や、Win32APIのCreateWindowEx関数を利用して、コントロールそのものを最初から作成する必要があります。

 そして、項目の追加や、どの項目が選択されているか、項目の選択状態変更などの各制御にsendmsg命令を利用します。(上の項目追加や削除の説明を参照〜

//	複数選択可能なリストボックス表示サンプル (by Kpan)

#include "gdi32.as"

;	リストボックスオブジェクトを設置
;	第2パラメータの $8 がポイント。これにより複数選択可能なリスト
;	ボックスになります。あるいは $800 を指定した場合、Shiftキーや
;	Ctrlキーを押しながらの複数選択可能リストボックスになります。
	winobj "listbox", "", $200, $50200001 | $8, 100, 200
;	winobj "listbox", "", $200, $50200001 | $800, 100, 200
	hListbox = objinfo(stat, 2)

;	オブジェクト内の文字列用フォントを指定。
;	ここではsysfont命令の「デフォルトGUIフォント」相当が反映されます。
	GetStockObject 17
	sendmsg hListbox, $30, stat

;	項目の追加 (LB_ADDSTRING)
;	追加する項目数分、sendmsg命令を繰り返します。
	repeat 10
		sendmsg hListbox, $180, , "こうもく "+cnt+""
	loop

;	特定項目の選択状態を変更する場合 (LB_SETSEL)
;	(複数選択リストボックスのみ)
;	第3パラのwparam値に選択する(=1) or 選択はずす(=0)
;	第3パラのlparam値にインデックス番号(0〜)を指定
	sendmsg hListbox, $185, 1, 3
	sendmsg hListbox, $185, 1, 7

	button "チェーック!", *check
	stop


;	選択されているインデックス番号の取得
;	インデックス番号を一挙に取得する処理は存在しないので、
;	選択されているかを項目1つ1つ調べていきます。
*check
;	選択項目数の取得 (LB_GETSELCOUNT)
;	statに選択状態の項目数が返ります。
	sendmsg hListbox, $190
	mes "選択項目数: "+stat+"コ"

;	項目数の取得 (LB_GETCOUNT)
;	statにリストボックス内の項目数が返ります。
	sendmsg hListbox, $18B

	repeat stat
;		特定項目が選択されているかどうかの確認 (LB_GETSEL)
;		第3パラのwparam値にインデックス番号(0〜)を指定
;		選択項目の場合はstatに1が返ります。
		sendmsg hListbox, $187, cnt
		if stat : mes " 選択項目: "+cnt
	loop

	stop

↑TOP↑

ソート機能付きリストボックスの表示

 リストボックスコントロールには、項目文字列をソートする機能が用意されています。HSPのlistbox命令は、その機能が働くようにはなっていません。winobj命令でソート機能付きリストボックスを表示してみます。項目の追加や削除に標準のobjprm命令は使えないので、sendmsg命令を利用します。(英文字の半角/全角は区別せずソート?

//	ソート機能付きリストボックス表示サンプル (by Kpan)

#include "gdi32.as"

;	ソート機能付きリストボックス ($2=LBS_SORT)
	winobj "listbox", "", $200, $50200001 | $2, 150, 100
	hListbox = objinfo(stat, 2)

;	sysfont命令「デフォルトGUIフォント」相当適用
	GetStockObject 17
	sendmsg hListbox, $30, stat

	sdim a
	pos 170, 40
	input a, 100
	button "追加", *add

	stop

*add
	if a = "" : stop

;	項目追加 (LB_ADDSTRING)
	sendmsg hListbox, $180, , a

;	入力ボックスを空に
	objprm 1, ""

↑TOP↑

リストボックスに水平スクロールバー表示

 HSPのリストボックスは、第2パラの拡張Yサイズで指定された高さを超える項目数になると自動的に縦方向の垂直スクロールバーが表示されます。逆に横方向の水平スクロールバーは文字列の長さ(横幅)に関係なく表示されません。

 これは全項目表示されるよう垂直スクロールバーは自動的に表示してくれるのに対して、水平スクロールバーにはそのような処理がないためです。自前で文字列の長さを調べて(GetTextExtentPoint32関数)、文字列の長さに合った水平スクロールバーを表示し、長さを調節してやらないといけません。このようなリストボックスを用意するにはlistbox命令は無理なので、winobj命令でコントロールそのものを最初から作成する必要があります。

 そして、項目の追加やどの項目が選択されているかなどのさまざまな制御はHSPのsendmsg命令を利用します。

//	リストボックスに水平スクロールバー表示サンプル (by Kpan)
//	(注) エディタの[HSP]メニュー→[HSP拡張マクロを使用する]を要有効。

#include "gdi32.as"

;	リストボックスを設置。ウィンドウスタイルにスクロールバー表示指定。
;	水平(WS_HSCROLL=$100000)、垂直(WS_VSCROLL=$200000)
	winobj "listbox", "", $200, $50000001 | $100000 | $200000, 100, 50
	hListbox = objinfo(stat, 2)

;	フォント設定
;	sysfont命令の「デフォルトGUIフォント」相当が適用されます。
	GetStockObject 17
	hFont = stat
	sendmsg hListbox, $30, hFont

;	追加する項目文字列をテキトーに
;	普通は後ろ部分が見れない「い」の長さに合った水平バーを表示
	item = "あああああ", "いいいいいいいいいいいいいいいイ", "うう"

;	SIZE構造体
	dim SIZE, 2

;	3ループさせて各項目追加
	repeat 3

	sendmsg hListbox, $180, , item(cnt)

;	文字列の横幅(ピクセル単位)を取得
	SelectObject hdc, hFont
	GetTextExtentPoint32 hdc, item(cnt), strlen(item(cnt)), varptr(SIZE)

;	最も横幅のある文字列だったら、水平スクロールバーのサイズを調整。
	if SIZE > maxSIZE {
;		水平スクロール可能範囲の指定 (LB_SETHORIZONTALEXTENT)
;		第3パラ(wparam値)にピクセル単位で幅を指定します。
;		文字列の横幅+余裕を持たせてプラス3
		sendmsg hListbox, $194, SIZE + 3
		maxSIZE = SIZE
	}

	loop

↑TOP↑

ドラッグリストボックスの表示

 リストボックスには、ドラッグリストボックスという拡張機能が用意されています。これは、項目文字列をマウスでドラッグ&ドロップすることで項目の入れ替えというのができるものです。サンプルスクリプトを公開しています。

 ものすごいテキトーな処理の流れを書くと、普通のリストボックスをMakeDragList関数でドラッグリストボックス化、ドラッグ時の通知メッセージ(RegisterWindowMessage関数で「DRAGLISTMSGSTRING」)のDRAGLISTINFO構造体を見て色々と処理をしていきます。LBItemFromPt関数からマウスポインタのある項目インデックスを取得し、DrawInsert関数でコントロール脇に目印を付け、実際の項目の入れ替えはsendmsg命令を利用します。

ダウンロード (オブジェクト編 4)

↑TOP↑

<< オブジェクト 3 | HSP3 オブジェクト | オブジェクト 5 >>

Copyright © 2005-2012 . All rights reserved.