プロが教える店舗&オフィスのセキュリティ対策術

こんにちは。Windows上でプログラムをしています。
ツリーコントロールをダイアログに貼り付けているのですが、開閉アイコン「+」「-」のアイコン変更はできるものなのでしょうか?
「+」「-」のアイコンをVisualStudioのプロジェクトのプロパティダイアログの左ペインに表示されているような三角形に変更したいと思っています。

A 回答 (1件)

 こんにちは。


 「+/-」ボタンの変更は出来ないようですので、カスタムドローを使って描くしか道は無いのかもしれません。

 http://lhsp.s206.xrea.com/misc/customdraw.html
 http://www.kumei.ne.jp/c_lang/sdk3/sdk_262.htm

 ダイアログの戻り値はTRUE/FALSEなので、カスタムドローメッセージの戻り値の為に、
 SetWindowLong(hDlg, DWL_MSGRESULT, lResult)
 を必ず呼び出します。

 取り合えず以下は「+/-」ボタンに見立てて「!アイコン」と「?アイコン」をイメージリストにしてから、子持ちのツリーアイテムの横に描かせています。
 阿弥陀籤の様な線は自前で描こうとすると地獄そのものなので、割愛しています。参考程度に。

#include<windows.h>
#include<commctrl.h>
#include<tchar.h>
#include"resource.h"
#pragma comment(lib, "comctl32.lib")

#define ArrayCount(a) (sizeof(a)/sizeof(a[0]))

const LPCTSTR TSTR_IMGLIST = TEXT("image list");

typedef struct tagMessage
{
union
{
HWND hWnd;
HWND hDlg;
HWND hCtl;
};
UINT uMsg;
WPARAM wParam;
LPARAM lParam;
} Message;

static void TreeView_SetLParam(HWND hTV, HTREEITEM hTreeItem)
{
TVITEM item = {TVIF_PARAM};
item.lParam = (LPARAM)hTreeItem;
item.hItem = hTreeItem;
TreeView_SetItem(hTV, &item);
}

static HTREEITEM TreeView_Add(HWND hTV, HTREEITEM hTreeParent, LPCTSTR pszItem)
{
TVINSERTSTRUCT tvi = {0};
tvi.hParent = hTreeParent;
tvi.item.mask = TVIF_TEXT;
tvi.item.pszText = (LPTSTR)pszItem;

HTREEITEM hTreeItem = TreeView_InsertItem(hTV , &tvi);
::TreeView_SetLParam(hTV, hTreeItem);
return hTreeItem;
}

static void OnTVCustomDraw(Message& m, const LPNMTVCUSTOMDRAW p)
{
TCHAR sItem[256] = {0};
HIMAGELIST hImgList = (HIMAGELIST)::GetProp(m.hDlg, TSTR_IMGLIST);
HTREEITEM hTreeItem = (HTREEITEM)p->nmcd.lItemlParam;

//ツリーアイテムからアイテム情報を取り出す
TVITEM item = {TVIF_TEXT | TVIF_CHILDREN | TVIF_STATE};
item.hItem = hTreeItem;
item.pszText = sItem;
item.cchTextMax = ArrayCount(sItem);
TreeView_GetItem(p->nmcd.hdr.hwndFrom, &item);

const DWORD dwDTStyle = DT_LEFT | DT_VCENTER | DT_SINGLELINE;

//ツリーアイテム欄の高さ
const LONG lHeight = p->nmcd.rc.bottom - p->nmcd.rc.top;
RECT rcText = {(p->iLevel + 1) * lHeight, p->nmcd.rc.top, p->nmcd.rc.right, p->nmcd.rc.bottom};

//正確なテキスト領域を取る
::DrawText(p->nmcd.hdc, sItem, ::_tcslen(sItem), &rcText, dwDTStyle | DT_CALCRECT);

//テキスト領域を塗り潰す(クリックする度にフォーカスの残骸が残る為)
::FillRect(p->nmcd.hdc, &rcText, (HBRUSH)::GetStockObject(WHITE_BRUSH));

//テキストを書き込む
::DrawText(p->nmcd.hdc, sItem, ::_tcslen(sItem), &rcText, dwDTStyle);

//ツリーアイテムが子持ち
if(item.cChildren == 1)
{
//イメージリストの使用位置を決める
const INT nIndex = (item.state & TVIS_EXPANDED) ? 0 : 1;
::ImageList_Draw(hImgList, nIndex, p->nmcd.hdc, p->iLevel * lHeight, p->nmcd.rc.top, ILD_NORMAL);
}

//フォーカスを描く
if(p->nmcd.uItemState == (CDIS_FOCUS | CDIS_SELECTED))
::DrawFocusRect(p->nmcd.hdc, &rcText);
}

