HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2015
0427
リストビュー研究中リストビューのドラッグ&ドラッグ用モジュールを作成してみました10解決


リストビュー研究中

リンク

2015/4/27(Mon) 20:34:23|NO.68814

こちらのコールバック用モジュールを使用したモジュールを作成してみました

http://hsp.tv/play/pforum.php?mode=all&num=62130

リストビューで選択したアイテムをドラッグ&ドロップで並べ替えることができます
ただし詳細表示とリスト表示専用、グループ表示時不可です(しかも確認していない手抜き仕様です)

使用方法ですが
上記のコールバック関数モジュールを必ずこのモジュールの前に記述してください
"_MODCLBK3B2_AS"のバージョンにて動作確認をしています
そしてリストビューの作成後に
AutoDragDrop リストビューのオブジェクトID

と記述するだけで、カラムをクリックするとソートされるようになります
#module
#uselib "User32.dll"
#func SetWindowLong "SetWindowLongA" int, int, int
#func CallWindowProc "CallWindowProcA" int,int,int,int,int
//各種定数
#define WM_NOTIFY     0x0000004E
#define GWL_WNDPROC   0xFFFFFFFC
#define WM_MOUSEMOVE  0x00000200
#define WM_LBUTTONUP  0x00000202
#define NM_MOUSEMOVE  0xFFFFFFE7	//自作の通知メッセージ
#define NM_LBUTTONUP  0xFFFFFFE6	//自作の通知メッセージ
#deffunc AutoDragDrop int ObjID
	ghListview = objinfo_hwnd(ObjID)
	oncmd gosub *OnNotify, WM_NOTIFY
	//以下、リストビューのサブクラス化処理
	newclbk3 gpStaticProc, 4, *StaticProc				//リストビューのサブクラス化のためのコールバック関数を登録
	SetWindowLong ghListview, GWL_WNDPROC, gpStaticProc	//リストビューをサブクラス化
	gDefLvProc = stat									//リストビューのデフォルトのウィンドウプロシージャ
	gMyNHNMHDR = ghListview, 0, 0						//自作のNHNMHDR構造体を宣言。第一要素は必ずリストビューのハンドル
	return

//サブクラス化したリストビューのメッセージ処理
*StaticProc
	clbkargprotect gClbkPrm
	//メッセージにより分岐
	switch gClbkPrm(1)
		//リストビュー上でマウスが移動した
		case WM_MOUSEMOVE
			gMyNHNMHDR(2) = NM_MOUSEMOVE					//自作の通知メッセージ
			sendmsg hwnd, WM_NOTIFY, 0, varptr(gMyNHNMHDR)	//HSPのウィンドウに通知メッセージを送る
		swbreak
		//左ボタンを離した
		case WM_LBUTTONUP
			gMyNHNMHDR(2) = NM_LBUTTONUP					//自作の通知メッセージ
			sendmsg hwnd, WM_NOTIFY, 0, varptr(gMyNHNMHDR)	//HSPのウィンドウに通知メッセージを送る
		swbreak
		//上記のメッセージでなければそのままリストビューに送る
		default
			CallWindowProc gDefLvProc, gClbkPrm(0),gClbkPrm(1),gClbkPrm(2),gClbkPrm(3)
		swbreak
	swend
	return

//WM_NOTIFYが届いたときのサブルーチン
*OnNotify
	NotifyProc lparam, ghListview//lparamとリストビューのハンドルを引数に命令を呼び出す
	return stat

//HSPはモジュール終了→オブジェクトの破棄の処理の流れなので、モジュールの終了の際にサブクラス化の解除をしなければリストビューにWM_DESTROYが届かない
#deffunc ExitProc onexit
	SetWindowLong ghListview, GWL_WNDPROC, gDefLvProc	//デフォルトのウィンドウプロシージャに戻す
	return
#global

#module
#uselib "User32.dll"
#func  ScreenToClient  "ScreenToClient"  int, int
#func  SetCapture      "SetCapture"      int
#func  ReleaseCapture  "ReleaseCapture"
#cfunc WindowFromPoint "WindowFromPoint" int, int
#func  GetWindowRect   "GetWindowRect"   int, int
//各種定数
#define LVN_BEGINDRAG       0xFFFFFF93
#define NM_MOUSEMOVE        0xFFFFFFE7	//自作の通知メッセージ
#define NM_LBUTTONUP        0xFFFFFFE6	//自作の通知メッセージ
#define LVM_GETITEMCOUNT    0x00001004
#define LVM_GETITEMRECT     0x0000100E
#define LVM_SCROLL          0x00001014
#define LVM_GETTOPINDEX     0x00001027
#define LVM_GETCOUNTPERPAGE 0x00001028
#define LVM_GETITEMSTATE    0x0000102C
#define LVM_SUBITEMHITTEST  0x00001039
#define LVM_SORTITEMSEX     0x00001051
#define LVM_SETINSERTMARK   0x000010A6
#define LVIS_SELECTED       0x00000002

//WM_NOTIFYの通知メッセージを処理する命令
#deffunc NotifyProc int _lparam, int hListview, local NMHDR
	//NMHDR 構造体の割り当て
	dupptr NMHDR, _lparam, 3*4
	//通知メッセージがリストビューからでなければ戻る
	if(NMHDR(0) != hListview) : return 0
	//通知メッセージにより処理を分岐
	switch NMHDR(2)
		//ドラッグ&ドロップ開始
		case LVN_BEGINDRAG
			SetCapture hListview	//リストビュー外でクリックを離した時のためマウスキャプチャ開始
			gDragDropFlag = 1		//ドラッグ&ドロップのフラグを立てる
		swbreak
		//マウスが移動した(自作の通知メッセージ)
		case NM_MOUSEMOVE
			if(gDragDropFlag) : Draging hListview	//ドラッグ&ドロップのフラグがあればインサートマークを表示
		swbreak
		//左ボタンを離した(自作の通知メッセージ)
		case NM_LBUTTONUP
			if(gDragDropFlag) {		//ドラッグ&ドロップのフラグがあればアイテムの並べ替え
				OnDrop hListview	//ドラッグ&ドロップの終了命令
				gDragDropFlag = 0	//ドラッグ&ドロップのフラグを消す
			}
		swbreak
	swend
	return 0

//インサートマーク表示命令
#deffunc Insertmark int hListview, int iItem, int dwFlags, local LVINSERTMARK
	//インサートマークの表示にはLVINSERTMARK構造体を設定する
	//LVINSERTMARK構造体のサイズ、"0"以外でアイテムの下に表示、表示するアイテムのインデックス("-1"でインサートマーク削除)、"0"固定となっている
	LVINSERTMARK = 16, dwFlags, iItem, 0
	sendmsg hListview, LVM_SETINSERTMARK, 0, varptr(LVINSERTMARK)
	return

