|
|
|
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
コピペで思い切り間違えていました
誤「と記述するだけで、カラムをクリックするとソートされるようになります」
正「と記述するだけで、選択アイテムがドラッグ&ドロップで並べ替えできるようになります」
|
|
2015/4/28(Tue) 18:06:10|NO.68832
16行目でエラーが発生しています。
「文法が間違っています」
ということです。
windows7の64bit、メモリは4GBです。
|
|
2015/4/28(Tue) 18:24:11|NO.68834
kanamaruさんと同じエラーが発生します。
コールバックのモジュールは著作権フリーで自由に配布できるそうなので、
一式まとめたものをzipで配布してみてはどうでしょうか?
正直今の状態だと試すにも面倒で・・・
|
|
2015/4/28(Tue) 19:22:03|NO.68840
無事実行できました。
windows8.1 x64、メモリ4GBです。
|
|
2015/4/28(Tue) 19:23:20|NO.68841
今気づいたのですがひょっとしたらエラーの原因って
modclbkを内部に記述するかインクルードしてないからでは?
|
|
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 適用済み)
|
|
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/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
| |
|