static LRESULT OnInitDialog(Message& m)
{
//イメージリストの準備
HIMAGELIST hImgList = ::ImageList_Create(14, 14, ILC_COLOR32 | ILC_MASK, 2, 1);
::ImageList_AddIcon(hImgList, ::LoadIcon(NULL, IDI_QUESTION));
::ImageList_AddIcon(hImgList, ::LoadIcon(NULL, IDI_ASTERISK));
::SetProp(m.hDlg, TSTR_IMGLIST, hImgList);

//適当にツリーを作る
HWND hTV = ::GetDlgItem(m.hDlg, IDC_TREE1);

HTREEITEM hTreeNest = NULL;
HTREEITEM hTreeItem = ::TreeView_Add(hTV, TVI_ROOT, TEXT("parent1"));
::TreeView_Add(hTV, hTreeItem, TEXT("item1"));
hTreeNest = ::TreeView_Add(hTV, hTreeItem, TEXT("item1"));
::TreeView_Add(hTV, hTreeNest, TEXT("item2"));
::TreeView_Add(hTV, hTreeItem, TEXT("item3"));

::TreeView_Add(hTV, TVI_ROOT, TEXT("parent2"));
hTreeNest = ::TreeView_Add(hTV, TVI_ROOT, TEXT("parent3"));
::TreeView_Add(hTV, hTreeNest, TEXT("item1"));

return 0;
}

static LRESULT OnNotify(Message& m)
{
LPNMTVCUSTOMDRAW p = (LPNMTVCUSTOMDRAW)m.lParam;

if(p->nmcd.hdr.idFrom != IDC_TREE1)
return FALSE;

if(p->nmcd.hdr.code != NM_CUSTOMDRAW)
return FALSE;

switch (p->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
::SetWindowLong(m.hDlg, DWL_MSGRESULT, CDRF_NOTIFYITEMDRAW);
return TRUE;

case CDDS_ITEMPREPAINT:
::OnTVCustomDraw(m, p);
::SetWindowLong(m.hDlg, DWL_MSGRESULT, CDRF_SKIPDEFAULT);
return TRUE;
}
return 0;
}

static LRESULT OnClose(Message& m)
{
HIMAGELIST hImgList = (HIMAGELIST)::GetProp(m.hDlg, TSTR_IMGLIST);
::ImageList_Destroy(hImgList);
::RemoveProp(m.hDlg, TSTR_IMGLIST);
::DestroyWindow(m.hDlg);
return 0;
}

int CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
Message m = {hDlg, uMsg, wParam, lParam};
switch(uMsg)
{
case WM_INITDIALOG:
::OnInitDialog(m);
break;

case WM_NOTIFY:
::OnNotify(m);
break;

case WM_CLOSE:
::OnClose(m);
break;

case WM_DESTROY:
PostQuitMessage(0);
break;

default:
return FALSE;
}
return TRUE;
}

int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
::InitCommonControls();
HWND hWnd = ::CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, &::DlgProc, 0);
::ShowWindow(hWnd, nCmdShow);

while(::GetMessage(&msg, NULL, 0, 0) == TRUE)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return msg.wParam;
}
    • good
    • 0
この回答へのお礼

こんにちは。
カスタムドローについては自分も同じ結論に至りましたが、ではどうしたものかと悩んでいました。
非常に詳しいサンプルをありがとうございます。
未熟なためちょっとまだうまく動いてはくれませんが、いろいろ試したいと思います。
ありがとうこざいました。

お礼日時:2009/08/02 00:09

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!