首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

打造 QQ 風格 ListCtrl:自繪實現彩色頭像、狀態圖示與豐富用戶資訊

     編輯:關於VC++

前言

QQ 主介面的 ListCtrl 堪稱經典:彩色頭像、離線灰階、視訊/簡訊狀態圖示、豐富用戶資訊一應俱全。本文將帶領大家從零開始,打造一個功能相當的 CMyListCtrl,並完整解析關鍵技術點。

QQ 風格 ListCtrl 效果圖

核心任務與實現分析

1. 顯示彩色圖片頭像(在線用戶)

使用 CImageList 載入同尺寸圖片並關聯至 ListCtrl 即可。向 ImageList 添加圖片/圖示的三種常見方式:

CImageList m_imageList;
m_imagelist.Create(40, 40, ILC_MASK | ILC_COLOR32, 1, 1);
// 1. 添加資源圖示
m_imageList.Add(AfxGetApp()->LoadIcon(IDI_ICON));
// 2. 從 .ico 檔載入
HICON hIcon = (HICON)LoadImage(NULL, _T(".\\image\\SQQun.ico"), IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
m_imagelist.Add(hIcon);
// 3. 從 .bmp 檔載入(指定遮罩色)
CBitmap *pBitmap = new CBitmap;
pBitmap->m_hObject = (HBITMAP)LoadImage(NULL, _T("face.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_imagelist.Add(pBitmap, RGB(255, 255, 255));
delete pBitmap;

關聯並添加項目:

if (m_MyFriendListCtrl.Create(LVS_SMALLICON | WS_TABSTOP | WS_CHILD,
    CRect(50, 100, 206, 180), this, IDD_TALKER_LIST))
{
    m_MyFriendListCtrl.SetImageList(&m_imagelistBig, LVSIL_SMALL);
    m_MyFriendListCtrl.SetBackBitmap(_T(".\\image\\mainFrame-centerMid.bmp"));
    for (int i = 0; i < 10; i++)
    {
        CString strTemp;
        strTemp.Format(_T("我的好友%d"), i);
        LUSERITEM userInfo;
        userInfo.szUserID = strTemp.GetBuffer(strTemp.GetLength());
        strTemp.ReleaseBuffer();
        userInfo.szNoticeMsg = _T("天不怕!地不怕!");
        m_MyFriendListCtrl.InsertItem(i, strTemp, i, &userInfo);
        m_MyFriendListCtrl.SetItemData(i, (i % 2) ? i | 0x00000020 : i);
    }
    m_MyFriendListCtrl.ShowWindow(SW_SHOW);
}

2. 顯示灰階頭像(離線用戶)

灰階轉換可用圖片處理工具預製,亦可運行時以代碼實現。經比較,選用 CopyImage API 配合 LR_MONOCHROME 旗標,效率與效果兼顧:

CImageList* pImageList = GetImageList(LVSIL_SMALL);
if (pImageList != NULL)
{
    HICON hIcon = pImageList->ExtractIcon(nItem);
    HBITMAP hBitmap, hBitmapMask;
    ICONINFO* pIconInfo = new ICONINFO;
    if (::GetIconInfo(hIcon, pIconInfo))
    {
        hBitmap = pIconInfo->hbmColor;
        hBitmapMask = pIconInfo->hbmMask;
        if (!(nStyle & TVS_ONLINEUSER))
            // 關鍵:轉為單色位圖
            hBitmap = (HBITMAP)CopyImage(hBitmap, IMAGE_BITMAP, 0, 0,
                                         LR_COPYDELETEORG | LR_MONOCHROME);
        DrawBitmap(m_hDll, &memDC, hBitmap, rcIcon);
        DeleteObject(hBitmap);
        DeleteObject(hBitmapMask);
    }
    delete pIconInfo;
    ::DestroyIcon(hIcon);
}

文中也提供了一個像素級灰度演算法(BitmapColorToGray),效果更佳但耗時稍長,供參考。

3. 攜帶豐富用戶資訊(ID、姓名、IP、視訊、簡訊等)

SetItemData/GetItemData 僅提供 32 位資料,不足以承載複雜資訊。解決方案:定義結構體 LUSERITEM,並以 std::deque 管理:

struct LUSERITEM
{
    CString szUserID;
    CString szUserName;
    CString szIPAddress;
    CString szServerAddress;
    CString szNoticeMsg;
    BOOL    bOnline;
    int     nHeadImageIndex;
    // 可按需擴充
};

#include 
typedef std::deque DEQUELVITEM;

重載 InsertItem 同步寫入 deque,刪除時同步移除,確保資料一致性。

工程建立與自繪實現

  1. 用 ClassWizard 建立 CMyListCtrl 繼承 CListCtrl。
  2. 添加 OnPaint、OnMouseMove、OnHScroll、OnVScroll 等訊息處理。
  3. 在 .h 中定義結構體、常量旗標(TVS_VIDEO、TVS_MOBILEMSG…)、成員變數(字體、懸停旗標、deque、圖示句柄、背景位圖)。
  4. 實現 InsertItem、SetTailIcon、SetBackBitmap、DeleteUserInfo 等輔助函數。
  5. 所有自繪邏輯集中在 OnPaint() 中(篇幅所限略去,請參考原始碼)。

結語

為讓 VC 開發者能快速美化聊天軟體介面,筆者提供完整 CMyListCtrl 原始碼,期望拋磚引玉。CMyTreeCtrl 自繪原理大同小異,有興趣者可自行嘗試。問題歡迎聯繫:song_0962@sina.com (QQ: 34544052)。

完整運行效果

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved