0xAA55 发表于 2015-7-15 02:50:18

【C】用C语言实现的VB的PictureBox

作者:0xAA55
来源:http://www.0xaa55.com/thread-1417-1-1.html
转载请注明出处。

如图所示。这并不和VB的完全一样。它能显示图片,以及拉伸显示图片,除此以外,还能开启“自动重绘”模式。在自动重绘模式下用户需要通过调用函数取得hDC进行绘图操作。这样这东西就内置了一个画板。
头文件的代码:#ifndef _PictureBoxHeader_
#define _PictureBoxHeader_

#include<Windows.h>

//PictureBox的额外属性结构
//读取方式:(PicBoxAttr_p)GetWindowLong(hPicBox,GWL_USERDATA);
typedef struct
{
        DWORD                dwSign;                //签名
        HINSTANCE        hInst;                //实例句柄
        HWND                hWnd;                //窗口句柄
        HBRUSH                BkBrush;        //背景色
        HDC                        hCtlDC;                //控件HDC

        HDC                        hPicDC;                //图像HDC
        HBITMAP                hPicBmp;        //图像
        LONG                lPicW;                //图像宽度
        LONG                lPicH;                //图像高度

        HDC                        hImgDC;                //后台图像HDC
        HBITMAP                hImgBmp;        //后台图像
        void                *pImgBits;        //后台图像位图数据
        LONG                lImgW;                //后台图像宽度
        LONG                lImgH;                //后台图像镐度

        BOOL                bStretch;        //是否拉伸
        BOOL                bAutoRedraw;//是否自动重绘
}PicBoxAttr_t,*PicBoxAttr_p;

//注册PictureBox窗口类
ATOM WINAPI RegisterPictureBox();

//创建PictureBox控件
HWND WINAPI CreatePictureBox(int x,int y,int w,int h,HWND hParent,WORD ID);

//加载PictureBox的图像
BOOL WINAPI LoadPicture(HWND hWnd,TCHAR*szPicFile);

//判断是否为PictureBox控件
BOOL WINAPI IsPictureBox(HWND hWnd);

//设置PictureBox控件是否拉伸图像
void WINAPI SetPicBoxStretchMode(HWND hWnd,BOOL bStretch);

//设置PictureBox控件是否自动重绘
void WINAPI SetPicBoxAutoRedrawMode(HWND hWnd,BOOL bAutoRedraw);

//取得PictureBox的绘图句柄
HDC WINAPI GetPicBoxHDC(HWND hWnd);

//显示PictureBox的图像
void WINAPI RefreshPicBox(HWND hWnd);

//设置PictureBox的边框样式
void WINAPI SetPicBoxBorderMode(HWND hWnd,BOOL bShowBorder);

//清屏
void WINAPI ClearPicBoxImage(HWND hWnd);

//删除图片框的图片
void WINAPI DeletePicBoxPicture(HWND hWnd);

#endif // !_PictureBoxHeader_实现部分的代码:#include"picbox.h"

static ATOM g_ClassAtom=0;
const TCHAR g_szPicBoxClass[]=TEXT("PictureBox");

const DWORD        PicBoxSign=0x091C7B08;

#define        CalcPitch(w,b)        ((((w)*(b)-1)/32+1)*4)

//=============================================================================
//函数:CreatePicBoxAttr
//描述:创建PictureBox属性块
//-----------------------------------------------------------------------------
static
PicBoxAttr_p CreatePicBoxAttr(HWND hWnd)
{
        PicBoxAttr_p pAttr=(PicBoxAttr_p)malloc(sizeof(PicBoxAttr_t));
        if(pAttr)
        {
                memset(pAttr,0,sizeof(PicBoxAttr_t));

                pAttr->dwSign=PicBoxSign;
                pAttr->hInst=GetModuleHandle(NULL);
                pAttr->hWnd=hWnd;
                pAttr->BkBrush=(HBRUSH)(COLOR_BTNFACE+1);
                pAttr->hCtlDC=GetWindowDC(hWnd);
        }

        return pAttr;
}