//マウス下のアイテムのインデックス取得命令(ドラッグ&ドロップ用)
//LVM_HITTESTで簡単に取得できるのだが、アイテムの右側の空欄と、アイテムが少ない時のリストビュー下部の空欄が、どちらも"-1"となる
//アイテムの右側の空欄でもアイテムのインデックスを取得したいため、LVM_GETITEMRECTでアイテムの座標を取得しマウス座標で判定を行っている
#deffunc NearHITTEST int hListview, array Dst, local TopIndex, local RECT, local MousePos
	sendmsg hListview, LVM_GETITEMCOUNT								//総アイテム数を取得
	Dst = stat, 1													//値を返す変数の初期値
	MousePos = ginfo_mx, ginfo_my
	ScreenToClient hListview, varptr(MousePos)						//マウス座標をリストビュー上の座標に変換
	sendmsg hListview, LVM_GETTOPINDEX								//リストビューの先頭に表示されているアイテム。アイテムが多くスクロールしていたら"0"ではない
	TopIndex = stat
	sendmsg hListview, LVM_GETCOUNTPERPAGE							//画面上に表示されているアイテム数を取得
	//マウス座標がアイテムのY座標内か判定していく
	repeat stat, TopIndex											//先頭のアイテムから表示アイテム数だけ繰り返す
		dim RECT, 4
		sendmsg hListview, LVM_GETITEMRECT, cnt, varptr(RECT)		//アイテムのリストビュー上の座標を取得
		if((RECT(1) <= MousePos(1)) & (MousePos(1) <= RECT(3))) {	//アイテムの範囲内ならば
			Dst(0) = cnt											//そのアイテムのインデックス
			Dst(1) = 0												//インサートマークを下に表示するdwFlagsフラグを消す
			break
		}
	loop
	return

//ドラッグ中のインサートマーク表示
#deffunc Draging int hListview, local Index, local RECT, local ItemRECT, local MoveX, local MoveY
	//マウス座標がリストビュー上ならばインサートマーク表示
	if(WindowFromPoint(ginfo_mx, ginfo_my) == hListview) {
		NearHITTEST hListview, Index
		Insertmark hListview, Index(0)-Index(1), Index(1)
	//マウスをドラッグしたままリストビューの外に出たらスクロールする。ドラッグ&ドロップ中はSetCaptureでマウスキャプチャしているためウィンドウ外もマウス移動を取得可能
	} else {
		Insertmark hListview, -1									//インサートマークを削除
		dim ItemRECT, 4
		sendmsg hListview, LVM_GETITEMRECT, 0, varptr(ItemRECT)		//先頭のアイテムの表示サイズを取得
		dim RECT, 4
		GetWindowRect hListview, varptr(RECT)						//リストビューの画面上の位置を取得
		if(RECT(0) > ginfo_mx) : MoveX = -1							//マウスがリストビューの左側ならば横軸のスクロール量を-1
		if(RECT(1) > ginfo_my) : MoveY = -(ItemRECT(3)-ItemRECT(1))	//アイテムの縦幅の半分以上を指定しなければLVM_SCROLLは縦スクロールを行わない
		if(RECT(2) < ginfo_mx) : MoveX = 1
		if(RECT(3) < ginfo_my) : MoveY = ItemRECT(3)-ItemRECT(1) 
		sendmsg hListview, LVM_SCROLL, MoveX, MoveY					//リストビューをスクロール
	}
	return

//ドラッグ&ドロップ中にボタンを離す
#deffunc OnDrop int hListview, local Index, local prm, local Item
	//リストビュー上でマウスボタンを離した場合は並べ替えを行う
	if(WindowFromPoint(ginfo_mx, ginfo_my) == hListview) {
		//ドラッグ&ドロップ用並べ替えコールバック関数を作成していなければ作成
		if(gpDragDropSort == 0) : newclbk3 gpDragDropSort, 3, *DragDropSort
		//アイテムを並べ替え
		NearHITTEST hListview, Index							//マウス下のアイテムのインデックスを取得
		sendmsg hListview, LVM_SORTITEMSEX, 0, gpDragDropSort	//アイテムをソート
	}
	Insertmark hListview, -1	//インサートマークを削除
	ReleaseCapture				//マウスキャプチャを開放
	return
//ドラッグ&ドロップ用並べ替えコールバック関数
//ドロップ先のインデックスより手前のアイテムを"0"、インデックスより後方のアイテムを"2"、移動するアイテムを"1"として並べ替えを行う
//LVM_SORTITEMSEXでのソートは安定ソートなのでこの方法でのアイテムの移動が可能
*DragDropSort
	clbkargprotect prm
	//"0"での初期化を兼ねて配列確保
	dim Item, 2
	//ドロップ先のインデックスより後方ならば"2"を代入
	if(prm(0) >= Index) : Item(0) = 2
	if(prm(1) >= Index) : Item(1) = 2
	//選択されていたら"1"を代入
	sendmsg hListview, LVM_GETITEMSTATE, prm(0), LVIS_SELECTED	//アイテムの選択を確認
	if(stat) : Item(0) = 1										//選択されているなら"1"を代入
	sendmsg hListview, LVM_GETITEMSTATE, prm(1), LVIS_SELECTED
	if(stat) : Item(1) = 1
	return Item(0) - Item(1)
#global



この記事に返信する


リストビュー研究中

リンク

2015/4/27(Mon) 20:42:47|NO.68816

コピペで思い切り間違えていました
誤「と記述するだけで、カラムをクリックするとソートされるようになります」
正「と記述するだけで、選択アイテムがドラッグ&ドロップで並べ替えできるようになります」



kanamaru

リンク

2015/4/28(Tue) 18:06:10|NO.68832

16行目でエラーが発生しています。
「文法が間違っています」
ということです。
windows7の64bit、メモリは4GBです。



スペース(HSP歴3年)

リンク

2015/4/28(Tue) 18:24:11|NO.68834

kanamaruさんと同じエラーが発生します。
コールバックのモジュールは著作権フリーで自由に配布できるそうなので、
一式まとめたものをzipで配布してみてはどうでしょうか?
正直今の状態だと試すにも面倒で・・・



tds12

リンク

2015/4/28(Tue) 19:22:03|NO.68840

無事実行できました。

windows8.1 x64、メモリ4GBです。



kanamaru

リンク

2015/4/28(Tue) 19:23:20|NO.68841

今気づいたのですがひょっとしたらエラーの原因って
modclbkを内部に記述するかインクルードしてないからでは?



farukon

リンク

2015/4/28(Tue) 20:06:05|NO.68846

コンパイル時にエラーが発生しました。

#HSP script preprocessor ver3.32 / onion software 1997-2013(c) #Use file [hspdef.as] #HSP code generator ver3.32 / onion software 1997-2013(c) ???(16) : error 2 : 文法が間違っています (16行目) --> newclbk3@m0 gpstaticproc@m0, 4, *staticproc@m0

dynabook BX メモリ 2GB
Windows 7 Home Premium 32bit (Service Pack 1 適用済み)



tds12

リンク

2015/4/28(Tue) 20:35:25|NO.68853

>コンパイル時にエラーが発生しました。
「上記のコールバック関数モジュールを必ずこのモジュールの前に記述してください」
と書いてありますよ。



リストビュー研究中

リンク

2015/4/28(Tue) 22:03:31|NO.68861

最初の投稿にも記載したように以下のコールバック用モジュールが必要です
http://hsp.tv/play/pforum.php?mode=all&num=62130
以下はコールバック用モジュールをつなげただけのソースです
他に手はいっさい加えていません

