ListView 自绘模式的一种实现

本文通过重载WM_NOTIFY消息,实现ListView外观的自定义.
实现结果为奇偶数分别采用不同的背景颜色.同时最后一列加入了一个时钟图标.
该代码为本人的GUI系统(MiniWin)在数字电视机顶盒中的部分实现代码
需要学习WIN32-API开发的人可以参考,
其中IDC_EPGSCHEDULE为Listview控件的ID

以下为MiniWin界面效果图以及相关代码.其中包含了ListBox自绘模式的实现,ToolBar的应用等

 

//  epgWindow.c: implementation of the epgWindow class.
//
//

#include 
" dvbutils.h "
#include 
< stdio.h >
#include 
< string .h >
#include 
" dvbepg.h "
#include 
" prvideo.h "

#define  WM_EVENT_UPDATE WM_LAST+0x1000
#define  IDT_EPGTIMER        100
#define  IDC_TITLE            101
#define  IDC_DATETIME        102
#define  IDC_SVCGROUPS        103
#define  IDC_GRPSERVICE        104
#define  IDC_WEEK            105
#define  IDC_EPGSCHEDULE        107
#define  IDC_VIDEO            108

static  HBITMAP hbmpClock;

extern   int  GetAllService(HWND hwnd,FAVGROUP * fav);
static   int  UpdateScheduleInfo(HWND hch,SECTIONDB * db, int  week)
{
    
int i,evtCount=0;
    DWORD t1
=GetTickCount();
    LockWindowUpdate(hch);
    SendMessage(hch,LVM_DELETEALLITEMS,
0,0);

    
if(db!=NULL){
        SECTIONDATA
*sd;
        SYSTEMTIME curTime;
        FILETIME CurFt;
        GetLocalTime(
&curTime);
        SystemTimeToFileTime(
&curTime,&CurFt);
        sd
=db->sections;
        
if(sd&&sd->Data)
            TRACE(
"Update EITS %d.%d.%d=%dSections ",GetEitNetID(sd->Data),
            GetEitStreamID(sd
->Data),GetEitServiceID(sd->Data),db->Count);
        
while(sd){
            
int i,ec=GetEitEventCount(sd->Data);
            
for(i=0;i<ec;i++){
                DVBEvent evt;
                
int idx;
                UINT duration;
                
char tstr[256],name[256],txt[256];
                FILETIME ft;
                SYSTEMTIME evtLocalTime;
                LVITEM lv;
                GetEitEvent(sd
->Data,&evt,i);
                MJDToLocalTime(
&evtLocalTime,evt.mjdDate,evt.utcTime);
                
//MJDToSystemTime(&est,evt.mjdDate,evt.utcTime);
                if(evtLocalTime.wDayOfWeek!=week)continue;
                sprintf(tstr,
"%02d:%02d",evtLocalTime.wHour,evtLocalTime.wMinute);
                duration
=UTC2Seconds(evt.duration);
                SystemTimeToFileTime(
&evtLocalTime,&ft);
                ZeroMemory(
&lv,sizeof(lv));
                lv.pszText
=tstr;
                lv.mask
=LVIF_TEXT|LVIF_PARAM;
                lv.iItem
=evtCount+i;
                lv.lParam
=ft.dwLowDateTime;
                idx
=ListView_InsertItem(hch,&lv);
                lv.lParam
=0;
                
if( (ft.dwLowDateTime<CurFt.dwLowDateTime)  && 
                    ( ft.dwLowDateTime
+duration>CurFt.dwLowDateTime) ){
                    ListView_SetItemState(hch,idx,LVIS_FOCUSED 
| LVIS_SELECTED,LVIS_FOCUSED | LVIS_SELECTED ); 
                    ListView_EnsureVisible(hch,idx,
0);
                    
//Make sure Current Event is selected and Visible
                }

                sprintf(tstr,
"%02X:%02X",evt.duration>>16,(evt.duration>>8)&0xFF);   
                ListView_SetItemText(hch,idx,
1,tstr);
                GetShortEventName(
&evt,name,txt,NULL);
                ListView_SetItemText(hch,idx,
2,name);
                ListView_SetItemText(hch,idx,
3," ");
                ListView_SetItemText(hch,idx,
4,txt);
            }

            evtCount
+=ec;
            sd
=sd->next;
        }

    }

    LockWindowUpdate(NULL);
    TRACE(
"UpdateScheduleInfo used %d ms ",GetTickCount()-t1);
    
return evtCount;
}

static  INT DoServiceChange(HWND hwnd) {
    
    HWND hgrpsvc
=GetDlgItem(hwnd,IDC_GRPSERVICE);
    INT  rc,idx
=SendMessage(hgrpsvc,LB_GETCURSEL,0,0);
    SERVICELOCATOR 
*svr=(SERVICELOCATOR*)SendMessage(hgrpsvc,LB_GETITEMDATA,idx,0);
    HWND hSch,hweek
=GetDlgItem(hwnd,IDC_WEEK);
    TCITEM tci;
    SECTIONDB 
*sdb=NULL;
    tci.mask
=TCIF_PARAM;
    hSch
=GetDlgItem(hwnd,IDC_EPGSCHEDULE);
    TabCtrl_GetItem(hweek,TabCtrl_GetCurSel(hweek),
&tci);
    
if( (svr!=NULL) && ((UINT)svr!=LB_ERR)){
        PlayByService(svr);
        sdb
=LockScheduleDB(svr);//PlayByService会自动发送接收EITSchedule的请求
        if(sdb==NULL||sdb->sections==NULL){                    
            TRACE(
"EPG::Request(%d.%d.%d) ",svr->netId,svr->tsId,svr->serviceId);
            
//RequestEPG(svr,REQUEST_EITSCH);
            rc=0;
        }
else
            rc
=UpdateScheduleInfo(hSch,sdb,tci.lParam);
            UnlockScheduleDB(svr);
//PlayByService会自动发送接收EITSchedule的请求
        }

    }

    
return rc;
}

