none
イメージリストコントロール 選択アイテムの境界線の色づけ RRS feed

  • 質問

  • お世話になります。

    C++/MFCのリストコントロールにて、イメージリストを使っています。

    開発環境は、VisualStudio2005 proです。

    リスト項目選択時に、境界線を色づけしたいのですが、、上手く動きません。

    シングルクリック時の下記コードなのですが、、、書き方がいけないのでしょうか・・・。

    OnNMClicklistview(NMHDR *pNMHDR, LRESULT *pResult)
    {
        LPNMITEMACTIVATE pItemAct=(LPNMITEMACTIVATE)pNMHDR;
    
         LVHITTESTINFO hitTest;
         memset(&hitTest,'\0',sizeof(LVHITTESTINFO));
         hitTest.pt=pItemAct->ptAction;
         m_listView.SendMessage(LVM_SUBITEMHITTEST,0,(LPARAM)&hitTest);
    
        m_listView.SetOutlineColor(0x000000ff);
        m_listView.Update(hitTest.iItem);
    }
    
       ※m_listlView リストビューの変数名

    よろしくお願いいたします。


    2015年11月19日 8:34

回答

  • Visual Studio 2015ではなく、Visual Studio 2005ですか?

    質問するときは実行環境(ターゲット環境)や、MFCのプロジェクト種別(ダイアログベース/SDI/MDI)などもきちんと書きましょう。

    CListCtrl::SetOutlineColor()はLVM_SETOUTLINECOLORのラッパーであり、各項目のアウトライン色を一律変更するためのものです。「アイテムを選択したときに画像の状態をアイテムごとに個別に変更する」などの処理を実装したい場合、オーバーレイを使うという方法があります。

    手元に古い開発環境がないので、VS 2015 CommunityとWindows 8.1で動作確認したコードを載せます。

    stdafx.hでvectorのヘッダーをインクルードしていることを前提にしています。また、Visual C++リソースビューで当該リストコントロールの[Owner Data]をTrueに設定してリストを仮想化し、また[View]をIconモードLVS_ICONに設定していることを前提にしています。

    ※MSDNライブラリのListView_SetItemCount/ListView_SetItemCountExの説明によると、LVS_OWNERDATAスタイルを付加して仮想化する場合は本来ListView_SetItemCountではなくListView_SetItemCountExを使うべきで、またListView_SetItemCountExはレポートモードLVS_REPORTかリストモードLVS_LISTが使われていることを前提としているようなので、IconモードLVS_ICONでは完全な仮想化が実現できないかもしれません。

    そのほか、古いVS 2005だとCDialogExafxdialogex.hまわりでコンパイルエラーになると思いますが、環境に合わせて適宜修正してください。

    ぶっちゃけレガシーなMFCにこだわる理由が特になければ、こういったGUIまわりのカスタマイズはC#/VB.NET + WPF/WinRTのほうがはるかに効率的だと思います。どうしてもMFCを選択せざるを得ない場合でも、開発環境としての新しいOSサポート、MFCの機能追加・バグ修正やC++11規格対応が強化されているVS 2012以降の環境にできるだけ早く移行することをお勧めします。

    // MfcCustomListCtrlTest1Dlg.h : ヘッダー ファイル
    //
    
    #pragma once
    #include <afxcmn.h>
    
    class MyListItemData
    {
    public:
    	CString LabelString;
    public:
    	MyListItemData() {}
    	explicit MyListItemData(LPCTSTR label)
    		: LabelString(label)
    	{}
    };
    
    // CMfcCustomListCtrlTest1Dlg ダイアログ
    class CMfcCustomListCtrlTest1Dlg : public CDialogEx
    {
    	// コンストラクション
    public:
    	CMfcCustomListCtrlTest1Dlg(CWnd* pParent = NULL); // 標準コンストラクター
    
    	// ダイアログ データ
    #ifdef AFX_DESIGN_TIME
    	enum { IDD = IDD_MFCCUSTOMLISTCTRLTEST1_DIALOG };
    #endif
    
    protected:
    	virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV サポート
    
    	// 実装
    private:
    	HICON m_hIcon;
    
    private:
    	std::vector<MyListItemData> m_ownerDataListItemsArray;
    	CImageList m_imageList;
    	static const int OverlayImageIndex = 1;
    
    protected:
    	// 生成された、メッセージ割り当て関数
    	virtual BOOL OnInitDialog();
    	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    	afx_msg void OnPaint();
    	afx_msg HCURSOR OnQueryDragIcon();
    	DECLARE_MESSAGE_MAP()
    private:
    	CListCtrl m_ddxcListCtrl1;
    public:
    	afx_msg void OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult);
    	afx_msg void OnLvnGetdispinfoList1(NMHDR *pNMHDR, LRESULT *pResult);
    };
    // MfcCustomListCtrlTest1Dlg.cpp : 実装ファイル
    //
    
    #include "stdafx.h"
    #include "MfcCustomListCtrlTest1.h"
    #include "MfcCustomListCtrlTest1Dlg.h"
    #include <afxdialogex.h>
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    
    #pragma region // アプリケーションのバージョン情報に使われる CAboutDlg ダイアログ
    
    class CAboutDlg : public CDialogEx
    {
    public:
    	CAboutDlg();
    
    	// ダイアログ データ
    #ifdef AFX_DESIGN_TIME
    	enum { IDD = IDD_ABOUTBOX };
    #endif
    
    protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV サポート
    
    // 実装
    protected:
    	DECLARE_MESSAGE_MAP()
    };
    
    CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
    {
    }
    
    void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialogEx::DoDataExchange(pDX);
    }
    
    BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
    END_MESSAGE_MAP()
    
    #pragma endregion
    
    // CMfcCustomListCtrlTest1Dlg ダイアログ
    
    
    CMfcCustomListCtrlTest1Dlg::CMfcCustomListCtrlTest1Dlg(CWnd* pParent /*=NULL*/)
    	: CDialogEx(IDD_MFCCUSTOMLISTCTRLTEST1_DIALOG, pParent)
    {
    	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
    
    void CMfcCustomListCtrlTest1Dlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialogEx::DoDataExchange(pDX);
    	DDX_Control(pDX, IDC_LIST1, m_ddxcListCtrl1);
    }
    
    BEGIN_MESSAGE_MAP(CMfcCustomListCtrlTest1Dlg, CDialogEx)
    	ON_WM_SYSCOMMAND()
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
    	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, &CMfcCustomListCtrlTest1Dlg::OnLvnItemchangedList1)
    	ON_NOTIFY(LVN_GETDISPINFO, IDC_LIST1, &CMfcCustomListCtrlTest1Dlg::OnLvnGetdispinfoList1)
    END_MESSAGE_MAP()
    
    
    namespace
    {
    	void MakeSolidBitmap(CWnd* pWnd, CBitmap& bmp, int width, int height, COLORREF backColor, COLORREF borderColor)
    	{
    		CDC* pWndDC = pWnd->GetDC();
    		CDC dc;
    		dc.CreateCompatibleDC(pWndDC);
    
    		bmp.CreateCompatibleBitmap(pWndDC, width, height);
    
    		CBitmap* pOldBmp = dc.SelectObject(&bmp);
    
    		dc.FillSolidRect(0, 0, width, height, backColor);
    
    		dc.SelectStockObject(HOLLOW_BRUSH);
    		CPen borderPen(PS_SOLID, 1, borderColor);
    		CPen* pOldPen = dc.SelectObject(&borderPen);
    		dc.Rectangle(1, 1, width - 1, height - 1);
    
    		dc.SelectObject(pOldPen);
    		dc.SelectObject(pOldBmp);
    		pWnd->ReleaseDC(pWndDC);
    	}
    }
    
    // CMfcCustomListCtrlTest1Dlg メッセージ ハンドラー
    
    BOOL CMfcCustomListCtrlTest1Dlg::OnInitDialog()
    {
    	CDialogEx::OnInitDialog();
    
    	// "バージョン情報..." メニューをシステム メニューに追加します。
    
    	// IDM_ABOUTBOX は、システム コマンドの範囲内になければなりません。
    	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    	ASSERT(IDM_ABOUTBOX < 0xF000);
    
    	CMenu* pSysMenu = GetSystemMenu(FALSE);
    	if (pSysMenu != NULL)
    	{
    		BOOL bNameValid;
    		CString strAboutMenu;
    		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
    		ASSERT(bNameValid);
    		if (!strAboutMenu.IsEmpty())
    		{
    			pSysMenu->AppendMenu(MF_SEPARATOR);
    			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    		}
    	}
    
    	// このダイアログのアイコンを設定します。アプリケーションのメイン ウィンドウがダイアログでない場合、
    	//  Framework は、この設定を自動的に行います。
    	SetIcon(m_hIcon, TRUE); // 大きいアイコンの設定
    	SetIcon(m_hIcon, FALSE); // 小さいアイコンの設定
    
    	// TODO: 初期化をここに追加します。
    
    	for (int i = 0; i < 10; ++i)
    	{
    		CString strLabel;
    		strLabel.Format(_T("ラベル %d"), i);
    		m_ownerDataListItemsArray.push_back(MyListItemData(strLabel));
    	}
    
    	{
    		const DWORD oldExStyle = m_ddxcListCtrl1.GetExtendedStyle();
    		m_ddxcListCtrl1.SetExtendedStyle(oldExStyle | LVS_EX_BORDERSELECT | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER);
    #if 0
    		// CListCtrl::SetOutlineColor() は LVM_SETOUTLINECOLOR のラッパー。
    		// 各項目のアウトライン色を一律変更するためのもの。
    		// LVS_ICON モードで大きい画像を表示すると効果が分かりやすいが、LVS_REPORT モードだと分かりづらい。
    		// https://msdn.microsoft.com/ja-jp/library/dybxywt4.aspx
    		// https://msdn.microsoft.com/en-us/library/windows/desktop/bb761200.aspx
    		// https://msdn.microsoft.com/en-us/library/windows/desktop/bb774732.aspx
    		m_ddxcListCtrl1.SetOutlineColor(RGB(255, 0, 0));
    #endif
    	}
    
    #if 0
    	// LVS_REPORT 用。
    	// Vista 以降であれば、LVS_EX_HEADERINALLVIEWS を指定することですべてのビューモードにおいて表示可能。
    	for (int i = 0; i < 4; ++i)
    	{
    		CString strHeader;
    		strHeader.Format(_T("カラム %d"), i);
    		m_ddxcListCtrl1.InsertColumn(i, strHeader, LVCFMT_LEFT, 128, -1);
    	}
    #endif
    
    	{
    		const int imageCount = 2;
    		const int imageWidth = 32;
    		const int imageHeight = 32;
    		const COLORREF maskColor = RGB(0xFF, 0x00, 0xFF);
    		m_imageList.Create(imageWidth, imageHeight, ILC_COLOR24 | ILC_MASK, imageCount, 0);
    		// オーバーレイ用のマスク画像。
    		{
    			CBitmap bitmap;
    			MakeSolidBitmap(this, bitmap, imageWidth, imageHeight, maskColor, RGB(0xFF, 0xD7, 0x00));
    			m_imageList.Add(&bitmap, maskColor);
    		}
    #if 0
    		// テスト用に MFC 14.0 (VC 2015) 標準のアプリケーションのアイコンを使ってみる。
    		// 複数解像度や複数色深度を含むアイコンから画像を自動的に抽出してくれる。
    		// ただし、ILC_COLOR32 を指定した場合は使えない模様。
    		{
    			HICON hIcon = ::LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
    			m_imageList.Add(hIcon);
    		}
    #else
    		// テスト用に適当なソリッド画像を作成する。
    		{
    			CBitmap bitmap;
    			MakeSolidBitmap(this, bitmap, imageWidth, imageHeight, RGB(0x00, 0x80, 0x80), RGB(0x00, 0x80, 0x80));
    			m_imageList.Add(&bitmap, maskColor);
    		}
    #endif
    		// オーバーレイを使う場合、ILC_MASK を指定しておかないと失敗する。
    		// http://stackoverflow.com/questions/31154146/unable-to-set-overlay-image-for-clistctrl
    		VERIFY(m_imageList.SetOverlayImage(0, OverlayImageIndex));
    		m_ddxcListCtrl1.SetImageList(&m_imageList, LVSIL_NORMAL);
    		//m_ddxcListCtrl1.SetImageList(&m_imageList, LVSIL_SMALL);
    	}
    
    	// リスト ビューの仮想化を行なうため、
    	// Visual C++ リソース ビューにおいて、当該リスト コントロールの
    	// [Owner Data] を True にしておく。LVS_OWNERDATA スタイルを付加することに相当する。
    	// そのほか、仮想化とは関係ないが、必要に応じて、
    	// [Always Show Selection] (LVS_SHOWSELALWAYS) を True に、
    	// [Share Image Lists] (LVS_SHAREIMAGELISTS) を True にしておく。
    	// https://msdn.microsoft.com/en-us/library/windows/desktop/bb774739.aspx
    	
    	m_ddxcListCtrl1.SetItemCount(static_cast<int>(m_ownerDataListItemsArray.size()));
    
    	return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
    }
    
    void CMfcCustomListCtrlTest1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    	{
    		CAboutDlg dlgAbout;
    		dlgAbout.DoModal();
    	}
    	else
    	{
    		CDialogEx::OnSysCommand(nID, lParam);
    	}
    }
    
    // ダイアログに最小化ボタンを追加する場合、アイコンを描画するための
    //  下のコードが必要です。ドキュメント/ビュー モデルを使う MFC アプリケーションの場合、
    //  これは、Framework によって自動的に設定されます。
    
    void CMfcCustomListCtrlTest1Dlg::OnPaint()
    {
    	if (IsIconic())
    	{
    		CPaintDC dc(this); // 描画のデバイス コンテキスト
    
    		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    
    		// クライアントの四角形領域内の中央
    		int cxIcon = GetSystemMetrics(SM_CXICON);
    		int cyIcon = GetSystemMetrics(SM_CYICON);
    		CRect rect;
    		GetClientRect(&rect);
    		int x = (rect.Width() - cxIcon + 1) / 2;
    		int y = (rect.Height() - cyIcon + 1) / 2;
    
    		// アイコンの描画
    		dc.DrawIcon(x, y, m_hIcon);
    	}
    	else
    	{
    		CDialogEx::OnPaint();
    	}
    }
    
    // ユーザーが最小化したウィンドウをドラッグしているときに表示するカーソルを取得するために、
    //  システムがこの関数を呼び出します。
    HCURSOR CMfcCustomListCtrlTest1Dlg::OnQueryDragIcon()
    {
    	return static_cast<HCURSOR>(m_hIcon);
    }
    
    
    // LVN_ITEMCHANGED イベント ハンドラー。
    void CMfcCustomListCtrlTest1Dlg::OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult)
    {
    	NMLISTVIEW* pNMLV = reinterpret_cast<NMLISTVIEW*>(pNMHDR);
    	// TODO: ここにコントロール通知ハンドラー コードを追加します。
    
    	*pResult = 0;
    }
    
    // LVN_GETDISPINFO イベント ハンドラー。
    void CMfcCustomListCtrlTest1Dlg::OnLvnGetdispinfoList1(NMHDR *pNMHDR, LRESULT *pResult)
    {
    	NMLVDISPINFO* pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
    	// TODO: ここにコントロール通知ハンドラー コードを追加します。
    
    	LVITEM& item = pDispInfo->item;
    	const int itemIndex = item.iItem;
    	const int subIndex = item.iSubItem;
    	if (size_t(itemIndex) < m_ownerDataListItemsArray.size())
    	{
    		if (item.mask & LVIF_TEXT)
    		{
    			item.pszText = const_cast<LPTSTR>(m_ownerDataListItemsArray[itemIndex].LabelString.GetString());
    		}
    		if (item.mask & LVIF_IMAGE)
    		{
    			item.iImage = 1; // とりあえずメイン画像は常に固定インデックスを使う。
    			const bool isSelected = m_ddxcListCtrl1.GetItemState(itemIndex, LVIS_SELECTED) == LVIS_SELECTED;
    			// アイテムが選択されている場合は、登録しておいたオーバーレイ画像のインデックスを指定する。
    			// http://hp.vector.co.jp/authors/VA016117/explorer1.html
    			if (isSelected)
    			{
    				item.mask |= LVIF_STATE;
    				item.stateMask = LVIS_OVERLAYMASK;
    				item.state = INDEXTOOVERLAYMASK(OverlayImageIndex) & LVIS_OVERLAYMASK;
    			}
    		}
    	}
    
    	*pResult = 0;
    }

    • 編集済み sygh 2015年11月21日 22:44
    • 回答の候補に設定 星 睦美 2015年11月24日 6:08
    • 回答としてマーク パブリックENG 2015年11月27日 9:14
    2015年11月21日 16:07