//=============================================================================
//函数:DeletePicBoxAttr
//描述:删除PictureBox属性块
//-----------------------------------------------------------------------------
static
void DeletePicBoxAttr(PicBoxAttr_p pAttr)
{
        if(pAttr)
        {
                //释放控件HDC
                if(pAttr->hCtlDC)
                        ReleaseDC(pAttr->hWnd,pAttr->hCtlDC);
               
                //删除图像
                if(pAttr->hPicBmp)DeleteObject(pAttr->hPicBmp);
                if(pAttr->hPicDC)DeleteDC(pAttr->hPicDC);

                //删除后台图像
                if(pAttr->hImgBmp)DeleteObject(pAttr->hImgBmp);
                if(pAttr->hImgDC)DeleteDC(pAttr->hImgDC);

                //释放内存
                free(pAttr);
        }
}

//=============================================================================
//函数:SetupPicBoxImage
//描述:重置PictureBox的后台图像
//-----------------------------------------------------------------------------
static
BOOL SetupPicBoxImage(PicBoxAttr_p pAttr)
{
        RECT rc;
        BITMAPINFOHEADER BMIF;
        HDC hWindowDC;
        HDC hNewDC=NULL;
        HBITMAP hNewBMP=NULL;
        void*pBits;

        //创建一个新的HDC和HBITMAP
        hWindowDC=GetWindowDC(pAttr->hWnd);
        hNewDC=CreateCompatibleDC(hWindowDC);
        ReleaseDC(pAttr->hWnd,hWindowDC);
        if(!hNewDC)
                return FALSE;

        GetClientRect(pAttr->hWnd,&rc);
        BMIF.biSize=sizeof(BMIF);
        BMIF.biWidth=rc.right-rc.left;
        BMIF.biHeight=rc.bottom-rc.top;
        BMIF.biPlanes=1;
        BMIF.biBitCount=24;
        BMIF.biCompression=0;
        BMIF.biSizeImage=CalcPitch(BMIF.biWidth,BMIF.biBitCount)*BMIF.biHeight;
        BMIF.biXPelsPerMeter=0;
        BMIF.biYPelsPerMeter=0;
        BMIF.biClrUsed=0;
        BMIF.biClrImportant=0;
        hNewBMP=CreateDIBSection(hNewDC,(BITMAPINFO*)&BMIF,DIB_PAL_COLORS,&pBits,
                NULL,0);
        if(!hNewBMP)
                goto Failed;
        SelectObject(hNewDC,hNewBMP);

        //填充为背景色,然后搬运旧的后台图像
        FillRect(hNewDC,&rc,pAttr->BkBrush);
        if(pAttr->hImgDC)
        {
                BitBlt(hNewDC,0,0,pAttr->lImgW,pAttr->lImgH,pAttr->hImgDC,0,0,SRCCOPY);
                DeleteDC(pAttr->hImgDC);
        }
        else if(pAttr->hPicDC)
                BitBlt(hNewDC,0,0,pAttr->lPicW,pAttr->lPicH,pAttr->hPicDC,0,0,SRCCOPY);

        if(pAttr->hImgBmp)
                DeleteObject(pAttr->hImgBmp);

        //替换为新的后台图像
        pAttr->lImgW=BMIF.biWidth;
        pAttr->lImgH=BMIF.biHeight;
        pAttr->hImgBmp=hNewBMP;
        pAttr->hImgDC=hNewDC;
        pAttr->pImgBits=pBits;

        return TRUE;
Failed:
        if(hNewBMP)
                DeleteObject(hNewBMP);
        if(hNewDC)
                DeleteDC(hNewDC);
        return FALSE;
}

//=============================================================================
//函数:LoadPicture
//描述:加载PictureBox的图像
//-----------------------------------------------------------------------------
BOOL WINAPI LoadPicture(HWND hWnd,TCHAR*szPicFile)
{
        PicBoxAttr_p pAttr;
        BITMAP bmp;

        if(IsPictureBox(hWnd))
                pAttr=(PicBoxAttr_p)GetWindowLongPtr(hWnd,GWL_USERDATA);
        else
                return FALSE;

        //创建HDC,然后清除之前加载过的图像
        if(!pAttr->hPicDC)
        {
                HDC hDC=GetWindowDC(hWnd);
                pAttr->hPicDC=CreateCompatibleDC(hDC);
                ReleaseDC(hWnd,hDC);
        }
        if(pAttr->hPicBmp)
                DeleteObject(pAttr->hPicBmp);

        //加载图像
        pAttr->hPicBmp=(HBITMAP)LoadImage(pAttr->hInst,szPicFile,IMAGE_BITMAP,0,0,
                LR_LOADFROMFILE|LR_CREATEDIBSECTION);
        if(!pAttr->hPicBmp)
                return FALSE;
        SelectObject(pAttr->hPicDC,pAttr->hPicBmp);

        GetObject(pAttr->hPicBmp,sizeof(bmp),&bmp);
        pAttr->lPicW=bmp.bmWidth;
        pAttr->lPicH=bmp.bmHeight;

        RefreshPicBox(hWnd);
        return TRUE;
}

//=============================================================================
//函数:RefreshPicBox
//描述:显示PictureBox的图像
//-----------------------------------------------------------------------------
void WINAPI RefreshPicBox(HWND hWnd)
{
        RECT rc;
        GetClientRect(hWnd,&rc);
        InvalidateRect(hWnd,&rc,TRUE);
}

//=============================================================================
//函数:PicBoxWndProc
//描述:PictureBox的消息处理函数
//-----------------------------------------------------------------------------
static
LRESULT CALLBACK PicBoxWndProc(HWND hWnd,UINT Msg,WPARAM wp,LPARAM lp)
{
        PicBoxAttr_p pAttr=NULL;
        switch(Msg)
        {
        case WM_CREATE:
                pAttr=CreatePicBoxAttr(hWnd);
                if(pAttr)
                        SetWindowLongPtr(hWnd,GWL_USERDATA,(LONG_PTR)pAttr);
                else
                        return-1;
                break;
        case WM_COMMAND:
                hWnd=GetParent(hWnd);
                if(hWnd)
                        return SendMessage(hWnd,Msg,wp,lp);
                break;
        case WM_PAINT:
                pAttr=(PicBoxAttr_p)GetWindowLong(hWnd,GWL_USERDATA);
                if(pAttr)
                {
                        PAINTSTRUCT ps;
                        HDC hDC;
                        hDC=BeginPaint(hWnd,&ps);
                        if(pAttr->bAutoRedraw)//自动重绘的话,绘制后台图像
                        {
                                if(!pAttr->hImgDC || !pAttr->hImgBmp)
                                        SetupPicBoxImage(pAttr);
                                BitBlt(hDC,0,0,pAttr->lImgW,pAttr->lImgH,
                                pAttr->hImgDC,0,0,SRCCOPY);
                        }
                        else//否则绘制图像
                        {
                                RECT rc;
                                GetClientRect(hWnd,&rc);
                                if(pAttr->bStretch)
                                {
                                        SetStretchBltMode(hDC,HALFTONE);
                                        StretchBlt(hDC,
                                                rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,
                                                pAttr->hPicDC,
                                                0,0,pAttr->lPicW,pAttr->lPicH,SRCCOPY);
                                }
                                else
                                        BitBlt(hDC,rc.left,rc.top,pAttr->lPicW,pAttr->lPicH,
                                                pAttr->hPicDC,0,0,SRCCOPY);
                        }
                        EndPaint(hWnd,&ps);
                }
                break;
        case WM_DESTROY:
                pAttr=(PicBoxAttr_p)GetWindowLongPtr(hWnd,GWL_USERDATA);
                if(pAttr)
                        DeletePicBoxAttr(pAttr);
                SetWindowLongPtr(hWnd,GWL_USERDATA,0);
                break;
        default:
                return DefWindowProc(hWnd,Msg,wp,lp);
        }
        return 0;
}

//=============================================================================
//函数:RegisterPictureBox
//描述:注册PictureBox窗口类
//-----------------------------------------------------------------------------
ATOM WINAPI RegisterPictureBox()
{
        WNDCLASSEX WCEx=
        {
                sizeof(WNDCLASSEX),
                0,
                PicBoxWndProc,
                0,
                0,
                GetModuleHandle(NULL),
                NULL,
                LoadCursor(NULL,MAKEINTRESOURCE(IDC_ARROW)),
                (HBRUSH)(COLOR_BTNFACE+1),
                NULL,
                g_szPicBoxClass,
                NULL
        };
        return g_ClassAtom=RegisterClassEx(&WCEx);
}