#ifndef _MODCLBK3B2_AS #ifdef _MODCLBK3A1_AS #undef _MODCLBK3A1_AS #undef newclbk3 #undef clbkargprotect #undef CLBKMODE_CDECL #undef _newclbk3 #undef modclbk_term #endif #ifdef _MODCLBK3B2_AS #undef clbk_getthisptr #endif #define global _MODCLBK3A1_AS #define global _MODCLBK3B1_AS #define global _MODCLBK3B2_AS #define global _MODCLBK3B3_AS #define global newclbk3(%1,%2 = 0,%3,%4 = 0) tmpclbklb@modclbk3b3=%3:%1=_newclbk3(%2,tmpclbklb@modclbk3b3,%4) //新しい関数ポインタを取得する // %1...関数ポインタを受け取る変数 // %2...引数の数 // %3...呼び出されるラベル // %4...作成のモード(CLBKMODE) #define global clbkargprotect(%1) lp@modclbk3b3=lparam:wp@modclbk3b3=wparam:dupptr args@modclbk3b3,lp@modclbk3b3,wp@modclbk3b3*4,4:dim %1,wp@modclbk3b3:memcpy %1,args@modclbk3b3,wp@modclbk3b3*4 //引数を取得する // %1...引数を受け取るための変数 #module "modclbk3b2" #define ctype uintbitshiftright(%1,%2) (((%1&$7fffffff)>>%2)|((1&(%1>>31))<<(31-%2))) #uselib "msvcrt.dll" #cfunc malloc "malloc" int #func free "free" int #uselib "kernel32.dll" #func VirtualProtect "VirtualProtect" var,int,int,var #cfunc LoadLibrary "LoadLibraryA" sptr #cfunc GetProcAddress "GetProcAddress" int,sptr #func FreeLibrary "FreeLibrary" int #define global CLBKMODE_CDECL $00000001 // 呼び出し規約をcdeclに設定する // 呼び出し規約をthiscallに設定する #defcfunc _newclbk3 int _argmax,var clbklb,int mode // int _argmax ... 関数の引数の数 // var clbklb ... 呼び出すサブルーチンが入った変数 // int mode ... コールバック関数のモード(CLBKMODE_) dim _x,1 mref ctx,68 ilb=0 memcpy ilb,clbklb,4,0,0 argmax = _argmax if inited == 0{ inited = 1 dim ptrtable ptrmax = 0 hcrt = LoadLibrary("msvcrt.dll") ptrtomalloc = GetProcAddress(hcrt,"malloc") ptrtofree = GetProcAddress(hcrt,"free") thisptr = 0 } code_callptr = lpeek(ctx,168 + 48)// if argmax>0{ dim clbk,57 clbk(0) = $83ec8b55,$45c730ec,$000000fc,$f845c700 clbk(4) = $00000000,$00e045c7,$c7000000,$0000e445 clbk(8) = $45c70000,$000000ec,$d845c700,$00000000 clbk(12) = $8bd84d89,$e0c1f845,$4d8b5002,$83d1ffe0 clbk(16) = $458904c4,$f445c7d4,$00000000,$00dc45c7 clbk(20) = $c7000000,$0000f045,$45c70000,$000000e8 clbk(24) = $0c558d00,$8be85589,$4d8bd445,$c7088908 clbk(28) = $0001d045,$09eb0000,$83d0558b,$558901c2 clbk(32) = $f8458bd0,$7dd04539,$e84d8b1a,$8904c183 clbk(36) = $558be84d,$d4458bd0,$8be84d8b,$0c89fc49 clbk(40) = $8bd5eb90,$458bf455,$8b0289f8,$558bdc4d clbk(44) = $681189d4,$00000000,$ffec458b,$04c483d0 clbk(48) = $8bf04d8b,$fc558911,$00e845c7,$8b000000 clbk(52) = $8b50d445,$d1ffe44d,$8b04c483,$e58bfc45 clbk(56) = $0000c25d lpoke clbk,$10,argmax:lpoke clbk,$17,ptrtomalloc:lpoke clbk,$1e,ptrtofree lpoke clbk,$25,code_callptr:lpoke clbk,$2c,varptr(thisptr) lpoke clbk,$48,varptr(ctx) + 36:lpoke clbk,$4f,varptr(ctx) + 40 lpoke clbk,$56,varptr(ctx) + 784:lpoke clbk,$b4,ilb if ((mode & $f) == CLBKMODE_CDECL) == 0:wpoke clbk,$e2,(argmax * 4) & $ffff funcsize = 228 } if argmax==0{ dim clbk,25 clbk(0) = $83ec8b55,$45c718ec,$000000fc,$f045c700 clbk(4) = $00000000,$00f845c7,$c7000000,$0000e845 clbk(8) = $45c70000,$000000f4,$ec45c700,$00000000 clbk(12) = $8bec4d89,$00c7f845,$00000000,$c7e84d8b clbk(16) = $00000001,$00006800,$558b0000,$83d2fff0 clbk(20) = $458b04c4,$89088bf4,$458bfc4d,$5de58bfc clbk(24) = $000000c3 lpoke clbk,$10,code_callptr:lpoke clbk,$17,varptr(ctx) + 36 lpoke clbk,$1e,varptr(ctx) + 40:lpoke clbk,$25,varptr(ctx) + 784 lpoke clbk,$2c,varptr(thisptr):lpoke clbk,$46,ilb funcsize = 100 } clbkptr = malloc(funcsize) dupptr clbkfunc,clbkptr,funcsize,4 memcpy clbkfunc,clbk,funcsize VirtualProtect clbkfunc,funcsize,$40,_x ptrtable(ptrmax) = clbkptr ptrmax++ return clbkptr #defcfunc clbk_getthisptr //Thisポインタを取得する。 //コールバックとして呼び出された直後に別変数へコピーしなければならない。 return thisptr #deffunc modclbk_term onexit repeat ptrmax free ptrtable(cnt) loop if inited{ FreeLibrary hcrt } ptrmax = 0 return #global #endif #module #uselib "User32.dll" #func SetWindowLong "SetWindowLongA" int, int, int #func CallWindowProc "CallWindowProcA" int,int,int,int,int //各種定数 #define WM_NOTIFY 0x0000004E #define GWL_WNDPROC 0xFFFFFFFC #define WM_MOUSEMOVE 0x00000200 #define WM_LBUTTONUP 0x00000202 #define NM_MOUSEMOVE 0xFFFFFFE7 //自作の通知メッセージ #define NM_LBUTTONUP 0xFFFFFFE6 //自作の通知メッセージ #deffunc AutoDragDrop int ObjID ghListview = objinfo_hwnd(ObjID) oncmd gosub *OnNotify, WM_NOTIFY //以下、リストビューのサブクラス化処理 newclbk3 gpStaticProc, 4, *StaticProc //リストビューのサブクラス化のためのコールバック関数を登録 SetWindowLong ghListview, GWL_WNDPROC, gpStaticProc //リストビューをサブクラス化 gDefLvProc = stat //リストビューのデフォルトのウィンドウプロシージャ gMyNHNMHDR = ghListview, 0, 0 //自作のNHNMHDR構造体を宣言。第一要素は必ずリストビューのハンドル return //サブクラス化したリストビューのメッセージ処理 *StaticProc clbkargprotect gClbkPrm //メッセージにより分岐 switch gClbkPrm(1) //リストビュー上でマウスが移動した case WM_MOUSEMOVE gMyNHNMHDR(2) = NM_MOUSEMOVE //自作の通知メッセージ sendmsg hwnd, WM_NOTIFY, 0, varptr(gMyNHNMHDR) //HSPのウィンドウに通知メッセージを送る swbreak //左ボタンを離した case WM_LBUTTONUP gMyNHNMHDR(2) = NM_LBUTTONUP //自作の通知メッセージ sendmsg hwnd, WM_NOTIFY, 0, varptr(gMyNHNMHDR) //HSPのウィンドウに通知メッセージを送る swbreak //上記のメッセージでなければそのままリストビューに送る default CallWindowProc gDefLvProc, gClbkPrm(0),gClbkPrm(1),gClbkPrm(2),gClbkPrm(3) swbreak swend return //WM_NOTIFYが届いたときのサブルーチン *OnNotify NotifyProc lparam, ghListview//lparamとリストビューのハンドルを引数に命令を呼び出す return stat //HSPはモジュール終了→オブジェクトの破棄の処理の流れなので、モジュールの終了の際にサブクラス化の解除をしなければリストビューにWM_DESTROYが届かない #deffunc ExitProc onexit SetWindowLong ghListview, GWL_WNDPROC, gDefLvProc //デフォルトのウィンドウプロシージャに戻す return #global #module #uselib "User32.dll" #func ScreenToClient "ScreenToClient" int, int #func SetCapture "SetCapture" int #func ReleaseCapture "ReleaseCapture" #cfunc WindowFromPoint "WindowFromPoint" int, int #func GetWindowRect "GetWindowRect" int, int //各種定数 #define LVN_BEGINDRAG 0xFFFFFF93 #define NM_MOUSEMOVE 0xFFFFFFE7 //自作の通知メッセージ #define NM_LBUTTONUP 0xFFFFFFE6 //自作の通知メッセージ #define LVM_GETITEMCOUNT 0x00001004 #define LVM_GETITEMRECT 0x0000100E #define LVM_SCROLL 0x00001014 #define LVM_GETTOPINDEX 0x00001027 #define LVM_GETCOUNTPERPAGE 0x00001028 #define LVM_GETITEMSTATE 0x0000102C #define LVM_SUBITEMHITTEST 0x00001039 #define LVM_SORTITEMSEX 0x00001051 #define LVM_SETINSERTMARK 0x000010A6 #define LVIS_SELECTED 0x00000002 //WM_NOTIFYの通知メッセージを処理する命令 #deffunc NotifyProc int _lparam, int hListview, local NMHDR //NMHDR 構造体の割り当て dupptr NMHDR, _lparam, 3*4 //通知メッセージがリストビューからでなければ戻る if(NMHDR(0) != hListview) : return 0 //通知メッセージにより処理を分岐 switch NMHDR(2) //ドラッグ&ドロップ開始 case LVN_BEGINDRAG SetCapture hListview //リストビュー外でクリックを離した時のためマウスキャプチャ開始 gDragDropFlag = 1 //ドラッグ&ドロップのフラグを立てる swbreak //マウスが移動した(自作の通知メッセージ) case NM_MOUSEMOVE if(gDragDropFlag) : Draging hListview //ドラッグ&ドロップのフラグがあればインサートマークを表示 swbreak //左ボタンを離した(自作の通知メッセージ) case NM_LBUTTONUP if(gDragDropFlag) { //ドラッグ&ドロップのフラグがあればアイテムの並べ替え OnDrop hListview //ドラッグ&ドロップの終了命令 gDragDropFlag = 0 //ドラッグ&ドロップのフラグを消す } swbreak swend return 0 //インサートマーク表示命令 #deffunc Insertmark int hListview, int iItem, int dwFlags, local LVINSERTMARK //インサートマークの表示にはLVINSERTMARK構造体を設定する //LVINSERTMARK構造体のサイズ、"0"以外でアイテムの下に表示、表示するアイテムのインデックス("-1"でインサートマーク削除)、"0"固定となっている LVINSERTMARK = 16, dwFlags, iItem, 0 sendmsg hListview, LVM_SETINSERTMARK, 0, varptr(LVINSERTMARK) return //マウス下のアイテムのインデックス取得命令(ドラッグ&ドロップ用) //LVM_HITTESTで簡単に取得できるのだが、アイテムの右側の空欄と、アイテムが少ない時のリストビュー下部の空欄が、どちらも"-1"となる //アイテムの右側の空欄でもアイテムのインデックスを取得したいため、LVM_GETITEMRECTでアイテムの座標を取得しマウス座標で判定を行っている #deffunc NearHITTEST int hListview, array Dst, local TopIndex, local RECT, local MousePos sendmsg hListview, LVM_GETITEMCOUNT //総アイテム数を取得 Dst = stat, 1 //値を返す変数の初期値 MousePos = ginfo_mx, ginfo_my ScreenToClient hListview, varptr(MousePos) //マウス座標をリストビュー上の座標に変換 sendmsg hListview, LVM_GETTOPINDEX //リストビューの先頭に表示されているアイテム。アイテムが多くスクロールしていたら"0"ではない TopIndex = stat sendmsg hListview, LVM_GETCOUNTPERPAGE //画面上に表示されているアイテム数を取得 //マウス座標がアイテムのY座標内か判定していく repeat stat, TopIndex //先頭のアイテムから表示アイテム数だけ繰り返す dim RECT, 4 sendmsg hListview, LVM_GETITEMRECT, cnt, varptr(RECT) //アイテムのリストビュー上の座標を取得 if((RECT(1) <= MousePos(1)) & (MousePos(1) <= RECT(3))) { //アイテムの範囲内ならば Dst(0) = cnt //そのアイテムのインデックス Dst(1) = 0 //インサートマークを下に表示するdwFlagsフラグを消す break } loop return //ドラッグ中のインサートマーク表示 #deffunc Draging int hListview, local Index, local RECT, local ItemRECT, local MoveX, local MoveY //マウス座標がリストビュー上ならばインサートマーク表示 if(WindowFromPoint(ginfo_mx, ginfo_my) == hListview) { NearHITTEST hListview, Index Insertmark hListview, Index(0)-Index(1), Index(1) //マウスをドラッグしたままリストビューの外に出たらスクロールする。ドラッグ&ドロップ中はSetCaptureでマウスキャプチャしているためウィンドウ外もマウス移動を取得可能 } else { Insertmark hListview, -1 //インサートマークを削除 dim ItemRECT, 4 sendmsg hListview, LVM_GETITEMRECT, 0, varptr(ItemRECT) //先頭のアイテムの表示サイズを取得 dim RECT, 4 GetWindowRect hListview, varptr(RECT) //リストビューの画面上の位置を取得 if(RECT(0) > ginfo_mx) : MoveX = -1 //マウスがリストビューの左側ならば横軸のスクロール量を-1 if(RECT(1) > ginfo_my) : MoveY = -(ItemRECT(3)-ItemRECT(1)) //アイテムの縦幅の半分以上を指定しなければLVM_SCROLLは縦スクロールを行わない if(RECT(2) < ginfo_mx) : MoveX = 1 if(RECT(3) < ginfo_my) : MoveY = ItemRECT(3)-ItemRECT(1) sendmsg hListview, LVM_SCROLL, MoveX, MoveY //リストビューをスクロール } return //ドラッグ&ドロップ中にボタンを離す #deffunc OnDrop int hListview, local Index, local prm, local Item //リストビュー上でマウスボタンを離した場合は並べ替えを行う if(WindowFromPoint(ginfo_mx, ginfo_my) == hListview) { //ドラッグ&ドロップ用並べ替えコールバック関数を作成していなければ作成 if(gpDragDropSort == 0) : newclbk3 gpDragDropSort, 3, *DragDropSort //アイテムを並べ替え NearHITTEST hListview, Index //マウス下のアイテムのインデックスを取得 sendmsg hListview, LVM_SORTITEMSEX, 0, gpDragDropSort //アイテムをソート } Insertmark hListview, -1 //インサートマークを削除 ReleaseCapture //マウスキャプチャを開放 return //ドラッグ&ドロップ用並べ替えコールバック関数 //ドロップ先のインデックスより手前のアイテムを"0"、インデックスより後方のアイテムを"2"、移動するアイテムを"1"として並べ替えを行う //LVM_SORTITEMSEXでのソートは安定ソートなのでこの方法でのアイテムの移動が可能 *DragDropSort clbkargprotect prm //"0"での初期化を兼ねて配列確保 dim Item, 2 //ドロップ先のインデックスより後方ならば"2"を代入 if(prm(0) >= Index) : Item(0) = 2 if(prm(1) >= Index) : Item(1) = 2 //選択されていたら"1"を代入 sendmsg hListview, LVM_GETITEMSTATE, prm(0), LVIS_SELECTED //アイテムの選択を確認 if(stat) : Item(0) = 1 //選択されているなら"1"を代入 sendmsg hListview, LVM_GETITEMSTATE, prm(1), LVIS_SELECTED if(stat) : Item(1) = 1 return Item(0) - Item(1) #global