すべての返信

  • Visual Studio 2015ではなく、Visual Studio 2005ですか?

    質問するときは実行環境(ターゲット環境)や、MFCのプロジェクト種別(ダイアログベース/SDI/MDI)などもきちんと書きましょう。

    CListCtrl::SetOutlineColor()はLVM_SETOUTLINECOLORのラッパーであり、各項目のアウトライン色を一律変更するためのものです。「アイテムを選択したときに画像の状態をアイテムごとに個別に変更する」などの処理を実装したい場合、オーバーレイを使うという方法があります。

    手元に古い開発環境がないので、VS 2015 CommunityとWindows 8.1で動作確認したコードを載せます。

    stdafx.hでvectorのヘッダーをインクルードしていることを前提にしています。また、Visual C++リソースビューで当該リストコントロールの[Owner Data]をTrueに設定してリストを仮想化し、また[View]をIconモードLVS_ICONに設定していることを前提にしています。

    ※MSDNライブラリのListView_SetItemCount/ListView_SetItemCountExの説明によると、LVS_OWNERDATAスタイルを付加して仮想化する場合は本来ListView_SetItemCountではなくListView_SetItemCountExを使うべきで、またListView_SetItemCountExはレポートモードLVS_REPORTかリストモードLVS_LISTが使われていることを前提としているようなので、IconモードLVS_ICONでは完全な仮想化が実現できないかもしれません。

    そのほか、古いVS 2005だとCDialogExafxdialogex.hまわりでコンパイルエラーになると思いますが、環境に合わせて適宜修正してください。

    ぶっちゃけレガシーなMFCにこだわる理由が特になければ、こういったGUIまわりのカスタマイズはC#/VB.NET + WPF/WinRTのほうがはるかに効率的だと思います。どうしてもMFCを選択せざるを得ない場合でも、開発環境としての新しいOSサポート、MFCの機能追加・バグ修正やC++11規格対応が強化されているVS 2012以降の環境にできるだけ早く移行することをお勧めします。

    // MfcCustomListCtrlTest1Dlg.h : ヘッダー ファイル
    //
    
    #pragma once
    #include <afxcmn.h>
    
    class MyListItemData
    {
    public:
    	CString LabelString;
    public:
    	MyListItemData() {}
    	explicit MyListItemData(LPCTSTR label)
    		: LabelString(label)
    	{}
    };
    
    // CMfcCustomListCtrlTest1Dlg ダイアログ
    class CMfcCustomListCtrlTest1Dlg : public CDialogEx
    {
    	// コンストラクション
    public:
    	CMfcCustomListCtrlTest1Dlg(CWnd* pParent = NULL); // 標準コンストラクター
    
    	// ダイアログ データ
    #ifdef AFX_DESIGN_TIME
    	enum { IDD = IDD_MFCCUSTOMLISTCTRLTEST1_DIALOG };
    #endif
    
    protected:
    	virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV サポート
    
    	// 実装
    private:
    	HICON m_hIcon;
    
    private:
    	std::vector<MyListItemData> m_ownerDataListItemsArray;
    	CImageList m_imageList;
    	static const int OverlayImageIndex = 1;
    
    protected:
    	// 生成された、メッセージ割り当て関数
    	virtual BOOL OnInitDialog();
    	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    	afx_msg void OnPaint();
    	afx_msg HCURSOR OnQueryDragIcon();
    	DECLARE_MESSAGE_MAP()
    private:
    	CListCtrl m_ddxcListCtrl1;
    public:
    	afx_msg void OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult);
    	afx_msg void OnLvnGetdispinfoList1(NMHDR *pNMHDR, LRESULT *pResult);
    };
    // MfcCustomListCtrlTest1Dlg.cpp : 実装ファイル
    //
    
    #include "stdafx.h"
    #include "MfcCustomListCtrlTest1.h"
    #include "MfcCustomListCtrlTest1Dlg.h"
    #include <afxdialogex.h>
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    
    #pragma region // アプリケーションのバージョン情報に使われる CAboutDlg ダイアログ
    
    class CAboutDlg : public CDialogEx
    {
    public:
    	CAboutDlg();
    
    	// ダイアログ データ
    #ifdef AFX_DESIGN_TIME
    	enum { IDD = IDD_ABOUTBOX };
    #endif
    
    protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV サポート
    
    // 実装
    protected:
    	DECLARE_MESSAGE_MAP()
    };
    
    CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
    {
    }
    
    void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialogEx::DoDataExchange(pDX);
    }
    
    BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
    END_MESSAGE_MAP()
    
    #pragma endregion
    
    // CMfcCustomListCtrlTest1Dlg ダイアログ
    
    
    CMfcCustomListCtrlTest1Dlg::CMfcCustomListCtrlTest1Dlg(CWnd* pParent /*=NULL*/)
    	: CDialogEx(IDD_MFCCUSTOMLISTCTRLTEST1_DIALOG, pParent)
    {
    	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
    
    void CMfcCustomListCtrlTest1Dlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialogEx::DoDataExchange(pDX);
    	DDX_Control(pDX, IDC_LIST1, m_ddxcListCtrl1);
    }
    
    BEGIN_MESSAGE_MAP(CMfcCustomListCtrlTest1Dlg, CDialogEx)
    	ON_WM_SYSCOMMAND()
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
    	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, &CMfcCustomListCtrlTest1Dlg::OnLvnItemchangedList1)
    	ON_NOTIFY(LVN_GETDISPINFO, IDC_LIST1, &CMfcCustomListCtrlTest1Dlg::OnLvnGetdispinfoList1)
    END_MESSAGE_MAP()
    
    
    namespace
    {
    	void MakeSolidBitmap(CWnd* pWnd, CBitmap& bmp, int width, int height, COLORREF backColor, COLORREF borderColor)
    	{
    		CDC* pWndDC = pWnd->GetDC();
    		CDC dc;
    		dc.CreateCompatibleDC(pWndDC);
    
    		bmp.CreateCompatibleBitmap(pWndDC, width, height);
    
    		CBitmap* pOldBmp = dc.SelectObject(&bmp);
    
    		dc.FillSolidRect(0, 0, width, height, backColor);
    
    		dc.SelectStockObject(HOLLOW_BRUSH);
    		CPen borderPen(PS_SOLID, 1, borderColor);
    		CPen* pOldPen = dc.SelectObject(&borderPen);
    		dc.Rectangle(1, 1, width - 1, height - 1);
    
    		dc.SelectObject(pOldPen);
    		dc.SelectObject(pOldBmp);
    		pWnd->ReleaseDC(pWndDC);
    	}
    }
    
    // CMfcCustomListCtrlTest1Dlg メッセージ ハンドラー
    
    BOOL CMfcCustomListCtrlTest1Dlg::OnInitDialog()
    {
    	CDialogEx::OnInitDialog();
    
    	// "バージョン情報..." メニューをシステム メニューに追加します。
    
    	// IDM_ABOUTBOX は、システム コマンドの範囲内になければなりません。
    	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    	ASSERT(IDM_ABOUTBOX < 0xF000);
    
    	CMenu* pSysMenu = GetSystemMenu(FALSE);
    	if (pSysMenu != NULL)
    	{
    		BOOL bNameValid;
    		CString strAboutMenu;
    		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
    		ASSERT(bNameValid);
    		if (!strAboutMenu.IsEmpty())
    		{
    			pSysMenu->AppendMenu(MF_SEPARATOR);
    			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    		}
    	}
    
    	// このダイアログのアイコンを設定します。アプリケーションのメイン ウィンドウがダイアログでない場合、
    	//  Framework は、この設定を自動的に行います。
    	SetIcon(m_hIcon, TRUE); // 大きいアイコンの設定
    	SetIcon(m_hIcon, FALSE); // 小さいアイコンの設定
    
    	// TODO: 初期化をここに追加します。
    
    	for (int i = 0; i < 10; ++i)
    	{
    		CString strLabel;
    		strLabel.Format(_T("ラベル %d"), i);
    		m_ownerDataListItemsArray.push_back(MyListItemData(strLabel));
    	}
    
    	{
    		const DWORD oldExStyle = m_ddxcListCtrl1.GetExtendedStyle();
    		m_ddxcListCtrl1.SetExtendedStyle(oldExStyle | LVS_EX_BORDERSELECT | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER);
    #if 0
    		// CListCtrl::SetOutlineColor() は LVM_SETOUTLINECOLOR のラッパー。
    		// 各項目のアウトライン色を一律変更するためのもの。
    		// LVS_ICON モードで大きい画像を表示すると効果が分かりやすいが、LVS_REPORT モードだと分かりづらい。
    		// https://msdn.microsoft.com/ja-jp/library/dybxywt4.aspx
    		// https://msdn.microsoft.com/en-us/library/windows/desktop/bb761200.aspx
    		// https://msdn.microsoft.com/en-us/library/windows/desktop/bb774732.aspx
    		m_ddxcListCtrl1.SetOutlineColor(RGB(255, 0, 0));
    #endif
    	}
    
    #if 0
    	// LVS_REPORT 用。
    	// Vista 以降であれば、LVS_EX_HEADERINALLVIEWS を指定することですべてのビューモードにおいて表示可能。
    	for (int i = 0; i < 4; ++i)
    	{
    		CString strHeader;
    		strHeader.Format(_T("カラム %d"), i);
    		m_ddxcListCtrl1.InsertColumn(i, strHeader, LVCFMT_LEFT, 128, -1);
    	}
    #endif
    
    	{
    		const int imageCount = 2;
    		const int imageWidth = 32;
    		const int imageHeight = 32;
    		const COLORREF maskColor = RGB(0xFF, 0x00, 0xFF);
    		m_imageList.Create(imageWidth, imageHeight, ILC_COLOR24 | ILC_MASK, imageCount, 0);
    		// オーバーレイ用のマスク画像。
    		{
    			CBitmap bitmap;
    			MakeSolidBitmap(this, bitmap, imageWidth, imageHeight, maskColor, RGB(0xFF, 0xD7, 0x00));
    			m_imageList.Add(&bitmap, maskColor);
    		}
    #if 0
    		// テスト用に MFC 14.0 (VC 2015) 標準のアプリケーションのアイコンを使ってみる。
    		// 複数解像度や複数色深度を含むアイコンから画像を自動的に抽出してくれる。
    		// ただし、ILC_COLOR32 を指定した場合は使えない模様。
    		{
    			HICON hIcon = ::LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
    			m_imageList.Add(hIcon);
    		}
    #else
    		// テスト用に適当なソリッド画像を作成する。
    		{
    			CBitmap bitmap;
    			MakeSolidBitmap(this, bitmap, imageWidth, imageHeight, RGB(0x00, 0x80, 0x80), RGB(0x00, 0x80, 0x80));
    			m_imageList.Add(&bitmap, maskColor);
    		}
    #endif
    		// オーバーレイを使う場合、ILC_MASK を指定しておかないと失敗する。
    		// http://stackoverflow.com/questions/31154146/unable-to-set-overlay-image-for-clistctrl
    		VERIFY(m_imageList.SetOverlayImage(0, OverlayImageIndex));
    		m_ddxcListCtrl1.SetImageList(&m_imageList, LVSIL_NORMAL);
    		//m_ddxcListCtrl1.SetImageList(&m_imageList, LVSIL_SMALL);
    	}
    
    	// リスト ビューの仮想化を行なうため、
    	// Visual C++ リソース ビューにおいて、当該リスト コントロールの
    	// [Owner Data] を True にしておく。LVS_OWNERDATA スタイルを付加することに相当する。
    	// そのほか、仮想化とは関係ないが、必要に応じて、
    	// [Always Show Selection] (LVS_SHOWSELALWAYS) を True に、
    	// [Share Image Lists] (LVS_SHAREIMAGELISTS) を True にしておく。
    	// https://msdn.microsoft.com/en-us/library/windows/desktop/bb774739.aspx
    	
    	m_ddxcListCtrl1.SetItemCount(static_cast<int>(m_ownerDataListItemsArray.size()));
    
    	return TRUE;  // フォーカスをコントロールに設定した場合を除き、TRUE を返します。
    }
    
    void CMfcCustomListCtrlTest1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    	{
    		CAboutDlg dlgAbout;
    		dlgAbout.DoModal();
    	}
    	else
    	{
    		CDialogEx::OnSysCommand(nID, lParam);
    	}
    }
    
    // ダイアログに最小化ボタンを追加する場合、アイコンを描画するための
    //  下のコードが必要です。ドキュメント/ビュー モデルを使う MFC アプリケーションの場合、
    //  これは、Framework によって自動的に設定されます。
    
    void CMfcCustomListCtrlTest1Dlg::OnPaint()
    {
    	if (IsIconic())
    	{
    		CPaintDC dc(this); // 描画のデバイス コンテキスト
    
    		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    
    		// クライアントの四角形領域内の中央
    		int cxIcon = GetSystemMetrics(SM_CXICON);
    		int cyIcon = GetSystemMetrics(SM_CYICON);
    		CRect rect;
    		GetClientRect(&rect);
    		int x = (rect.Width() - cxIcon + 1) / 2;
    		int y = (rect.Height() - cyIcon + 1) / 2;
    
    		// アイコンの描画
    		dc.DrawIcon(x, y, m_hIcon);
    	}
    	else
    	{
    		CDialogEx::OnPaint();
    	}
    }
    
    // ユーザーが最小化したウィンドウをドラッグしているときに表示するカーソルを取得するために、
    //  システムがこの関数を呼び出します。
    HCURSOR CMfcCustomListCtrlTest1Dlg::OnQueryDragIcon()
    {
    	return static_cast<HCURSOR>(m_hIcon);
    }
    
    
    // LVN_ITEMCHANGED イベント ハンドラー。
    void CMfcCustomListCtrlTest1Dlg::OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult)
    {
    	NMLISTVIEW* pNMLV = reinterpret_cast<NMLISTVIEW*>(pNMHDR);
    	// TODO: ここにコントロール通知ハンドラー コードを追加します。
    
    	*pResult = 0;
    }
    
    // LVN_GETDISPINFO イベント ハンドラー。
    void CMfcCustomListCtrlTest1Dlg::OnLvnGetdispinfoList1(NMHDR *pNMHDR, LRESULT *pResult)
    {
    	NMLVDISPINFO* pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
    	// TODO: ここにコントロール通知ハンドラー コードを追加します。
    
    	LVITEM& item = pDispInfo->item;
    	const int itemIndex = item.iItem;
    	const int subIndex = item.iSubItem;
    	if (size_t(itemIndex) < m_ownerDataListItemsArray.size())
    	{
    		if (item.mask & LVIF_TEXT)
    		{
    			item.pszText = const_cast<LPTSTR>(m_ownerDataListItemsArray[itemIndex].LabelString.GetString());
    		}
    		if (item.mask & LVIF_IMAGE)
    		{
    			item.iImage = 1; // とりあえずメイン画像は常に固定インデックスを使う。
    			const bool isSelected = m_ddxcListCtrl1.GetItemState(itemIndex, LVIS_SELECTED) == LVIS_SELECTED;
    			// アイテムが選択されている場合は、登録しておいたオーバーレイ画像のインデックスを指定する。
    			// http://hp.vector.co.jp/authors/VA016117/explorer1.html
    			if (isSelected)
    			{
    				item.mask |= LVIF_STATE;
    				item.stateMask = LVIS_OVERLAYMASK;
    				item.state = INDEXTOOVERLAYMASK(OverlayImageIndex) & LVIS_OVERLAYMASK;
    			}
    		}
    	}
    
    	*pResult = 0;
    }

    • 編集済み sygh 2015年11月21日 22:44
    • 回答の候補に設定 星 睦美 2015年11月24日 6:08
    • 回答としてマーク パブリックENG 2015年11月27日 9:14
    2015年11月21日 16:07
  • フォーラム オペレーターの星 睦美です。

    パブリックENG さんの質問にsygh さんからの回答がありますので確認いただいて返信いただければと思います。参考になる回答には投稿者からの[回答としてマーク] をお願いします。

    フォーラムのヘルプ


    フォーラム オペレーター 星 睦美 - MSDN Community Support

    2015年11月24日 6:13
  • Visual Studio2005で間違えありません。基幹システムですので、中々移行ができません。。

    ソースコードまで付けて頂き、ありがとうございます。

    ご指摘頂いた、実行環境・プロジェクトの種類の記載ですが、今後注意します。

    ソースコードを付けて頂いた事で、やっていく事の方向性が見えたように思います。

    参考にさせて頂き、進めて行きたいと思います。ありがとうございました。


    • 編集済み パブリックENG 2015年11月24日 7:58 Visual Studioのバージョン追記
    2015年11月24日 7:57
  • 返信が遅くなり、申し訳ありません。

    記載された内容をもとに、更に情報を調べた所、

    カスタムドローのクリックイベントにて実現が可能でした。

    描写は、ペンとブラシにて、行えました。

    回答とさせて頂きます。ありがとうございました。

    2015年11月27日 9:35