//=============================================================================
//函数:CreatePictureBox
//描述:创建PictureBox控件
//-----------------------------------------------------------------------------
HWND WINAPI CreatePictureBox(int x,int y,int w,int h,HWND hParent,WORD ID)
{
        return CreateWindowEx(0,MAKEINTATOM(g_ClassAtom),NULL,
                WS_CHILD|WS_VISIBLE|WS_BORDER,x,y,w,h,
                hParent,(HMENU)ID,GetModuleHandle(NULL),NULL);
}

//=============================================================================
//函数:IsPictureBox
//描述:判断是否为PictureBox控件
//-----------------------------------------------------------------------------
BOOL WINAPI IsPictureBox(HWND hWnd)
{
#        define nPicBox (sizeof(g_szPicBoxClass)/sizeof(TCHAR)-1)
        TCHAR szPicBoxClass;

        //首先判断窗口类
        if(GetClassName(hWnd,szPicBoxClass,nPicBox+2) == nPicBox)
        {
                if(!lstrcmp(szPicBoxClass,g_szPicBoxClass))
                {
                        //然后判断附加信息
                        PicBoxAttr_p pAttr
                                =(PicBoxAttr_p)GetWindowLong(hWnd,GWL_USERDATA);
                        if(!IsBadReadPtr(pAttr,sizeof(PicBoxAttr_t)))
                        {
                                if(pAttr->dwSign==PicBoxSign)
                                        return TRUE;
                        }
                }
        }
       
        return FALSE;
#        undef nPicBox
}

//=============================================================================
//函数:SetPicBoxStretchMode
//描述:设置PictureBox控件是否拉伸图像
//-----------------------------------------------------------------------------
void WINAPI SetPicBoxStretchMode(HWND hWnd,BOOL bStretch)
{
        if(IsPictureBox(hWnd))
        {
                PicBoxAttr_p pAttr;
                pAttr=(PicBoxAttr_p)GetWindowLong(hWnd,GWL_USERDATA);
                pAttr->bStretch=bStretch;

                //强制重绘
                RefreshPicBox(hWnd);
        }
}

//=============================================================================
//函数:SetPicBoxAutoRedrawMode
//描述:设置PictureBox控件是否自动重绘
//-----------------------------------------------------------------------------
void WINAPI SetPicBoxAutoRedrawMode(HWND hWnd,BOOL bAutoRedraw)
{
        if(IsPictureBox(hWnd))
        {
                PicBoxAttr_p pAttr=(PicBoxAttr_p)GetWindowLong(hWnd,GWL_USERDATA);
                pAttr->bAutoRedraw=bAutoRedraw;
                if(bAutoRedraw)
                        SetupPicBoxImage(pAttr);
        }
}

//=============================================================================
//函数:GetPicBoxHDC
//描述:取得PictureBox的绘图句柄
//-----------------------------------------------------------------------------
HDC WINAPI GetPicBoxHDC(HWND hWnd)
{
        if(IsPictureBox(hWnd))
        {
                PicBoxAttr_p pAttr=(PicBoxAttr_p)GetWindowLong(hWnd,GWL_USERDATA);
                if(pAttr->bAutoRedraw)
                        return pAttr->hImgDC;
                else
                        return pAttr->hCtlDC;
        }
        return NULL;
}

//=============================================================================
//函数:SetPicBoxBorderMode
//描述:设置PictureBox的边框样式
//-----------------------------------------------------------------------------
void WINAPI SetPicBoxBorderMode(HWND hWnd,BOOL bShowBorder)
{
        if(IsPictureBox(hWnd))
        {
                if(bShowBorder)
                        SetWindowLong(hWnd,GWL_STYLE,GetWindowLong(hWnd,GWL_STYLE)|WS_BORDER);
                else
                        SetWindowLong(hWnd,GWL_STYLE,GetWindowLong(hWnd,GWL_STYLE)&~WS_BORDER);
                RefreshPicBox(hWnd);
        }
}