static  LRESULT WINAPI EpgWndProc(HWND hwnd,UINT msgID,WPARAM wParam,LPARAM lParam)
{
    
switch(msgID)
        
{
            
case WM_TIMER:
                
{
                    
char sdate[128],stime[64];
                    SYSTEMTIME tnow;
                    GetLocalTime(
&tnow);
                    GetDateFormat(LOCALE_NEUTRAL,
0,&tnow,0,sdate,64);
                    GetTimeFormat(LOCALE_NEUTRAL,TIME_NOSECONDS
|TIME_FORCE24HOURFORMAT,&tnow," hh:mm tt",stime,64);
                    strcat(sdate,stime);
                    SetDlgItemText(hwnd,IDC_DATETIME,sdate);
                }

                
break;
            
case WM_COMMAND:
                
{
                    
switch(wParam)
                    
{
                    
case MAKELONG(IDC_SVCGROUPS,OPN_SELCHANGE)://分组改变事件处理
                        {
                            INT idx
=SendMessage((HWND)lParam,OPT_GETCURSEL,0,0);
                            FAVGROUP
*fav=(FAVGROUP*)SendMessage((HWND)lParam,OPT_GETITEMDATA,idx,0);
                            HWND hs
=GetDlgItem(hwnd,IDC_GRPSERVICE);
                            GetAllService(hs,(FAVGROUP
*)fav);
                        }

                        
break;
                    
case MAKELONG(IDC_WEEK,OPN_SELCHANGE)://分组改变事件处理
                        TRACE("WEEK CHANGE ");
                        
//pass throught
                    case MAKELONG(IDC_GRPSERVICE,LBN_SELCHANGE)://Service切换事件处理
                        DoServiceChange(hwnd);
                        
break;
                    
default:
                        
break;
                    }

                }
break;
            
case WM_DRAWITEM:
                
{
                    DRAWITEMSTRUCT 
*ds=(DRAWITEMSTRUCT*)lParam;
                    HDC hdc
=(HDC)ds->hDC;
                    RECT rc
=ds->rcItem;
                    
char text[128];
                    HBRUSH hbBorder;
                    HDC hmdc
=CreateCompatibleDC((HDC)hdc);
                    
if(ds->CtlType==ODT_LISTBOX)
                    
{
                        HBRUSH hb;
                        HBRUSH hbBorder
=CreateSolidBrush(RGB(214,247,255));
                        HRGN hrgn
=CreateRoundRectRgn(rc.left,rc.top,rc.right,rc.bottom,0,0);
                        
                        
if(ds->itemState&ODS_SELECTED){
                            
if(ds->itemState&ODS_FOCUS)
                                hb
=CreateSolidBrush(RGB(207,99,22));
                            
else
                                hb
=CreateSolidBrush(RGB(255,255,181));
                        }
else
                            hb
=CreateSolidBrush(RGB(24,141,185));

                        FillRgn(hdc,hrgn,hb);
                        FrameRgn(hdc,hrgn,hbBorder,
0,2);
                        SendMessage(ds
->hwndItem,LB_GETTEXT,ds->itemID,(LPARAM)text);
                        SetBkMode(hdc,TRANSPARENT);
                        SetTextColor(hdc,RGB(
0,0,0));
                        DrawText(hdc,text,
sizeof(text),&rc,DT_VCENTER|DT_SINGLELINE|DT_LEFT);
                        SendMessage(ds
->hwndItem,LB_GETITEMDATA,ds->itemID,0);
                        DeleteObject((HGDIOBJ)hb);
                        DeleteObject((HGDIOBJ)hrgn);
                        DeleteObject((HGDIOBJ)hbBorder);
                    }

                    DeleteDC(hmdc);
                }

                
return 0;

            
case WM_ERASEBKGND:
                
{
                    HDC hmdc
=CreateCompatibleDC((HDC)wParam);
                    HBRUSH hbBorder;

                    
//画菜单背景
                    hbBorder=CreateSolidBrush(RGB(61,185,197));
                    FillRect((HDC)wParam,NULL,hbBorder);
                    DeleteObject((HGDIOBJ)hbBorder);
                    
                
{   
                    RECT rc;
                    HBITMAP hbmpTitle;
                    HBRUSH hbrush;
                    BITMAP bmp;
                    hbmpTitle
=LoadBitmap(hInstDVBRes,MAKEINTRESOURCE(IDB_WINTITLE));
                    hbrush
=CreatePatternBrush(hbmpTitle);
                    GetObject((HGDIOBJ)hbmpTitle,
sizeof(BITMAP),&bmp);
                    GetClientRect(hwnd,
&rc);rc.bottom=rc.top+bmp.bmHeight;
                    FillRect((HDC)wParam,
&rc,hbrush);
                    DeleteObject((HGDIOBJ)hbrush); 
                    DeleteObject((HGDIOBJ)hbmpTitle);
                    
                    hbmpTitle
=LoadBitmap(hInstDVBRes,MAKEINTRESOURCE(IDB_WINHELP));
                    hbrush
=CreatePatternBrush(hbmpTitle);
                    GetObject((HGDIOBJ)hbmpTitle,
sizeof(BITMAP),&bmp);
                    GetClientRect(hwnd,
&rc);rc.top=rc.bottom-bmp.bmHeight;
                    FillRect((HDC)wParam,
&rc,hbrush);
                    DeleteObject((HGDIOBJ)hbrush); 
                    DeleteObject((HGDIOBJ)hbmpTitle);
                }

                    DeleteDC(hmdc);
                }

                
return 0;
    
case WM_NOTIFY:
        
{
            NMHDR 
*nmhdr = (PVOID)lParam;
            
if(nmhdr->code==TCN_SELCHANGE){
                DoServiceChange(hwnd);
            }

            
if(nmhdr->idFrom ==IDC_EPGSCHEDULE){
                
if(nmhdr->code == NM_CUSTOMDRAW) {
                    NMLVCUSTOMDRAW 
*nmlvcd = (PVOID)nmhdr;
                    SYSTEMTIME stnow;
                    FILETIME ft;
                    
switch(nmlvcd->nmcd.dwDrawStage) {
                    
case CDDS_PREPAINT:
                        
return CDRF_NOTIFYITEMDRAW;
                    
case CDDS_ITEMPREPAINT:
                        GetLocalTime(
&stnow);
                        SystemTimeToFileTime(
&stnow,&ft);
                        
if(nmlvcd->nmcd.lItemlParam<ft.dwLowDateTime){
                            
if(nmlvcd->nmcd.uItemState!=0)
                                nmlvcd
->clrTextBk =CLR_DEFAULT;
                            
else{
                                nmlvcd
->clrTextBk =RGB(200,200,200);
                            }

                            
return CDRF_DODEFAULT;
                        }

                        
return CDRF_NOTIFYSUBITEMDRAW;
                    
case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
                        
if(nmlvcd->nmcd.dwItemSpec%2){
                            nmlvcd
->clrTextBk =CLR_DEFAULT;
                        }
else
                            nmlvcd
->clrTextBk =RGB(200,200,250);
                        
return CDRF_NOTIFYPOSTPAINT;
                    
case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
                        
if(nmlvcd->iSubItem==3){
                            BITMAP bmp;
                            RECT rc
=nmlvcd->nmcd.rc;
                            HBITMAP hobmp,hbm
=LoadBitmap(hInstDVBRes,MAKEINTRESOURCE(IDB_CLOCK));
                            HDC hmdc
=CreateCompatibleDC(nmlvcd->nmcd.hdc);
                            hobmp
=(HBITMAP)SelectObject(hmdc,(HGDIOBJ)hbm);
                            GetObject((HGDIOBJ)hbm,
sizeof(BITMAP),&bmp);
                            BitBlt(nmlvcd
->nmcd.hdc,rc.left,
                                rc.top
+(RECTH(&rc)-bmp.bmHeight)/2,24,24,hmdc,0,0,SRCCOPY);
                            SelectObject(hmdc,(HGDIOBJ)hobmp);
                            DeleteObject((HGDIOBJ)hbm);
                            DeleteDC(hmdc);
                            
return CDRF_SKIPDEFAULT;
                        }

                        
return CDRF_DODEFAULT;
                    }

                    
return CDRF_DODEFAULT;
                }
else if(nmhdr->code==LVN_ITEMCHANGED){
                    LPNMLISTVIEW lv
=(LPNMLISTVIEW)lParam;
                    SetWindowLong(lv
->hdr.hwndFrom,GWL_USERDATA,lv->iItem);
                }
else if(nmhdr->code==LVN_KEYDOWN){
                    LPNMLVKEYDOWN lk
=(LPNMLVKEYDOWN)lParam;
                    CHAR desc[
256];
                    LVITEM itm;    
                    itm.mask
=LVIF_TEXT;
                    itm.iItem
=GetWindowLong(lk->hdr.hwndFrom,GWL_USERDATA);
                    itm.iSubItem
=3;
                    itm.pszText
=desc;
                    itm.cchTextMax
=256;
                    ListView_GetItem(lk
->hdr.hwndFrom,&itm);
                    
if(lk->wVKey==VK_RETURN)
                        MessageBox(hwnd,desc,
"节目简介",0);
                }

            }

        }
break;
        
case WM_DESTROY:
            DeleteObject((HGDIOBJ)hbmpClock);
            
return DefWindowProc(hwnd,msgID,wParam,lParam);
        
case WM_CLOSE:
            PrVideoSetOutputWindow(
0,0,720,576);
            
//RegisterEPGNotify(NULL);
            DefWindowProc(hwnd,msgID,wParam,lParam);
            
break;
        
case WM_ACTIVATE:
            
if(wParam){       
                RECT rc;
                GetWindowRect(GetDlgItem(hwnd,IDC_VIDEO),(LPRECT)
&rc);
                PrVideoSetOutputWindow(rc.left,rc.top,RECTW(
&rc),RECTH(&rc));
            }

            
return     DefWindowProc(hwnd,msgID,wParam,lParam);
        
default:
            
return DefWindowProc(hwnd,msgID,wParam,lParam);
    }

    
return 0;
}


static   void  CreateListView(HWND hwnd, int  count)
{
    
int i;
    LVCOLUMN lc;
    
char *titles[]={"开始时间","片长","片名","预定","节目介绍"};
    
int width[]={120,160,220,60,100};
    
//WS_EX_DLGMODALFRAME和LVS_EX_GRIDLINES定义存在冲突,会导致NC区域边框出现问题
    HWND hv=CreateWindowEx(LVS_EX_FULLROWSELECT/*|LVS_EX_GRIDLINES*/,"ListView",NULL,
        WS_TABSTOP
|WS_CHILD|WS_VSCROLL|WS_VISIBLE|LVS_SHOWSELALWAYS//|LVS_SINGLESEL
        |LVS_REPORT|LVS_NOCOLUMNHEADER,//|LVS_OWNERDRAWFIXED|,
        36,286,582,175,hwnd,(HMENU)IDC_EPGSCHEDULE,NULL,NULL);
    
for(i=0;i<sizeof(titles)/sizeof(char*);i++)
    
{
        lc.pszText
=titles[i];
        lc.cx
=width[i];
        lc.mask
=LVCF_TEXT|LVCF_WIDTH|LVCF_FMT;
        lc.fmt
=i==0?LVCFMT_RIGHT:LVCFMT_LEFT;
        SendMessage(hv,LVM_INSERTCOLUMN,i,(LPARAM)
&lc);
    }

}