可憐

リンク

2015/4/28(Tue) 23:55:54|NO.68866

リストビュー研究中様

先日下記の板でリストビューの件でお世話になりました

http://hsp.tv/play/pforum.php?mode=all&num=68455

とても使い勝手がいいので使わして頂きます。
ありがとうございます。



リストビュー研究中

リンク

2015/5/8(Fri) 19:19:20|NO.69069

モジュールを作り直しました。変更点は
・グループ表示では並べ替えできないので判定を入れた
・アイコン表示と小さいアイコン表示ではアイテムの位置を変更する処理とした
・LVM_INSERTMARKHITTESTという便利なメッセージを使用した(内部処理の変更)

前バージョンと同じくリストビュー作成後に

AutoDragDrop リストビューのオブジェクトID
と記述するだけで、選択アイテムがドラッグ&ドロップで並べ替えできるようになります

長くなりますがソースです

#ifndef _MODCLBK3B2_AS #ifdef _MODCLBK3A1_AS #undef _MODCLBK3A1_AS #undef newclbk3 #undef clbkargprotect #undef CLBKMODE_CDECL #undef _newclbk3 #undef modclbk_term #endif #ifdef _MODCLBK3B2_AS #undef clbk_getthisptr #endif #define global _MODCLBK3A1_AS #define global _MODCLBK3B1_AS #define global _MODCLBK3B2_AS #define global _MODCLBK3B3_AS #define global newclbk3(%1,%2 = 0,%3,%4 = 0) tmpclbklb@modclbk3b3=%3:%1=_newclbk3(%2,tmpclbklb@modclbk3b3,%4) //新しい関数ポインタを取得する // %1...関数ポインタを受け取る変数 // %2...引数の数 // %3...呼び出されるラベル // %4...作成のモード(CLBKMODE) #define global clbkargprotect(%1) lp@modclbk3b3=lparam:wp@modclbk3b3=wparam:dupptr args@modclbk3b3,lp@modclbk3b3,wp@modclbk3b3*4,4:dim %1,wp@modclbk3b3:memcpy %1,args@modclbk3b3,wp@modclbk3b3*4 //引数を取得する // %1...引数を受け取るための変数 #module "modclbk3b2" #define ctype uintbitshiftright(%1,%2) (((%1&$7fffffff)>>%2)|((1&(%1>>31))<<(31-%2))) #uselib "msvcrt.dll" #cfunc malloc "malloc" int #func free "free" int #uselib "kernel32.dll" #func VirtualProtect "VirtualProtect" var,int,int,var #cfunc LoadLibrary "LoadLibraryA" sptr #cfunc GetProcAddress "GetProcAddress" int,sptr #func FreeLibrary "FreeLibrary" int #define global CLBKMODE_CDECL $00000001 // 呼び出し規約をcdeclに設定する // 呼び出し規約をthiscallに設定する #defcfunc _newclbk3 int _argmax,var clbklb,int mode // int _argmax ... 関数の引数の数 // var clbklb ... 呼び出すサブルーチンが入った変数 // int mode ... コールバック関数のモード(CLBKMODE_) dim _x,1 mref ctx,68 ilb=0 memcpy ilb,clbklb,4,0,0 argmax = _argmax if inited == 0{ inited = 1 dim ptrtable ptrmax = 0 hcrt = LoadLibrary("msvcrt.dll") ptrtomalloc = GetProcAddress(hcrt,"malloc") ptrtofree = GetProcAddress(hcrt,"free") thisptr = 0 } code_callptr = lpeek(ctx,168 + 48)// if argmax>0{ dim clbk,57 clbk(0) = $83ec8b55,$45c730ec,$000000fc,$f845c700 clbk(4) = $00000000,$00e045c7,$c7000000,$0000e445 clbk(8) = $45c70000,$000000ec,$d845c700,$00000000 clbk(12) = $8bd84d89,$e0c1f845,$4d8b5002,$83d1ffe0 clbk(16) = $458904c4,$f445c7d4,$00000000,$00dc45c7 clbk(20) = $c7000000,$0000f045,$45c70000,$000000e8 clbk(24) = $0c558d00,$8be85589,$4d8bd445,$c7088908 clbk(28) = $0001d045,$09eb0000,$83d0558b,$558901c2 clbk(32) = $f8458bd0,$7dd04539,$e84d8b1a,$8904c183 clbk(36) = $558be84d,$d4458bd0,$8be84d8b,$0c89fc49 clbk(40) = $8bd5eb90,$458bf455,$8b0289f8,$558bdc4d clbk(44) = $681189d4,$00000000,$ffec458b,$04c483d0 clbk(48) = $8bf04d8b,$fc558911,$00e845c7,$8b000000 clbk(52) = $8b50d445,$d1ffe44d,$8b04c483,$e58bfc45 clbk(56) = $0000c25d lpoke clbk,$10,argmax:lpoke clbk,$17,ptrtomalloc:lpoke clbk,$1e,ptrtofree lpoke clbk,$25,code_callptr:lpoke clbk,$2c,varptr(thisptr) lpoke clbk,$48,varptr(ctx) + 36:lpoke clbk,$4f,varptr(ctx) + 40 lpoke clbk,$56,varptr(ctx) + 784:lpoke clbk,$b4,ilb if ((mode & $f) == CLBKMODE_CDECL) == 0:wpoke clbk,$e2,(argmax * 4) & $ffff funcsize = 228 } if argmax==0{ dim clbk,25 clbk(0) = $83ec8b55,$45c718ec,$000000fc,$f045c700 clbk(4) = $00000000,$00f845c7,$c7000000,$0000e845 clbk(8) = $45c70000,$000000f4,$ec45c700,$00000000 clbk(12) = $8bec4d89,$00c7f845,$00000000,$c7e84d8b clbk(16) = $00000001,$00006800,$558b0000,$83d2fff0 clbk(20) = $458b04c4,$89088bf4,$458bfc4d,$5de58bfc clbk(24) = $000000c3 lpoke clbk,$10,code_callptr:lpoke clbk,$17,varptr(ctx) + 36 lpoke clbk,$1e,varptr(ctx) + 40:lpoke clbk,$25,varptr(ctx) + 784 lpoke clbk,$2c,varptr(thisptr):lpoke clbk,$46,ilb funcsize = 100 } clbkptr = malloc(funcsize) dupptr clbkfunc,clbkptr,funcsize,4 memcpy clbkfunc,clbk,funcsize VirtualProtect clbkfunc,funcsize,$40,_x ptrtable(ptrmax) = clbkptr ptrmax++ return clbkptr #defcfunc clbk_getthisptr //Thisポインタを取得する。 //コールバックとして呼び出された直後に別変数へコピーしなければならない。 return thisptr #deffunc modclbk_term onexit repeat ptrmax free ptrtable(cnt) loop if inited{ FreeLibrary hcrt } ptrmax = 0 return #global #endif #module #uselib "User32.dll" #func SetWindowLong "SetWindowLongA" int, int, int #func CallWindowProc "CallWindowProcA" int,int,int,int,int //各種定数 #define WM_NOTIFY 0x0000004E #define GWL_WNDPROC 0xFFFFFFFC #define WM_MOUSEMOVE 0x00000200 #define WM_LBUTTONUP 0x00000202 #define NM_MOUSEMOVE 0xFFFFFFE7 //自作の通知メッセージ #define NM_LBUTTONUP 0xFFFFFFE6 //自作の通知メッセージ #deffunc AutoDragDrop int ObjID ghListview = objinfo_hwnd(ObjID) oncmd gosub *OnNotify, WM_NOTIFY //以下、リストビューのサブクラス化処理 newclbk3 gpStaticProc, 4, *StaticProc //リストビューのサブクラス化のためのコールバック関数を登録 SetWindowLong ghListview, GWL_WNDPROC, gpStaticProc //リストビューをサブクラス化 gDefLvProc = stat //リストビューのデフォルトのウィンドウプロシージャ gMyNHNMHDR = ghListview, 0, 0 //自作のNHNMHDR構造体を宣言。第一要素は必ずリストビューのハンドル return //サブクラス化したリストビューのメッセージ処理 *StaticProc clbkargprotect gClbkPrm //メッセージにより分岐 switch gClbkPrm(1) //リストビュー上でマウスが移動した case WM_MOUSEMOVE gMyNHNMHDR(2) = NM_MOUSEMOVE //自作の通知メッセージ sendmsg hwnd, WM_NOTIFY, 0, varptr(gMyNHNMHDR) //HSPのウィンドウに通知メッセージを送る swbreak //左ボタンを離した case WM_LBUTTONUP gMyNHNMHDR(2) = NM_LBUTTONUP //自作の通知メッセージ sendmsg hwnd, WM_NOTIFY, 0, varptr(gMyNHNMHDR) //HSPのウィンドウに通知メッセージを送る swbreak //上記のメッセージでなければそのままリストビューに送る default CallWindowProc gDefLvProc, gClbkPrm(0),gClbkPrm(1),gClbkPrm(2),gClbkPrm(3) swbreak swend return //WM_NOTIFYが届いたときのサブルーチン *OnNotify NotifyProc lparam, ghListview//lparamとリストビューのハンドルを引数に命令を呼び出す return stat //HSPはモジュール終了→オブジェクトの破棄の処理の流れなので、モジュールの終了の際にサブクラス化の解除をしなければリストビューにWM_DESTROYが届かない #deffunc ExitProc onexit SetWindowLong ghListview, GWL_WNDPROC, gDefLvProc //デフォルトのウィンドウプロシージャに戻す return #global #module #uselib "User32.dll" #func ScreenToClient "ScreenToClient" int, int #func SetCapture "SetCapture" int #func ReleaseCapture "ReleaseCapture" #cfunc WindowFromPoint "WindowFromPoint" int, int #func GetWindowRect "GetWindowRect" int, int #func GetWindowLong "GetWindowLongA" int, int #cfunc GetDesktopWindow "GetDesktopWindow" #uselib "comctl32.dll" #func ImageList_Destroy "ImageList_Destroy" int #func ImageList_BeginDrag "ImageList_BeginDrag" int,int,int,int #func ImageList_DragEnter "ImageList_DragEnter" int,int,int #func ImageList_DragMove "ImageList_DragMove" int,int #func ImageList_DragLeave "ImageList_DragLeave" int #func ImageList_EndDrag "ImageList_EndDrag" #func ImageList_Merge "ImageList_Merge" int,int,int,int,int,int //各種定数 #define GWL_STYLE 0xFFFFFFF0 //ウィンドウのスタイル取得 #define LV_VIEW_ICON 0x00000000 //アイコン表示(リストビューの種類) #define LV_VIEW_SMALLICON 0x00000002 //小さいアイコン表示(リストビューの種類) #define LV_VIEW_TILE 0x00000004 //タイル表示(リストビューの種類) #define LVS_AUTOARRANGE 0x00000100 //アイテムの自動整列(リストビューのスタイル) #define LVM_GETITEMRECT 0x0000100E //アイテムの描画サイズを取得 #define LVM_SCROLL 0x00001014 //リストビューをスクロール #define LVM_GETITEMSTATE 0x0000102C //アイテムの状態取得 #define LVM_SORTITEMSEX 0x00001051 //アイテムを並べ替え #define LVM_SETINSERTMARK 0x000010A6 //インサートマーク表示 #define LVM_GETNEXTITEM 0x0000100C //条件設定によるアイテムの検索 #define LVM_INSERTMARKHITTEST 0x000010A8 //インサートマークの表示位置取得 #define LVM_GETVIEW 0x0000108F //リストビューの種類を取得 #define LVM_ISGROUPVIEWENABLED 0x000010AF //グループ表示の確認 #define LVM_GETINSERTMARK 0x000010A7 //インサートマークの表示アイテム取得 #define LVM_CREATEDRAGIMAGE 0x00001021 //ドラッグイメージ作成 #define LVM_GETORIGIN 0x00001029 //リストビューの表示されている左上の座標(スクロールで移動していたら"0"でない) #define LVM_GETITEMPOSITION 0x00001010 //アイテムの表示座標 #define LVM_SETITEMPOSITION32 0x00001031 //指定座標にアイテムを移動 #define LVIS_SELECTED 0x00000002 //選択状態を取得(LVM_GETITEMSTATEの定数) #define LVNI_SELECTED 0x00000002 //選択されたアイテム(LVM_GETNEXTITEMの定数) #define LVN_BEGINDRAG 0xFFFFFF93 //左ボタンでのドラッグ開始(通知メッセージ) #define NM_MOUSEMOVE 0xFFFFFFE7 //マウス移動(自作の通知メッセージ) #define NM_LBUTTONUP 0xFFFFFFE6 //左ボタンアップ(自作の通知メッセージ) //WM_NOTIFYの通知メッセージを処理する命令 #deffunc NotifyProc int _lparam, int hListview, local NMHDR //NMHDR 構造体の割り当て dupptr NMHDR, _lparam, 3*4 //通知メッセージがリストビューからでなければ戻る if(NMHDR(0) != hListview) : return 0 //通知メッセージにより処理を分岐 switch NMHDR(2) //ドラッグ&ドロップ開始 case LVN_BEGINDRAG //グループ表示ではD&Dは行わない sendmsg hListview, LVM_ISGROUPVIEWENABLED //グループ表示の確認 if(stat == 0) { //グループ表示でなければ SetCapture hListview //リストビュー外でクリックを離した時のためマウスキャプチャ開始 gDragDropFlag = 1 //ドラッグ&ドロップのフラグを立てる //リストビューの種類によりドラッグ&ドロップの方法を切り替える sendmsg hListview, LVM_GETVIEW //種類を確認 //アイコン表示、小さいアイコン表示、タイル表示ならば if((stat == LV_VIEW_ICON) | (stat == LV_VIEW_SMALLICON) | (stat == LV_VIEW_TILE)) { //LVS_AUTOARRANGEが指定されていなければ、並べ替えでなくアイコンを移動する方法でドラッグ&ドロップ処理 GetWindowLong hListview, GWL_STYLE //リストビューのスタイルを取得 if((stat & LVS_AUTOARRANGE) == 0) { //LVS_AUTOARRANGEが指定されていなければ OnDragIcon hListview //ドラッグイメージ作成 gDragDropFlag = 2 //フラグを"2"に } } } swbreak //マウスが移動した(自作の通知メッセージ) case NM_MOUSEMOVE if(gDragDropFlag == 1) : Draging hListview //フラグが"1"ならばインサートマークを表示 if(gDragDropFlag == 2) : DragingIcon hListview //フラグが"2"ならばドラッグイメージを移動 swbreak //左ボタンを離した(自作の通知メッセージ) case NM_LBUTTONUP if(gDragDropFlag) { //ドラッグ&ドロップのフラグがあれば if(gDragDropFlag == 1) { //フラグが"1"ならばマウス下にアイテムを移動 OnDrop hListview } else { OnDropIcon hListview //それ以外("2")ならばアイコンを移動 } gDragDropFlag = 0 //ドラッグ&ドロップのフラグを消す ReleaseCapture //マウスキャプチャを開放 } swbreak swend return 0 //ドラッグ中のインサートマーク表示 #deffunc Draging int hListview, local POINT, local LVINSERTMARK, local RECT, local ItemRECT, local MoveX, local MoveY //LVINSERTMARK構造体を宣言 dim LVINSERTMARK, 4 LVINSERTMARK(0) = length(LVINSERTMARK)*4 //第一要素は構造体のサイズ //マウス座標がリストビュー上ならばインサートマーク表示 if(WindowFromPoint(ginfo_mx, ginfo_my) == hListview) { //インサートマークの表示位置を自動で取得し、表示する POINT = ginfo_mx, ginfo_my ScreenToClient hListview, varptr(POINT) //マウス座標をリストビューの座標に変換 sendmsg hListview, LVM_INSERTMARKHITTEST, varptr(POINT), varptr(LVINSERTMARK) //LVM_INSERTMARKHITTESTを使用するとLVINSERTMARK構造体に値を自動でセットしてくれる sendmsg hListview, LVM_SETINSERTMARK, 0, varptr(LVINSERTMARK) //インサートマークを表示 //マウスをドラッグしたままリストビューの外に出たらスクロールする。ドラッグ&ドロップ中はSetCaptureでマウスキャプチャしているためウィンドウ外もマウス移動を取得可能 } else { //インサートマークを消す LVINSERTMARK(2) = -1 sendmsg hListview, LVM_SETINSERTMARK, 0, varptr(LVINSERTMARK) //自動でスクロールの処理 dim ItemRECT, 4 sendmsg hListview, LVM_GETITEMRECT, 0, varptr(ItemRECT) //先頭のアイテムの表示サイズを取得 dim RECT, 4 GetWindowRect hListview, varptr(RECT) //リストビューの画面上の位置を取得 if(RECT(0) > ginfo_mx) : MoveX = -1 //マウスがリストビューの左側ならば横軸のスクロール量を-1 if(RECT(1) > ginfo_my) : MoveY = -(ItemRECT(3)-ItemRECT(1)) //アイテムの縦幅の半分以上を指定しなければLVM_SCROLLは縦スクロールを行わない if(RECT(2) < ginfo_mx) : MoveX = 1 if(RECT(3) < ginfo_my) : MoveY = ItemRECT(3)-ItemRECT(1) sendmsg hListview, LVM_SCROLL, MoveX, MoveY //リストビューをスクロール } return //ドラッグ&ドロップ中にボタンを離す #deffunc OnDrop int hListview, local LVINSERTMARK, local Index, local prm, local Item //LVINSERTMARK構造体を宣言 dim LVINSERTMARK, 4 LVINSERTMARK(0) = length(LVINSERTMARK)*4 //第一要素は構造体のサイズ //リストビュー上でマウスボタンを離した場合は並べ替えを行う if(WindowFromPoint(ginfo_mx, ginfo_my) == hListview) { //ドラッグ&ドロップ用並べ替えコールバック関数を作成していなければ作成 if(gpDragDropSort == 0) : newclbk3 gpDragDropSort, 3, *DragDropSort //インサートマークの位置を取得 sendmsg hListview, LVM_GETINSERTMARK, 0, varptr(LVINSERTMARK) //インサートマークの表示位置を取得 Index = LVINSERTMARK(2)+(0x1 & LVINSERTMARK(1)) //挿入するアイテムの位置を取得。dwFlagsには"0x8000000"がなぜか付与されているため1ビットのみ取得する //アイテムを並べ替え sendmsg hListview, LVM_SORTITEMSEX, 0, gpDragDropSort //アイテムをソート } //インサートマークを消す LVINSERTMARK(2) = -1 sendmsg hListview, LVM_SETINSERTMARK, 0, varptr(LVINSERTMARK) return //ドラッグ&ドロップ用並べ替えコールバック関数 //ドロップ先のインデックスより手前のアイテムを"0"、インデックスより後方のアイテムを"2"、移動するアイテムを"1"として並べ替えを行う //LVM_SORTITEMSEXでのソートは安定ソートなのでこの方法でのアイテムの移動が可能 *DragDropSort clbkargprotect prm //"0"での初期化を兼ねて配列確保 dim Item, 2 //ドロップ先のインデックスより後方ならば"2"を代入 if(prm(0) >= Index) : Item(0) = 2 if(prm(1) >= Index) : Item(1) = 2 //選択されていたら"1"を代入 sendmsg hListview, LVM_GETITEMSTATE, prm(0), LVIS_SELECTED //アイテムの選択を確認 if(stat) : Item(0) = 1 //選択されているなら"1"を代入 sendmsg hListview, LVM_GETITEMSTATE, prm(1), LVIS_SELECTED if(stat) : Item(1) = 1 return Item(0) - Item(1) //ドラッグイメージを作成 #deffunc OnDragIcon int hListview, local POINT, local Index, local hDragImageList, local minX, local minY, local hOneImageList, local hTempImageList //POINT構造体を宣言 dim POINT, 2 //先頭の選択アイテムを取得 sendmsg hListView, LVM_GETNEXTITEM, -1, LVNI_SELECTED Index = stat //選択アイテムのドラッグイメージを作成していく //LVM_CREATEDRAGIMAGEで簡単に作成できるが、二つ目からはImageList_Mergeでまとめていかなければならない while (Index > -1) //選択アイテムが見つかれば if(hDragImageList == 0) { //ドラッグイメージのハンドルが"0" = まだ作成していなければ sendmsg hListview, LVM_CREATEDRAGIMAGE, Index, varptr(POINT) //ドラッグイメージを作成 hDragImageList = stat //ハンドルを代入 minX = POINT(0) //イメージリストの左端 minY = POINT(1) //イメージリストの上端 } else { //ドラッグイメージが作成されていたら sendmsg hListview, LVM_CREATEDRAGIMAGE, Index, varptr(POINT) //ドラッグイメージを作成 hOneImageList = stat //ハンドルを代入 ImageList_Merge hDragImageList, 0, hOneImageList, 0, POINT(0)-minX,POINT(1)-minY //以前のドラッグイメージと結合 hTempImageList = stat //ハンドルを代入 ImageList_Destroy hOneImageList //一つのみのドラッグイメージを破棄 ImageList_Destroy hDragImageList //以前のドラッグイメージを破棄 hDragImageList = hTempImageList //結合したドラッグイメージのハンドルを代入 if(POINT(0)<minX) : minX = POINT(0) //ドラッグイメージが左方向に広がっていたら最小値を変更 if(POINT(1)<minY) : minY = POINT(1) //ドラッグイメージが上方向に広がっていたら最小値を変更 } sendmsg hListView, LVM_GETNEXTITEM, Index, LVNI_SELECTED //次の選択アイテムを取得 Index = stat wend //画面上のマウス座標をリストビュー上のマウス座標に変換。ドラッグイメージの表示位置に必要 POINT(0) = ginfo_mx //画面上のマウスのX座標 POINT(1) = ginfo_my //画面上のマウスのY座標 ScreenToClient hListview, varptr(POINT) //リストビュー上のマウス座標に変換 //ドラッグイメージを表示 ImageList_BeginDrag hDragImageList, 0, POINT(0)-minX, POINT(1)-minY //ドラッグイメージを表示 ImageList_DragEnter GetDesktopWindow(), ginfo_mx,ginfo_my //ディスクトップ = 全てのウィンドウ上でドラッグイメージを表示 //今後の処理のためグローバル変数に代入 ghDragImageList = hDragImageList gMousePOS_DragDrop(0) = ginfo_mx gMousePOS_DragDrop(1) = ginfo_my ScreenToClient hListview, varptr(gMousePOS_DragDrop) //リストビュー上のマウス座標に変換 sendmsg hListview, LVM_GETORIGIN, 0, varptr(POINT) //リストビューの表示されている左上座標を取得 gMousePOS_DragDrop(0) += POINT(0) //左上座標を追加。これを行わないとD&D中にスクロールすると正しい座標を取得できない gMousePOS_DragDrop(1) += POINT(1) return //ドラッグイメージの移動 #deffunc DragingIcon int hListview, local RECT, local MoveX, local MoveY //ドラッグイメージを移動 ImageList_DragMove ginfo_mx,ginfo_my //マウスをドラッグしたままリストビューの外に出たらスクロールする。ドラッグ&ドロップ中はSetCaptureでマウスキャプチャしているためウィンドウ外もマウス移動を取得可能 if(WindowFromPoint(ginfo_mx, ginfo_my) != hListview) { dim RECT,4 GetWindowRect hListview, varptr(RECT) //リストビューの画面上の位置を取得 if(RECT(0) > ginfo_mx) : MoveX = -1 //マウスがリストビューの左側ならば横軸のスクロール量を-1 if(RECT(1) > ginfo_my) : MoveY = -1 //マウスがリストビューの上側ならば縦軸のスクロール量を-1 if(RECT(2) < ginfo_mx) : MoveX = 1 if(RECT(3) < ginfo_my) : MoveY = 1 sendmsg hListview, LVM_SCROLL, MoveX, MoveY //リストビューをスクロール } return //アイテムの移動 #deffunc OnDropIcon int hListview, local POINT, local MousePOS, local Index //イメージリストを使用したドラッグ&ドロップの終了処理。この三つが決まり事らしい ImageList_DragLeave GetDesktopWindow() //表示していたウィンドウのドラッグイメージを消去 ImageList_EndDrag //ドラッグ&ドロップ終了 ImageList_Destroy ghDragImageList //イメージリストの破棄 //リストビュー上でマウスボタンを離した場合は選択アイテムを移動する if(WindowFromPoint(ginfo_mx, ginfo_my) == hListview) { //現在のマウス座標をリストビュー上に変換 MousePOS = ginfo_mx, ginfo_my ScreenToClient hListview, varptr(MousePOS) //リストビュー上のマウス座標に変換 dim POINT, 2 sendmsg hListview, LVM_GETORIGIN, 0, varptr(POINT) //リストビューの表示されている左上座標を取得 MousePOS(0) += POINT(0) //左上座標を追加。これを行わないとD&D中にスクロールすると正しい座標を取得できない MousePOS(1) += POINT(1) sendmsg hListview, LVM_GETNEXTITEM, -1, LVNI_SELECTED //選択アイテムを取得 Index = stat while (Index != -1) //選択アイテムが見つかっていたら繰り返す sendmsg hListview, LVM_GETITEMPOSITION, Index, varptr(POINT) //アイテムの位置を取得 POINT(0) += MousePOS(0)-gMousePOS_DragDrop(0) //D&D開始時からのマウスの移動量を追加 POINT(1) += MousePOS(1)-gMousePOS_DragDrop(1) //リストビューのスクロールに対応するためリストビュー上の座標で計算している sendmsg hListview, LVM_SETITEMPOSITION32, Index, varptr(POINT) //アイテムの移動 sendmsg hListview, LVM_GETNEXTITEM, Index, LVNI_SELECTED //次の選択アイテムを取得 Index = stat wend } return #global



ONION software Copyright 1997-2023(c) All rights reserved.