//=============================================================================
//函数:ClearPicBoxImage
//描述:清屏
//-----------------------------------------------------------------------------
void WINAPI ClearPicBoxImage(HWND hWnd)
{
        if(IsPictureBox(hWnd))
        {
                PicBoxAttr_p pAttr=(PicBoxAttr_p)GetWindowLong(hWnd,GWL_USERDATA);
                if(pAttr->bAutoRedraw && pAttr->hImgDC)
                {
                        RECT rc;
                        GetClientRect(hWnd,&rc);
                        FillRect(pAttr->hImgDC,&rc,pAttr->BkBrush);
                        if(pAttr->hPicDC && pAttr->hPicBmp)
                                BitBlt(pAttr->hImgDC,0,0,pAttr->lPicW,pAttr->lPicH,
                                        pAttr->hPicDC,0,0,SRCCOPY);
                }
                RefreshPicBox(hWnd);
        }
}

//=============================================================================
//函数:DeletePicBoxPicture
//描述:删除图片框的图片
//-----------------------------------------------------------------------------
void WINAPI DeletePicBoxPicture(HWND hWnd)
{
        if(IsPictureBox(hWnd))
        {
                PicBoxAttr_p pAttr=(PicBoxAttr_p)GetWindowLong(hWnd,GWL_USERDATA);
                if(pAttr->bAutoRedraw)
                {
                        RECT rc;
                        GetClientRect(hWnd,&rc);
                        FillRect(pAttr->hImgDC,&rc,pAttr->BkBrush);
                }
                DeleteObject(pAttr->hPicBmp);pAttr->hPicBmp=NULL;
                DeleteDC(pAttr->hPicDC);pAttr->hPicDC=NULL;
                RefreshPicBox(hWnd);
        }
}引用的例子:#include<Windows.h>

#include"picbox.h"

LRESULT CALLBACK WndProc(HWND hWnd,UINT Msg,WPARAM wp,LPARAM lp)
{
        switch(Msg)
        {
        default:
                return DefWindowProc(hWnd,Msg,wp,lp);
        case WM_CREATE:
                RegisterPictureBox();
                do
                {
                        HWND hPicBox1,hPicBox2;

                        hPicBox1=CreatePictureBox(0,0,300,300,hWnd,1);
                        LoadPicture(hPicBox1,TEXT("tex1.bmp"));

                        hPicBox2=CreatePictureBox(300,0,400,400,hWnd,1);
                        LoadPicture(hPicBox2,TEXT("tex1.bmp"));
                        SetPicBoxStretchMode(hPicBox2,TRUE);
                }while(0);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        }
        return 0;
}

int APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR szCmd,int nCmd)
{
        WNDCLASSEX WCEx={sizeof(WNDCLASSEX),0,WndProc,0,0,hInst,LoadIcon(NULL,MAKEINTRESOURCE(IDI_APPLICATION)),LoadCursor(NULL,MAKEINTRESOURCE(IDC_ARROW)),(HBRUSH)COLOR_BTNFACE,NULL,TEXT("tutpicbox"),NULL};//窗口类
        MSG msg;
        HWND hWnd=CreateWindowEx(0,MAKEINTATOM(RegisterClassEx(&WCEx)),TEXT("tutpicbox"),WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInst,NULL);//窗口句柄
        ShowWindow(hWnd,nCmd);
        UpdateWindow(hWnd);
        while(GetMessage(&msg,NULL,0,0))//消息循环
        {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
        }
        return msg.wParam;
}BIN:
SRC:

Golden Blonde 发表于 2015-7-15 03:01:55

这么复杂的玩意 我要怎么结合到A5UI里呢!!!

0xAA55 发表于 2015-7-15 03:05:46

美俪女神 发表于 2015-7-15 03:01
这么复杂的玩意 我要怎么结合到A5UI里呢!!!

这其实就是一个自制控件而已。

icqw 发表于 2015-7-15 22:24:14

可以转载么?

0xAA55 发表于 2015-7-15 23:05:14

icqw 发表于 2015-7-15 22:24
可以转载么?

可以。请注明作者和原网址。

icqw 发表于 2015-7-15 23:28:33

0xAA55 发表于 2015-7-15 23:05
可以。请注明作者和原网址。

嗯嗯 ,了解。

0xAA55 发表于 2015-7-18 00:47:09

已更新:
添加删除图片、清屏等功能。
修复窗口类判断不严谨的漏洞。

0x01810 发表于 2015-7-20 17:15:25

很方便的模板 thx

白天 发表于 2017-10-25 02:13:20

有什么好处啊?

白天 发表于 2017-10-25 02:22:38

可以提高重绘速度吗
页: [1]
查看完整版本: 【C】用C语言实现的VB的PictureBox