HWND CreateEpgWnd(UINT grpId)
{
    
int i;
    HWND ch,DispWin;
    SYSTEMTIME tnow;
    HWND epgWnd;
    HWND hg;
    HWND htab;    
    epgWnd 
= CreateMainWindow(NULL,WS_TABSTOP|WS_OVERLAPPED,40,30,650,520,EpgWndProc);
    
    GetLocalTime(
&tnow);
    CreateWindow(
"Static",NULL,WS_VISIBLE|WS_CHILD|SS_LEFT,//|SS_OWNERDRAW,
                    350,13,290,25,epgWnd,(HMENU)IDC_DATETIME,NULL,NULL);

    
//标题
    CreateWindow("Static","节 目 指 南",WS_VISIBLE|WS_CHILD,//|SS_OWNERDRAW,
                  40,13,200,24,epgWnd,(HMENU)IDC_TITLE,NULL,NULL);

    hg
=CreateWindow("Select",NULL,WS_VISIBLE|WS_CHILD|WS_BORDER|
        OPS_SHOWARROWALWAYS
|OPS_NOLABEL|WS_DISABLED,//(grpId==0xFFFFFFFF?0:WS_DISABLED),
                    35,60,325,27,epgWnd,(HMENU)IDC_SVCGROUPS,NULL,NULL);
    
if (NULL != hg)
    
{
        FAVGROUP
*fav;
        CreateDefaultGroup(FALSE);
        UpdateAllGroup();
        fav
=GetFirstFavGroup();//添加分组数据
        for(i=0;fav;fav=fav->next,i++){
            INT idx;
            idx
=SendMessage(hg,OPT_ADDSTRING,i,(LPARAM)fav->name);
            SendMessage(hg,OPT_SETITEMDATA,idx,fav);
            
if(grpId==0xFFFF)
                SendMessage(hg,OPT_SETCURSEL,
0,(LPARAM)0);
            
else if(grpId==fav->FavId)
                SendMessage(hg,OPT_SETCURSEL,idx,
0);
        }

    }

    ch
=CreateWindow("Listbox",NULL,WS_TABSTOP|WS_VSCROLL|WS_VISIBLE|WS_CHILD|
                    LBS_OWNERDRAWFIXED
|LBS_HASSTRINGS|LBS_NOTIFY|LBS_WRAP,
                    
35,96,325,150,epgWnd,(HMENU)IDC_GRPSERVICE,NULL,NULL);
    
    
if (NULL != ch)
    
{
        FAVGROUP
*fav;
        fav
=FindFavGroupByID(grpId==0xFFFF?GROUP_ALL:grpId);
        
//添加业务数据
        GetAllService(ch,fav);

        SendMessage(ch,LB_SETITEMHEIGHT,
0,30);
        SendMessage(ch,LB_SETCURSEL,
0,0);
    }

    
//电视窗口
    DispWin=CreateWindow("Static",NULL,WS_VISIBLE|WS_CHILD|SS_OWNERDRAW,
                          
370,60,250,178,epgWnd,(HMENU)IDC_VIDEO,NULL,NULL);
    
//将电视窗口变为圆角矩形
    {
        RECT rc;
        HRGN rgn;
        GetWindowRect(DispWin,(LPRECT)
&rc);
        rgn
=CreateRoundRectRgn(0,0,RECTW(&rc),RECTH(&rc),10,10);
        SetWindowRgn(DispWin,rgn,FALSE);
        DeleteObject((HGDIOBJ)rgn);    
    }


    htab
=CreateWindow("tabcontrol",NULL,WS_VISIBLE|WS_TABSTOP|WS_CHILD|TCS_BUTTONS|TCS_HOTTRACK|TCS_FOCUSONBUTTONDOWN,//|TCS_OWNERDRAWFIXED,
                       36,258,582,27,epgWnd,(HMENU)IDC_WEEK,NULL,NULL);    
    
if(NULL != htab)
    
{
        TCITEM itm;
        
int i;
        GetLocalTime(
&tnow);
        itm.mask
=TCIF_TEXT|TCIF_PARAM;
        
for (i=0; i<7; i++){
            CHAR wname[
32];
            GetLocaleInfo(LOCALE_NEUTRAL,
                tnow.wDayOfWeek
==0?LOCALE_SDAYNAME7:(LOCALE_SDAYNAME1+tnow.wDayOfWeek-1),wname,32);
            itm.lParam
=tnow.wDayOfWeek;
            tnow.wDayOfWeek
=(tnow.wDayOfWeek+1)%7;
            itm.pszText 
= wname;
            TabCtrl_InsertItem(htab,i,
&itm);
        }

        SendMessage(htab,TCM_SETCURSEL,
0,0);
    }

    CreateListView(epgWnd,
100);
    
{
        TBBUTTON toolbarBtns[] 
= {
            
{000, BTNS_SEP, {00}00},
            
{0123, TBSTATE_ENABLED,BTNS_BUTTON, {00}0"选择"},
            
{1122, TBSTATE_ENABLED, BTNS_BUTTON, {00}00},
            
{2133, TBSTATE_ENABLED, BTNS_BUTTON, {00}0"Test"},
            
{3144, TBSTATE_ENABLED, BTNS_BUTTON, {00}00},
            
{4145, TBSTATE_ENABLED, BTNS_BUTTON, {00}00},
            
{5156, TBSTATE_ENABLED, BTNS_BUTTON|BTNS_DROPDOWN, {00}00},
        }
;

        HWND htoolbar
=CreateToolbarEx(epgWnd, WS_CHILD|WS_VISIBLE|
            TBSTYLE_LIST
|TBSTYLE_TRANSPARENT|TBSTYLE_FLAT|CCS_BOTTOM,
            
12342, hInstDVBRes, IDB_COLORKEYS, toolbarBtns,
            
sizeof(toolbarBtns)/sizeof(TBBUTTON), 36183618sizeof(TBBUTTON));
        SendMessage(htoolbar,TB_SETEXTENDEDSTYLE,
0, TBSTYLE_EX_DRAWDDARROWS);
    }


    ShowWindow(epgWnd,SW_SHOW);
    
//SetFocus(GetDlgItem(epgWnd,IDC_GRPSERVICE));    
    SetTimer(epgWnd,IDT_EPGTIMER,1000,NULL);
    
return epgWnd;
}



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值