スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

--.--.-- | スポンサー広告

リストビューのサブアイテムの直接編集2

前回からの続き

リストビューの初期化が終わったところで
いよいよサブアイテムの編集を行えるようにコードを実装します。

※リストビューのスタイルに LVS_EDITLABELS を指定するのを忘れずに


LRESULT APITestMain::EditLabel(LV_DISPINFO* Info)
{
switch (Info->hdr.code)
{
case LVN_BEGINLABELEDIT:
{
// ターゲット場所を調査
POINT cursor;
::GetCursorPos(&cursor);
::ScreenToClient(m_ListWnd, &cursor);

LV_COLUMN lvc;
lvc.mask = LVCF_WIDTH;

RECT rect;
ListView_GetItemRect(m_ListWnd, Info->item.iItem, &rect, LVIR_LABEL);

if(::PtInRect(&rect, cursor))
m_EditColumn = 0;

int col = 1;
while(m_EditColumn == -1 && ListView_GetColumn(m_ListWnd, col, &lvc))
{
rect.left = rect.right;
rect.right += lvc.cx;

if(::PtInRect(&rect, cursor))
m_EditColumn = col;

col++;
}

// マウスをクリックした位置がアイテム外だったら編集キャンセル
if(m_EditColumn == -1)
{
// ※1
::SetWindowLongPtr(m_hWnd, DWLP_MSGRESULT, TRUE);
return TRUE;
}

m_EditRow = Info->item.iItem;

// エディットボックスをサブクラス化
HWND edit_wnd = ListView_GetEditControl(m_ListWnd);
m_EditItem.Attach(edit_wnd);
m_EditItem.SetPos(rect.left, rect.top);

// エディットボックスのテキストの内容をターゲットのアイテムの内容に書き換え
TCHAR buffer[256] = _T("");
ListView_GetItemText(m_ListWnd, Info->item.iItem, m_EditColumn,
buffer, 255);
::SetWindowText(edit_wnd, buffer);
break;
}

case LVN_ENDLABELEDIT:
if(Info->item.pszText != NULL)
ListView_SetItemText(m_ListWnd, Info->item.iItem, m_EditColumn,
Info->item.pszText);

m_EditColumn = -1;
m_EditItem.Detach();
ListView_SetItemState(m_ListWnd, Info->item.iItem, 0,
LVNI_FOCUSED | LVNI_SELECTED);

break;
}

return FALSE;
}


# m_EditRow は編集ターゲットの行番号を
# m_EditColumn は列番号を保持しています
# m_EditItem はエディットボックスをサブクラス化するためのクラス変数、詳細は後述

やっていることは至極単純で早い話が
LVN_BEGINLABELEDIT メッセージが発行された際に
通常であれば先頭のカラムに表示されるはずのエディットボックスを
強制的に編集のターゲットとなったアイテムの場所へ移動
させています。

ちなみに呼び出し元はこうなっています。

//--------------------------------------------------------------
// ウインドウプロシージャ
//--------------------------------------------------------------
LRESULT APITestMain::WndProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{

case WM_NOTIFY:
// IDC_LISTVIEW はリストビューのリソースID
if((int)wParam == IDC_LISTVIEW)
{
LV_DISPINFO* info = reinterpret_cast<LV_DISPINFO *>(lParam);
return EditLabel(info);
}

break;

}

return FALSE;
}


さて強制的に移動させる……と言っている割には
MoveWindow API 等が出てきていません。
というのも実はアイテム編集時に出てくるエディットボックスは
内部で強制的に座標を移動させるようになっているらしく
MoveWindow API 等移動させようとしても元の位置に戻ってしまうのです。
そのためエディットボックスをサブクラス化して座標の位置を固定化させます。

# なおサブクラス化にあたって belution というサイトにある
# CWndBase クラスを使用しています
# http://techtips.belution.com/ja/vc/0009/


#include "EditSubItem.h"

// コンストラクタ
EditSubItem::EditSubItem()
{
m_Position.x = 0;
m_Position.y = 0;
}

// デストラクタ
EditSubItem::~EditSubItem()
{

}

// 固定する座標を保存
void EditSubItem::SetPos(int Left, int Top)
{
m_Position.x = Left;
m_Position.y = Top;
}

LRESULT EditSubItem::WndProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_WINDOWPOSCHANGING:
{
LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
pos->x = m_Position.x;
pos->y = m_Position.y;
break;
}
}

return CallWindowProc(m_lpfnOldWndProc, hWnd, uMsg, wParam, lParam);
}


以上で完成!
・・・・・・
実際動かしてみればわかると思いますが表示周りがおかしいことに気づくはずです。
それもそのはず、強制的にエディットボックスを動かしたのだから
当然元のアイテムの文字列が消えたままです。
しかもエディットボックスを移動した先のアイテムの文字列も
(エディットボックスの)下に表示されたままです。
これを解消するにはオーナードローを行います。

次回に続く

※1
今回ダイアログベースで作成したため
編集をキャンセルするためには直接ウインドウに返値を渡してあげる必要がある
理由は
http://blogs.msdn.com/oldnewthing/archive/2003/11/07/55619.aspx
ん~個人的にあまり納得できない( ´・ω・)
スポンサーサイト

テーマ:プログラミング - ジャンル:コンピュータ

2007.06.23 | Comments(0) | Trackback(0) | プログラム

«  | HOME |  »

ブロとも申請フォーム

この人とブロともになる

カウンター


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。