快捷搜索:
您的位置:奥门新萄京8522 > 成人娱乐 > 如何用易语言自绘gdi,实现系统滚动条换肤功能

如何用易语言自绘gdi,实现系统滚动条换肤功能

2019-10-29 21:24

问题:什么用易语言自绘gdi?

转载几篇外人写的皮肤类控件的技巧散文

图片 1

回答:

1 落成系统滚动条换肤功用

原连接:

上风度翩翩篇我们来得了什么动用Windows SDK创制基本控件,本篇来谈谈怎么样输出文本字符。

以下二种自绘都可使用GDI或是GDI 完结1.控件自绘通过API 在子类化中收获WM_PAINT新闻, BeginPaint()最早控件自绘,以EndPaint()截止其位图设备为各控件和窗口,所以通过此方法绘制的窗口存在控件句柄。优点:无需手动描述控件音讯,只须要关怀控件的绘图短处:窗口不可能同时兼备差异光滑度2.全然自绘窗口具备WS_EX_LAYERED属性,WM_PAINT音讯失效,只可以通过API UpdateLayeredWindow进行窗口更新,全体控件均由自绘完结,包含自绘组件的音讯也须求手动完毕。优点:窗口可享有不相同折射率,那是控件自绘所达不到的老毛病:全体控件均由自绘实现,富含自绘组件的音讯也必要手动完成。须求精通WINDOWS音讯机制,并开展自绘组件的新闻模拟。窗口上的平日空间将不可能出示,然则可由此取得WM_DRAWITEM 和WM_PAINT音讯实行绘图,好处便是空间的有着事件都课使用,无需自创模拟。

对于Windows系统中各样控件换肤作用,要数滚动条的换肤最难完结了,特别是控件自带的系统滚动条,如Edit、ListBox、ListView、TreeView等自带的体系滚动条,要想达成其自定义的肌肤功能,用健康方法有如都敬谢不敏兑现。

 

在运用Win32编制程序时,大家常常要出口文本到窗口上,Windows全体的文书字符或然图片输出都以透过图形设备接口(GDI)举办的,Windows的三大主导器件之后生可畏的GDI32.dll封装了全数的文件和图像输出。

对曹金玲规的肌肤定制通常都以经过定制WM_PAINT、WM_ERASEBKGND、WM_CTLCOLORxxx、NM_CUSTOMDRAW来兑现。然则系统滚动条的绘图,常规的、很阳光的方法行不通,微软把一条平坦大路堵死了。依照本身的观看比赛测试,系统滚动条有数不完的新闻都对其施行了绘图,那包涵WM_NCPAINT、WM_NCMOUSEMOVE、WM_NCMOUSELEAVE、WM_HSCROLL、WM_VSCROLL、WM_KEYDOWN、WM_MOUSEWHEEL等等,这么些音信中大抵能够定制,但多少无助定制。比方WM_HSCROLL就不能定制,假若大家管理那一个音信,就务须和睦决定滚动条的限量、地点、翻页值,而那一个值大家平时不可能获得,微软素有未曾报告我们,对于差别的控件它操控滚动条到底选择何种政策,不知情。尽管大家不去定制那些WM_HSCROLL,而暗中认可的处理它又实施滚动条的绘图,那不失为进退无路,叫人狼狈不堪。当然不是一丝一毫未有主意,死路一条。为了制服阻碍,翻越障碍,各种人有例外的陈设,有攀岩翻越的,安全性不高;也是有走小路绕行的,比较费力。

达成控件的晶莹背景

  • GDI基本知识

在互连网再三查找,本身也留意讨论,基本有三种形式来贯彻系统滚动条换肤,风度翩翩种方法是HOOK API,也正是拦截API的法子,还有少年老成种是模拟法。

成千上万境况下,我们必要控件 的背景是晶莹剔透的,正是必要直接看出控件父窗口的背景颜色、背景位图,比方标签控件、单选Radio控件、复选Check控件,常常都务求在父窗口的背景上 举行绘图。不过须求控件的画布透明,这几个技巧在GDI的文书档案中绝非观察Microsoft作任何评释,当然还是有其他方式。

Windows下要绘制和出口文本,都以通过GDI(Graphics Device Interface,图形设备接口)完毕的,GDI是windows在绘制图文时的配备上下文遭遇,富含画笔、画刷、字体、位图等多种与绘图有关的指标。设备条件(DC)在绘制中起入眼的功效。大约具有的绘图(满含图片和文书)都与道具条件有关,注意“境遇”的意思,就跟大家在画布上作画和写字同样,绘制时的画布是哪个,用的怎么笔,什么颜色,填充整个画布时用的怎样刷子等等,那正是大家的绘图时的条件,而Windows绘图的DC设备上下文正是豆蔻年华律的道理。设备条件句柄(HDC)正是用来描述DC的句柄,能够说,只要有了那一个句柄,就具有了在窗口上输出图形和文书的规格。你得到了窗口用户区的HDC,就可以在窗口顾客区上画;你收获了窗口的非顾客区HDC,就足以在它上边画;你拿走了桌面HDC,就可以一贯在桌面上画……

拦截API,实际上是改良操作系统的API入口。因为系统绘制滚动条是透过各样绘制函数来落到实处的,举个例子SetScrollInfo(),基本连串通过那生机勃勃类函数达成滚动条的绘图,对这一个API举办阻挠,约等于我们和谐写多个SetScrollInfo(),来亲自贯彻滚动条的绘图,以便因而落成滚动条的自定义绘制,实现大家想要的各个风格的肌肤外观。API的掣肘有二种:风华正茂种是更正系统所装入内部存款和储蓄器可举行模块的导入地址,替换来大家所写的伪API之处,使API调用能够自行跳转到那个伪API上;还或者有生机勃勃种是直接纠正API函数首地址处的多少机器指令,保存现场,写入跳转指令,使系统在实施到那些API时能自动跳转到大家所写的伪API上。笔者要说的是,这么些拦截办法还真是有个别邪门,有安全隐患,病毒就常干这种事情。对操作系统举行那类暴力破解式的校订,比较轻易引起系统防火墙或反病毒软件报错,Windows原则上不容许干这种事;其二,后生可畏旦选拔此法的程序因不胜而夭亡,原本对操作系统的改动未有苏醒,那也许会危害到系统里的装有进度的安居,导致死机或运维非常。对于商业性的工程支出,往往很忧虑这点,都赞同于追求平稳,日常是宁用拙法,不玩巧技;其三,此法有线程同步难点:因为正值你改改程序指令同一时候,若其余进度里的线程恰好履行到这里时候难题就能够爆发出来,单CPU可能没啥问题,系统内部存款和储蓄器和CPU缓冲可以造成一同,但多核系统就难说了;别的那些方式还应该有移植性难点:在黄金时代种版本的系统中,通过拦截API有效,在另黄金时代种版本的体系中,就放任得还使得,终归微软落实滚动条的绘图,它没明确一定就用哪个函数来兑现,也许新系统中它另有必杀技,API拦截也就不灵了。

 

获得器材条件句柄的办法有二种:一是管理WM_PAINT新闻时,通过BeginPaint函数再次来到。此外后生可畏种正是由此GetDC、GetWindowDC的API函数获取。

上面作者要详细讲的是模拟法了,那些措施不用拦截API,全数的手艺实现都限制在系统所允许的范围内,咱三衅三浴的当奉公守法的好心人。

本条: 假设程序协助桌面核心服务来讲,则可调用主旨服务的API来促成背景。我们先看看那几个API:

  • 通过WM_PAINT新闻获得DC

所谓模拟法就是在系统滚动条的区域放置二个效仿窗口,那么些窗口特地用于绘制系统滚动条。当然我们也要拦截带滚动条控件的几何新闻,以管教模拟窗口的绘图正确。下边只以ListView控件的水准滚动条为例,实行表达,垂直滚动条换肤能够列推。

HRESULT DrawThemeParentBackground(HWND hwnd , HDC hdc , RECT *prc );

Windows在检验到必要再行绘制也许刷新窗口时,会积极性须求管理WM_PAINT音信。例如在如下情形下就能够继续努力求管理:

图片 2

本条函数就是特意用来绘制父窗口的背景的,此中的hwnd参数是子窗口的句柄,hdc也时子窗口的画布句柄,prc是子窗口需绘制的区域,这几个函数实际是把父窗口的背景拷贝到子窗口上来,以这种格局达到透明。

  1. 客户移动三个窗口,导致原来被盖住的部分窗口彰显出来。
  2. 客户调节窗口的轻重,並且窗口作风类型设置为CS_HREDRAW和CS_VREDRAW。
  3. 前后相继调用ScrollWindow可能ScrollDC函数滚动客商区。
  4. 前后相继调用InvalidateRect或然InvalidateWranglergn函数,该函数字突显示生产一条WM_PAINT消息。

首先大家要在滚动条的区域上创制一个效仿窗口,恰好覆盖滚动条:

 

咱俩得以在该音信中成就图像和文字绘制,该音信的拍卖具备特定的格式,必须在事实上绘制前调用BeginPaint,在绘制完结后调用EndPaint函数,相当于说我们需求把具备绘制的功力都放到这八个函数之间,并且HDC也一定要在当时期利用,不能够保存起来在任哪里方选用。使用WM_PAINT有一个功利,正是windows会自身计算哪些区域要求立异,也正是说独有真正调换的地点才会更新,那样立异的代价会减低到细微。

HWND hListView = ...;//ListView窗口的句柄

其二: 尽管程序不支持桌面核心服务,则不可能接收方面包车型地铁不二法门,比如程序运维在Windows二〇〇〇上。此时我们能够向父窗口发送WM_PAINT新闻,不过此新闻所附带的wParam参数是五个画布句柄:

  • 经过API函数获取HDC

HWND pWnd = ::GetParent(hListView);

HDC dc = GetDC(NULL);

我们还足以经过GetDC、GetWindowDC函数来收获HDC,可是要细心,通过那么些来获得的HDC,能够保存起来在任何时候使用,但是要记住生龙活虎旦窗口有校勘,必需想艺术另行绘制,不然就能磨灭了。最终在利用完成后需求调用ReleaseDC来刑释,不然会变成能源走漏。

HWND hBuddy = ::CreateWindowEx(WS_EX_NOACTIVATE, "Buddy_Window", "", WS_CLIPSIBLINGS|WS_DISABLED|WS_CHILD, 0, 0, 0, 0, pWnd, NULL, gModule, NULL);

HWND cWnd= ...;//子窗口句柄

  • 创办特定字体

Buddy_Window是您注册的比葫芦画瓢窗口类。注意,窗口必须要有WS_DISABLED风格,那是个至关心重视要,那几个风格能够保障鼠标操作能够由此模拟窗口,而直白操控到所覆盖的滚动条,模拟窗口本人不选取别的鼠标键盘的输入。其它读取滚动条的矩形以至它的种种要素的可视、可用、压下等气象可因此GetScrollBarInfo()这些API来完结,可是要证Bellamy些,那些API有些Bug,大家可去下载FreeCL 2.03版源码,里头改良了这么些主题素材。

HWND pWnd= ...;//父窗口句柄

大家平日最广大的文书输出是无需本身创办字体的,因为周围的对象都有连串预约义好的。如若想出口点新鲜(非系统预订义的)字体,就须要我们创建并机关选入设备条件。创设字体首要有CreateFont和CreateFontIndirect,那三个函数的参数都游人如织,基本均等,具体用法看前边的实例。

实现创制模拟窗口之后,你要给ListView安装一个您写的窗口进度,以阻挠各个导致滚动条属性改动的种种新闻:

RECTcRect;

  • 落到实处公文绘制

LRESULT CALLBACK MyListViewProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

GetClientRect(cWnd,&cRect);

有了上面包车型客车功底,我们就足以因此Windows的API来达成文本输出了,常用的文件输出函数有TextOut、DrawText、DrawTextExt、ExtTextOut等,那么些函数基本都有类同的参数,例如hdc,坐标地点,字符串。上面TextOut、DrawText、ExtTextOut为例来阐明怎样在Windows窗口中怎么着输出文本,此外请查看MSDN的用法。

{

HBITMAPbitmap = CreateCompatibleBitmap(dc, cRect.right,cRect.bottom);

#include <windows.h>
#include <tchar.h>

static TCHAR szAppName[] = TEXT("Textout");
static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
     HWND     hWnd;
     MSG      msg;
     WNDCLASS wndclass;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW;
     wndclass.lpfnWndProc   = WndProc;
     wndclass.cbClsExtra    = 0;
     wndclass.cbWndExtra    = 0;
     wndclass.hInstance     = hInstance;
     wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
     wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
     wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
     wndclass.lpszMenuName  = NULL;
     wndclass.lpszClassName = szAppName;

     if (!RegisterClass(&wndclass))
     {
          MessageBox (NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
          return 0;
     }

     hWnd = CreateWindow(szAppName,            // window class name
                          szAppName,           // window caption
                          WS_OVERLAPPEDWINDOW, // window style
                          CW_USEDEFAULT,       // initial x position
                          CW_USEDEFAULT,       // initial y position
                          400,                 // initial x size
                          300,                 // initial y size
                          NULL,                // parent window handle
                          NULL,                // window menu handle
                          hInstance,           // program instance handle
                          NULL);               // creation parameters

     ShowWindow(hWnd, iCmdShow);
     UpdateWindow(hWnd);

     while (GetMessage(&msg, NULL, 0, 0))
     {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
     }

     return msg.wParam;
}

static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC         hDC;
    PAINTSTRUCT ps;

    switch (message)
    {
    case WM_CREATE:
        return 0;
    case WM_PAINT:
        {
            RECT rect = {10, 30, 100, 50};
            TCHAR str[] = TEXT("English and 中文");

            hDC = BeginPaint(hWnd, &ps);
            TextOut(hDC, 10, 10, str, _tcslen(str));

            SetTextColor(hDC, RGB(255,0,0));
            DrawText(hDC, str, -1, &rect, DT_LEFT|DT_VCENTER);

            SetTextColor(hDC, RGB(0,255,0));
            INT dx[] = {8,8,8,8,16,8,8,8,16,8,8,8,10};
            ExtTextOut(hDC, 10, 50, 0, &rect, str, _tcslen(str), dx);

            SetTextColor(hDC, RGB(0,0,255));
            rect.right = 110;
            rect.top = 70;
            rect.bottom = 82;
            ExtTextOut(hDC, 10, rect.top, ETO_CLIPPED, &rect, str, _tcslen(str), dx);
            HFONT hFont = CreateFont(96,         // nHeight, 所创建字体的字符高度
                        0,           // nWidth,       字体的字符平均宽度
                        200,          // nEscapement,  字符输出方向与水平向右的方向所成角度,以0.1度为单位
                        0,             // nOrientation, 字符与基线的角度,以0.1度为单位
                        FW_BOLD,        // nWeight,      字符颜色的深浅度
                        TRUE,            // bItalic,      斜体属性标志(FALSE:正常字体,TRUE:斜体)
                        FALSE,            // bUnderline,   下划线属性标志(FALSE:无下划线,TRUE:有下划线)
                        FALSE,             // cStrikeOut,   删除线属性标志(FALSE:无删除线,TRUE:有删除线)
                        ANSI_CHARSET,       // nCharSet,        字符集标识0:ANSI字符集,1:系统缺省字符集
                        OUT_DEFAULT_PRECIS,  // nOutPrecision,   输出精度
                        CLIP_DEFAULT_PRECIS, // nClipPrecision,  剪切精度
                        DEFAULT_QUALITY,      // nQuality,        输出品质
                        DEFAULT_PITCH|FF_SWISS, // nPitchAndFamily, 字符间距
                        TEXT("Arial"));          // lpszFacename,    现有系统TrueType字体名称
            HFONT hOldFont = (HFONT)SelectObject(hDC, hFont);
            SetBkMode(hDC, TRANSPARENT);
            SetTextColor(hDC, RGB(0x00, 0xFF, 0xFF));
            TextOut(hDC, 0, 150, TEXT("创建Font"), 6);
            DeleteObject(hFont);
            EndPaint(hWnd, &ps);
        }
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0 ;
    }
    return DefWindowProc (hWnd, message, wParam, lParam);
}

case WM_LBUTTONDOWN:

ReleaseDC(dc);

 

    ......

HDCmemDC = CreateCompatibleDC(NULL);

程序运营,点击鼠标左键后效果如下:

case WM_LBUTTONDBLCLK:

HGDIOBJoldBitmap = SelectObject(memDC, bitmap);

图片 3

    ......

//此处可以调用SetClipRect()等函数来约束绘制范围

先后中的DrawText、ExtTextOut能设置文本输出的矩形范围,超过部分是看不见的,从运转结果大家也足以见到有两行呈现不全,正是由于设置的展现范围小的缘由。

case WM_NCMOUSEMOVE:

SendMessage(pWnd, WM_ERASEBKGND, (WPARAM)memDC,0); 

此外ExtTextOut函数还能安装字符的间距,运营结果的第三行正是这种投机安装间隔不平等的结果。

    ......

SendMessage(pWnd, WM_PAINT, (WPARAM)memDC,0);

本程序还用CreateFont函数创立了二个斜体、右上排列的文本串。通过上例,大家把常用的文件输出作为实例体现给大家,只要好赏心悦目待实例代码,在重新组合MSDN的求证,再增加本连串的首先篇的Windows编制程序基本框架,一定能够明白好Windows编制程序的焦点文件输出。

case WM_NCMOUSELEAVE:

//至此memDC上早就保存了父窗口的背景内容

 

    ...... 

//顾客能够调用BitBlt(...)等函数拷贝memDC的剧情到子窗口的某些区域,那样就实现了晶莹剔透效果;

关怀微信徒人平台:程序猿互动缔盟(coder_online),你能够第有时间获取原创技术作品,和(java/C/C /Android/Windows/Linux)技能大腕做朋友,在线调换编制程序经验,获取编制程序基础知识,解决编制程序难点。工程师互动结盟,开采职员本身的家。

}

SelectObject(memDC, oldBitmap);

图片 4

......

DeleteDC(memDC); 

转发请表明出处,感谢合作!

gOldListViewProc = (WNNPROC)::GetWindowLong(hListView, GWL_WNDPROC);

DeleteObject(bitmap);

::SetWindowLong(hListView, GWL_WNDPROC, LONG(&MyListViewProc));//安装窗口进度

上面的不二法门当然有限量,因为不是怀有的父窗口都得以承担这种万分的WM_PAINT音讯功效,可是MSDN中关系大超多控件都有那一个职能,我们要静心读它的文书档案内容。

 

 

音信管理

其三: 如若上面包车型客车法子都丰盛的话,就剩下最笨的办法了,用GDI函数涂刷子窗口的背景,但你事先将在精晓父窗口的背景颜色、背景位图等信息。比方拿父窗口的颜料来填充子窗口的背景,可以调用FillRect()等:

率先大家要阻止WM_NCLBUTTONDOWN 和 WM_NCLBUTTONDBLCLK那五个音讯,当您在滚动条上按下鼠标时,就立刻触发WM_NCLBUTTONDOWN,倘诺连接飞速按两下鼠标就还恐怕有WM_NCLBUTTONDBLCLK。注意双击时唯有三个WM_NCLBUTTONDOWN音讯,实际不是三个。第一遍按鼠标会并发二个WM_NCLBUTTONDBLCLK。实际上那四个消息大家完全能够等而视之,做同样的拍卖。系统在拍卖这些五个新闻时,都会在其内部管理中触发比超多别样新闻,个中有许多少个WM_HSCROLL、WM_CAPTURECHANGED、WM_NCMOUSELEAVE。大家重要是要拍卖WM_HSCROLL,因为它最有价值。在您放手鼠标后,系统一发布送并拍卖完最终三个WM_HSCROLL之后,这才从WM_NCLBUTTONDOWN或WM_NCLBUTTONDBLCLK中返回:

//-------------------父窗口的背景是颜色的情状

if(msg == WM_NCLBUTTONDOWN || msg == WM_NCLBUTTONDBLCLK)

COLOQashqaiREFpColor = ...;//父窗口的水彩

{

HDC cDC =...;//子窗口的画布句柄

    //注意私下认可管理会有N个WM_HSCROLL音信现身,要等您的按下拖拽操作完结后,那个调用才重返

RECTcRect = ...;//子窗口需刷新的区域 

    //在这里个调用内部,小编测度系统会跻身意气风发种新闻循环,因为按住左键之后,WM_NCMOUSEMOVE

HBRUSHbrush = CreateSolidBrush(pColor);

    //和WM_NCLBUTTONUP都不再触发了。当中间估摸是捕捉了WM_NCMOUSEMOVE新闻,因之反复刷新滚动

FillRect(cDC, &cRect,brush);

    //盒的职位,若有尤为重要你可设置鼠标钩子,以捕捉鼠标移动音讯,以当下刷新模拟窗口中滚动盒的

DeleteObject(brush);

    //的地点。若只是响应WM_HSCROLL新闻,你恐怕感觉滚动盒的拖拽相比滞,不平易。

 

   

//-------------------父窗口的背景是位图的事态

    //SetWindowsHookEx(...);

HBITMAPpBitmap = ...;父窗口的背景位图

    LRESUTL code = ::CallWindowProc(gOldListViewProc, hListView, msg, wParam, lParam);

HDC cDC =...;//子窗口的画布句柄

    //UnhookWindowsHookEx(...);

RECTcRect = ...;//子窗口需刷新的区域 

   

POINTrp;

    return code;

SetBurshOrgEx(cDC, x, y,&rp);要是是位图刷子,则还索要调度画布的刷子原点偏移确定保障无缝

}

HBRUSHbrush = CreatePatternBrush(pBitmap);

 

FillRect(cDC, &cRect,brush);

自己提出大家去微软的网址下载ControlSpy 2.0以此小工具,它用来监视控件的音信,那东西很有用。

DeleteObject(brush);

上边大家再看WM_HSCROLL消息,那一个音信日常是系统管理WM_NCLBUTTONDOWN或者WM_NCLBUTTONDBLCLK时发出的,但有的时候候也或者是程序特意发送的,和滚动条操作未有提到。

SetBurshOrgEx(cDC, rp.x, rp.y,NULL);还原画布的刷子偏移

if(msg == WM_HSCROLL)

 

 

    ::CallWindowProc(gOldListViewProc, hListView, msg, wParam, lParam);

报料换肤技能:定制控件背景颜色与背景位图

 

本文陈述怎么样定制控件的背景颜色和背景位图的才能。

第大器晚成要说一下控件的绘图进程:当控件的某部区域需求重绘时,都会触发WM_ERASEBKGND和WM_PAINT音讯。举例控件的某部区域被另三个程序的窗口挡住了,而后那多少个窗口又被移走了,这时候间调控件被遮挡的剧情就须要重新绘制了。

率先步:系统向控件发送WM_ERASEBKGND消息以得以实现背景的擦除职业(一时不发送,比方客商大概调用InvalidateRect(),其参数却钦点不擦除背景,这样就不曾这么些新闻);

其次步:系统向控件的窗口进程发送WM_PAINT音讯,控件试行拍卖这一个WM_PAINT音信时会有选取地触发前边四个步骤的动作;

其三步:对于有个别专门的工作控件,如Button、Edit、ListBox、 ScrollBar、Static控件,它还有可能会向父窗口发送WM_CTLCOLORxxx(WM_CTLCOLORBUTTON、 WM_CTLCOLOREDIT、WM_CTLCOLORSTATIC、WM_CTLCOLORLISTBOX、 WM_CTLCOLORAV4SCROLLBATucson等)的音讯,这一个新闻重返一个刷子句柄,系统拿那个刷子句柄进一步涂刷本身的背景。其余还开采Trackbar 也会向父窗口发送WM_CTLCOLOOdysseySTATIC音讯,TreeView在一些处境下也可以有,然则自个儿从不观望微软在什么样地点对这点作表达;小编一时发现很几人管理那个音信时,喜欢给系统重返二个NULL_BRUSH的空刷子,以为那样系统就不会把后面步骤画好的背景覆盖掉,其实不料定的,有个别控件不覆 盖,某些就有标题,像Trackbar正是这么,要小心。

第四步:对于菜单和广大正规控件,如Button、Edit、ListBox、 Static、ComboBox它可能会向父窗口发送WM_MEASUREITEM和WM_DRAWITEM音讯,其余通用控件Tab、 StatusBar、ListView、Header也只怕会有WM_DRAWITEM音讯;但对于绝大比超级多通用控件,如TreeView、 ListView、Rebar、Trackbar、Toolbar等,它会向父窗口发送多数其ID为NM_CUSTOMDRAW的WM_NOTIFY消息。对于那二种音讯,实际供给客户在早已涂刷好的背景之上再推行本身的绘图工作;

第五步:当控件的WM_DRAWITEM或者WM_NOTIFY新闻未有被顾客处理时,系统会亲自施行自个儿的私下认可绘制专门的职业,把控件画出来,这一步未有章程重载。

明亮了那些手续,大约大家心里早就知道,知道什么定制控件的背景颜色和背景位图了。平日景况下大家定制第一步、第三步完结团结的古怪背景,定制第四部实现控件自己的奇特绘制。以至大家得以整个重载控件第一步的WM_ERASEBKGND消息和第 二步的WM_PAINT音信,控件背景和控件绘制全部团结解决,没人说这么做老大。可是要静心,当自己达成WM_PAINT新闻的重载管理时,前边3个步 骤就都不发生了。

定制颜色倒是比较轻巧,依据控件的门类处理WM_ERASEBKGND、 WM_CTLCOLORxxx、WM_DRAWITEM、WM_NOTIFY信息了,平日情况下,定制WM_ERASEBKGND和 WM_CTLCOLOLacrossexxx就足以了;对于背景位图超级多控件却特别麻烦,像ListBox,你把背景位图涂刷好,结果因为用户操作滚动条或鼠标滚轮或按 方向键,背景位图也发出滚动,那就只可以重绘位图,对于背景颜色就不曾那么些难题,不管怎么滚动,颜色依然十一分颜色,位图就可怜,需求谐和重载产生滚动操作 的种种音讯以贯彻位图重绘。微软如同并不要是你会改良控件的背景位图,它未有对这些意况作希图,总是不加思索的对控件画布实施Scroll操作。真正兑现 背景位图的方法平日倒逼大家要阻拦那几个导致窗口内容产生滚动的各个操作,因而位图背景的职能实现也总让人以为多少标准、不那么可相信。

末段要评释的是:若是父控件还满含背景透明的子控件,你应有重载父控件的WM_ERASEBKGND音信,否则那多少个透明背景的子控件恐怕就未有准确的背景内容。

上面那些步骤是本人个人的知晓,不分明对哦!仅供参考。

 

    //1)读取滚动条的数据

爆料换肤技艺:实现系统滚动条换肤功效

对此Windows系统中各样控件换肤作用,要数滚动条的换肤最难完结了,尤其是控件自带的系统滚动条,如Edit、List博克斯、ListView、TreeView等自带的类别滚动条,要想达成其自定义的身体发肤作用,用健康方法如同都无计可施兑现。

对此正规的肌肤定制常常都以经过定制WM_PAINT、WM_ERASEBKGND、 WM_CTLCOLORxxx、NM_CUSTOMDRAW来落到实处。不过系统滚动条的绘图,常规的、很阳光的办法行不通,微软把一条平坦大路堵死了。根据笔者的观测测验,系统滚动条有众多的音讯都对其试行了绘图,那包罗WM_NCPAINT、WM_NCMOUSEMOVE、WM_NCMOUSELEAVE、 WM_HSCROLL、WM_VSCROLL、WM_KEYDOWN、WM_MOUSEWHEEL等等,那个音讯中有些能够定制,但有个别无可奈何定制。举个例子WM_HSCROLL就不能够定制,倘诺我们处理这些音信,就务须团结决定滚动条的限制、地方、翻页值,而这几个值大家通常不只怕赢得,微软历来未有告知大家, 对于分裂的控件它操控滚动条到底选择何种政策,不知底。假使大家不去定制这一个WM_HSCROLL,而默许的管理它又进行滚动条的绘图,那不失为进退无路, 叫人敬谢不敏。当然不是一心未有主意,死路一条。为了征服阻力,翻越障碍,每一个人有两样的宗旨,有攀岩翻越的,安全性不高;也是有走小路绕行的,相比为难。

在网络一再查找,自身也从长远的角度考虑,基本有三种情势来促成系统滚动条换肤,黄金时代种方法是HOOKAPI,也正是拦截API的不二诀要,还应该有风姿罗曼蒂克种是模拟法。

拦截API,实际上是改革操作系统的API入口。因为系统绘制滚动条是透过各个绘制函数来完成的,比方SetScrollInfo(),基本连串经过那生龙活虎类函数完结滚动条的绘图,对这些API进行阻拦,也便是大家和好写三个SetScrollInfo(),来亲自贯彻滚动条的绘图,以便因而实现滚动条的自定义绘制,完毕咱们想要的种种风格的肌肤外观。API的阻碍有两种:生龙活虎种是改善系统所装入内存可推行模块的导入地址,替换来大家所写的伪API的地址,使API调用能够自行跳转到这么些伪API上;还大概有风流倜傥种是直接校正API函 数首地址处的若干机器指令,保存现场,写入跳转指令,使系统在施行到这么些API时能自动跳转到我们所写的伪API上。作者要说的是,这一个拦截办法还真是有些邪门,有安全隐患,病毒就常干这种业务。对操作系统进行那类暴力破解式的退换,相当轻便引起系统防火墙或反病毒软件报错,Windows原则上不容许干这种 事;其二,生机勃勃旦选取此法的程序因不胜而咽气,原来对操作系统的改造未有苏醒,那或者会推延到系统里的装有进度的稳固,导致死机或运行十分。对于商业性的 工程开拓,往往很忧虑这点,都赞成于追求安定,常常是宁用拙法,不玩巧技;其三,此法有线程同步难题:因为正值你改改程序指令同期,若别的进程里的线程 恰好实行到此处时候难题就能够发生出来,单CPU恐怕没啥难题,系统内部存款和储蓄器和CPU缓冲能够成功一同,但多核系统就难说了;其余这么些点子还恐怕有移植性难题:在生龙活虎种版本的系统中,通过拦截API有效,在另大器晚成种版本的种类中,就不见得还管用,终归微软贯彻滚动条的绘图,它没分明一定就用哪些函数来完成,或然新系统中 它另有高招,API拦截也就不灵了。

上边作者要详细讲的是模拟法了,这些格局不用拦截API,全部的工夫实现都限制在系统所允许的范围内,咱一笔不苟的当鲁人持竿的热心人。

所谓模拟法正是在系统滚动条的区域放置一个效仿窗口,那么些窗口特地用来绘制系统滚动条。当然咱们也要拦截带滚动条控件的几何音信,以确认保证模拟窗口的绘图准确。上边只以ListView控件的品位滚动条为例,进行表明,垂直滚动条换肤能够列推。

图片 5

率先大家要在滚动条的区域上创建多个模拟窗口,恰好覆盖滚动条:

HWND hListView =...;//ListView窗口的句柄

HWND pWnd = ::GetParent(hListView);

HWND hBuddy =::CreateWindowEx(WS_EX_NOACTIVATE, "Buddy_Window", "",WS_CLIPSIBLINGS|WS_DISABLED|WS_CHILD, 0, 0, 0, 0, pWnd, NULL,gModule, NULL);

Buddy_Window是你注册的模仿窗口类。注意,窗口必定要有WS_DISABLED 风格,那是个第意气风发,这些风格能够确认保障鼠标操作能够因而模拟窗口,而直接操控到所隐瞒的滚动条,模拟窗口本身不收受任何鼠标键盘的输入。其它读取滚动条的矩 形以至它的顺序要素的可视、可用、压下等景况可由此GetScrollBarInfo()那些API来成功,但是要证圣元(Synutra)些,那一个API有个别Bug,我们可去下载FreeCL2.03 版源码,里头修正了那一个题目。

成就创制模拟窗口之后,你要给ListView安装多少个你写的窗口进度,以阻滞各个导致滚动条属性更改的各种消息:

LRESULT CALLBACK MyListViewProc(HWNDhwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

case WM_LBUTTONDOWN:

    ......

case WM_LBUTTONDBLCLK:

    ......

case WM_NCMOUSEMOVE:

    ......

case WM_NCMOUSELEAVE:

   ...... 

}

......

gOldListViewProc =(WNNPROC)::GetWindowLong(hListView, GWL_WNDPROC);

::SetWindowLong(hListView, GWL_WNDPROC,LONG(&MyListViewProc));//安装窗口进度

 

音讯管理 :

第后生可畏大家要堵住WM_NCLBUTTONDOWN 和WM_NCLBUTTONDBLCLK那五个新闻,当您在滚动条上按下鼠标时,就立时触发WM_NCLBUTTONDOWN,如若三番五次快速按两下鼠标就 还恐怕有WM_NCLBUTTONDBLCLK。注意双击时独有三个WM_NCLBUTTONDOWN新闻,并非五个。第二遍按鼠标会产出一个WM_NCLBUTTONDBLCLK。实际上那八个新闻我们全然能够等而视之,做相同的管理。系统在管理这几个七个音讯时,都会在个中间管理中触发好些个其他新闻,此中有几多少个WM_HSCROLL、WM_CAPTURECHANGED、WM_NCMOUSELEAVE。大家器重是要管理WM_HSCROLL,因为它最有价值。在您甩手鼠标后,系统一发布送并管理完倒数WM_HSCROLL之后,这才从WM_NCLBUTTONDOWN或 WM_NCLBUTTONDBLCLK中返回:

if(msg == WM_NCLBUTTONDOWN || msg== WM_NCLBUTTONDBLCLK)

{

   //注意暗中认可管理会有N个WM_HSCROLL音信现身,要等你的按下拖拽操作实现后,这一个调用才回到

   //在这里个调用内部,我猜测系统会跻身意气风发种音讯循环,因为按住左键之后,WM_NCMOUSEMOVE

    //和WM_NCLBUTTONUP都不再触发了。其里面估摸是捕捉了WM_NCMOUSEMOVE新闻,因之一再刷新滚动

   //盒之处,若有尤为重要你可设置鼠标钩子,以捕捉鼠标移动新闻,以那个时候刷新模拟窗口中滚动盒的

   //的岗位。若只是响应WM_HSCROLL新闻,你也许以为滚动盒的拖拽相比较滞,不平坦。

 

   //SetWindowsHookEx(...);

    LRESUTL code= ::CallWindowProc(gOldListViewProc, hListView, msg, wParam,lParam);

    //UnhookWindowsHookEx(...);

 

    returncode;

}

 

自己提议我们去微软的网址下载ControlSpy2.0 本条小工具,它用来监视控件的音讯,那东西很有用。

下边我们再看WM_HSCROLL音信,这几个音信平日是系统管理WM_NCLBUTTONDOWN或者WM_NCLBUTTONDBLCLK时爆发的,但不时也只怕是前后相继特意发送的,和滚动条操作未有关系。

if(msg == WM_HSCROLL)

   ::CallWindowProc(gOldListViewProc, hListView, msg, wParam,lParam);

   //1)读取滚动条的数量

   //2)再在模拟窗口上绘制滚动条

    //......

    return0;

}

其余还或然有为数不菲任何的音信恐怕形成滚动条属性的变迁,如顾客的键盘操作、鼠标滚轮操作恐怕引致 滚动条的Thumb地方发生更换,那几个操作分别形成WM_KEYDOWN和WM_MOUSEWHEEL,而系统又在这里五个音信中推行滚动条的绘图,因而你 必得截获它们,但拍卖方法同WM_HSCROLL,这里不再啰嗦了。

当大家未有按下鼠标左键时,只是简短地在滚动条移动鼠标时,大家会发觉滚动条的开关和 Thumb都会活动高亮,其实那么些变迁都以系统在WM_NCMOUSEMOVE和WM_NCMOUSELEAVE中绘制达成的。比方当鼠标步入到 Thumb上时,它就高亮了,当鼠标离开它,它又变豆绿了,你要分别管理WM_NCMOUSEMOVE和WM_NCMOUSELEAVE那四个音讯。注意 唯有ListView应用大旨风格之后才只怕有WM_NCMOUSELEAVE音讯,守旧风格的ListView就不曾那几个消息,唯有WM_NCMOUSEMOVE新闻,因而管理高亮还真某个麻烦。正是因为核心风格和观念风格的差距,由此小编建议您也管理WM_THEMECHANGED音讯,以识别不一样的核心方式,完结差别高亮管理。看下面那些图,TreeView的滚动条是核心风格的,但ListView的滚动条是古板风格的,但自个儿加了 换肤作用。

除此以外,我们还应该拦截管理ListView的WM_NCPAINT,将滚动条的区域抠掉,不让它绘制滚动条。就算滚动条被模仿窗口遮住了,但要么有不可能缺少如此做,防止止现身意外情状:

if(msg == WM_NCPAINT)

{

    HRGN wRgn =NULL; 

    RECTsbRect = GetScrollBarRect();//读取滚动条矩形的二个函数

    HRGNsRgn = ::CreateRectRgn(sbRect.left, sbRect.top, sbRect.right,sbRect.bottom

    if(wParam ==1)

    {

       RECT wRect;

       ::GetWindowRect(hListView, &wRect);

       wRgn = ::CreateRectRgn(wRect.left, wRect.top, wRect.right,wRect.bottom););

       wRgn = ::CombineRgn(wRng, wRgn, sRgn, RGN_DIFF);

    }

    else

    {

        wRgn= (HRGN)wParam; 

       wRgn = ::CombineRgn(wRng, wRgn, sRgn, RGN_DIFF);

    }

    ::DeleteObject(sRgn);

   ::CallWindowProc(gOldListViewProc, hListView, WM_NCPAINT,WPARAM(wRgn), 0);

    if(wParam ==1)

       ::DeleteObject(wRgn);

    return0;

}

除此以外,还要拦截WM_WINDOWPOSCHANGING音信,因为当ListView的位置、尺寸、Z秩序发生改动时要立即调动模拟窗口的地点、尺寸、Z秩序。为什么要在WM_WINDOWPOSCHANGING中张开,而不接受在 WM_WINDOWPOSCHANGED或WM_MOVE或WM_SIZE中张开呢?因为在WM_WINDOWPOSCHANGING中拍卖,可让模拟窗 口先于ListView调节本人的职分、尺寸和Z,可制止有些制图问题。实际笔者在FreeCL中既用了WM_WINDOWPOSCHANGING,也用到 WM_WINDOWPOSCHANGED七个音讯。在拍卖WM_WINDOWPOSCHANGING时调解岗位、尺寸、Z秩序,在处理WM_WINDOWPOSCHANGED时,强制重绘模拟窗口。

聊起底还要证美素佳儿(Friso)些的是,系统或然因为客商更换控件尺寸导致其滚动条自动消失或自发性呈现,或者调节滚动条的可用状态,如您拉宽支持多行显示的Edit控件,会促成滚动条箭头开关变灰,Thumb消失。那么些动作平日都以在 WM_WINDOWPOSCHANGED中成功的,因而那一个消息也需求拦截管理:

if(msg == WM_WINDOWPOSCHANGED)

{

    LRESULTlReturn = ::CallWindowProc(gOldListViewProc, hListView,WM_WINDOWPOSCHANGED,

       wParam, lParam);

   if(::GetNextWindow(hBuddy, GW_HWNDNEXT ) !=hListView)

   {  //调治模拟窗口的Z-Order,确认保证其紧贴ListView之上

       HWND hAbove = ::GetNextWindow(hListView, GW_HWNDPREV);

       UINT flag =SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOSENDCHANGING;
           ::SetWindowPos(hBuddy, hAbove?hAbove:HWND_TOP, 0, 0, 0, 0,flag);

    }

    //测量检验滚动条的显隐状态是或不是改动,并因之调治模拟窗口的显隐状态

   //尽管滚动条还是显得或滚动条有些因素的来得状态有浮动或控件地方、尺寸或者修正,

   //强制重绘模拟窗口

    //......

    returnlReturn;

}

最终要管理WM_SHOWWINDOW和WM_DESTROY,当ListView遮掩时让模拟窗口也随后灭亡;当它显得时,让模拟窗口也跟着显示。当ListView销毁时会触发WM_DESTROY,这个时候也要求销毁模拟窗口,这很要紧。 

总的来说,模拟法是蛮麻烦的,但比较安全,可信性高。对开荒者来说,都以对新闻进行一定管理,是常规花招,对最终顾客来说,用此法完结的滚动条自绘,完全能够满足供给,具有足够的自由度,以至足以对滚动条增加越来越多特定的功用,比如能够在下面增加其余按键,即便是加动画、加广告也都是能够的。

    //2)再在模仿窗口上绘制滚动条

    //......

    return 0;

}

别的还应该有许多其余的消息或者引致滚动条属性的生成,如顾客的键盘操作、鼠标滚轮操作也许导致滚动条的Thumb地方产生转移,那些操作分别形成WM_KEYDOWN和WM_MOUSEWHEEL,而系统又在此多少个新闻中奉行滚动条的绘图,由此你必须要截获它们,但拍卖措施同WM_HSCROLL,这里不再啰嗦了。

当大家从没按下鼠标左键时,只是简短地在滚动条移动鼠标时,我们会发觉滚动条的按键和Thumb都会自动高亮,其实这么些变迁都以系统在WM_NCMOUSEMOVE和WM_NCMOUSELEAVE中绘制落成的。譬如当鼠标步入到Thumb上时,它就高亮了,当鼠标离开它,它又变羊毛白了,你要分别管理WM_NCMOUSEMOVE和WM_NCMOUSELEAVE那五个音信。注意唯有ListView应用大旨风格之后才可能有WM_NCMOUSELEAVE音信,古板风格的ListView就从未这么些新闻,唯有WM_NCMOUSEMOVE新闻,由此管理高亮还真有一些麻烦。就是因为焦点风格和历史观风格的差别,因而小编提议你也管理WM_THEMECHANGED信息,以识别差异的宗旨形式,达成不一样高亮管理。看下边那几个图,TreeView的滚动条是核心风格的,但ListView的滚动条是古板风格的,但小编加了换肤作用。

此外,大家还应有拦截管理ListView的WM_NCPAINT,将滚动条的区域抠掉,不让它绘制滚动条。纵然滚动条被模仿窗口遮住了,但要么有无法缺乏那样做,以免止现身意外情况:

if(msg == WM_NCPAINT)

{

    HRGN wRgn = NULL; 

    RECT sbRect = GetScrollBarRect();//读取滚动条矩形的二个函数

    HRGN sRgn = ::CreateRectRgn(sbRect.left, sbRect.top, sbRect.right, sbRect.bottom

    if(wParam == 1)

    {

        RECT wRect;

        ::GetWindowRect(hListView, &wRect);

        wRgn = ::CreateRectRgn(wRect.left, wRect.top, wRect.right, wRect.bottom););

        wRgn = ::CombineRgn(wRng, wRgn, sRgn, RGN_DIFF);

    }

    else

    {

        wRgn = (HRGN)wParam; 

        wRgn = ::CombineRgn(wRng, wRgn, sRgn, RGN_DIFF);

    }

    ::DeleteObject(sRgn);

    ::CallWindowProc(gOldListViewProc, hListView, WM_NCPAINT, WPARAM(wRgn), 0);

    if(wParam == 1)

        ::DeleteObject(wRgn);

    return 0;

}

其它,还要拦截WM_WINDOWPOSCHANGING音讯,因为当ListView的任务、尺寸、Z秩序爆发转移时要立马调动模拟窗口的职位、尺寸、Z秩序。为什么要在WM_WINDOWPOSCHANGING中进行,而不选拔在WM_WINDOWPOSCHANGED或WM_MOVE或WM_SIZE中张开呢?因为在WM_WINDOWPOSCHANGING中拍卖,可让模拟窗口先于ListView调治和谐的任务、尺寸和Z,可幸免有个别绘制难点。实际笔者在FreeCL中既用了WM_WINDOWPOSCHANGING,也用到WM_WINDOWPOSCHANGED多个音讯。在管理WM_WINDOWPOSCHANGING时调度职分、尺寸、Z秩序,在拍卖WM_WINDOWPOSCHANGED时,强制重绘模拟窗口。

末段还要表明有个别的是,系统恐怕因为客商改造控件尺寸导致其滚动条自动消失或机关显示,或然调解滚动条的可用状态,如您拉宽扶助多行显示的Edit控件,会促成滚动条箭头按键变灰,Thumb消失。那么些动作经常都以在WM_WINDOWPOSCHANGED中完毕的,因而这一个新闻也亟需拦截管理:

if(msg == WM_WINDOWPOSCHANGED)

{

    LRESULT lReturn = ::CallWindowProc(gOldListViewProc, hListView, WM_WINDOWPOSCHANGED,

        wParam, lParam);

    if(::GetNextWindow(hBuddy, GW_HWNDNEXT) != hListView)

    {   //调节模拟窗口的Z-Order,确认保证其紧贴ListView之上

        HWND hAbove = ::GetNextWindow(hListView, GW_HWNDPREV);

        UINT flag = SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOSENDCHANGING;
            ::SetWindowPos(hBuddy, hAbove?hAbove:HWND_TOP, 0, 0, 0, 0, flag);

    }

    //测量试验滚动条的显隐状态是还是不是改动,并因之调度模拟窗口的显隐状态

    //借使滚动条依旧显得或滚动条某个因素的来得状态有转变或控件地点、尺寸可能改良,

    //强制重绘模拟窗口

    //......

    return lReturn;

}

终极要拍卖WM_SHOWWINDOW和WM_DESTROY,当ListView隐敝时让模拟窗口也随之灭绝;当它显得时,让模拟窗口也随时呈现。当ListView销毁时会触发WM_DESTROY,那个时候也亟需销毁模拟窗口,那很关键。 

总的来说,模拟法是蛮麻烦的,但比较安全,可相信性高。对开采者来说,都以对信息进行一定管理,是健康手腕,对最后客户来讲,用此法完成的滚动条自绘,完全能够满足要求,具备丰盛的自由度,乃至能够对滚动条增加更加多特定的成效,比方能够在上头增多别的按键,就算是加动画、加广告也都以能够的。

 

 

2  定制控件的背景颜色和背景位图的技术。

 

首先要说一下控件的绘图进程:当控件的某部区域须要重绘时,都会触发WM_ERASEBKGND和WM_PAINT信息。譬喻控件的某些区域被另一个前后相继的窗口挡住了,而后那些窗口又被移走了,那时候间调整件被遮挡的内容就须求再度绘制了。

先是步:系统向控件发送WM_ERASEBKGND消息以促成背景的擦除职业(不经常不发送,譬喻用户或许调用InvalidateRect(),其参数却钦点不擦除背景,那样就从未有过这些音信);

其次步:系统向控件的窗口进度发送WM_PAINT音讯,控件试行拍卖那一个WM_PAINT新闻时会有接受地触发后面多个步骤的动作;

其三步:对于有个别职业控件,如Button、艾德it、ListBox、ScrollBar、Static控件,它还会向父窗口发送WM_CTLCOLORxxx(WM_CTLCOLORBUTTON、WM_CTLCOLOREDIT、WM_CTLCOLORSTATIC、WM_CTLCOLORLISTBOX、WM_CTLCOLO帕杰罗SCROLLBA哈弗等)的音信,这一个新闻重回二个刷子句柄,系统拿那几个刷子句柄进一步涂刷本身的背景。其它还发掘Trackbar也会向父窗口发送WM_CTLCOLOLX570STATIC音讯,TreeView在少数意况下也可能有,不过作者并未看见微软在怎么地方对那一点作注明;笔者平日开采众几个人管理那么些音信时,喜欢给系统重临三个NULL_BRUSH的空刷子,感到这么系统就不会把前边步骤画好的背景覆盖掉,其实不自然的,有个别控件不隐讳,有个别就不寻常,像Trackbar正是那样,要小心。

第四步:对于菜单和重重正经控件,如Button、Edit、ListBox、Static、ComboBox它只怕会向父窗口发送WM_MEASUREITEM和WM_DRAWITEM音信,其余通用控件Tab、StatusBar、ListView、Header也可能会有WM_DRAWITEM信息;但对于大多数通用控件,如TreeView、ListView、Rebar、Trackbar、Toolbar等,它会向父窗口发送多数其ID为NM_CUSTOMDRAW的WM_NOTIFY新闻。对于那三种消息,实际供给客商在早已涂刷好的背景之上再试行自身的绘图职业;

第五步:当控件的WM_DRAWITEM或者WM_NOTIFY音信未有被客商管理时,系统会亲自实践本身的暗中认可绘制专业,把控件画出来,这一步未有主意重载。

知晓了这个步骤,大概我们心神早就知晓,知道哪些定制控件的背景颜色和背景位图了。经常情形下大家定制第一步、第三步完成和煦的新鲜背景,定制第四部达成控件本人的新鲜绘制。以至我们得以全方位重载控件第一步的WM_ERASEBKGND音讯和第二步的WM_PAINT新闻,控件背景和控件绘制全体谈得来解决,没人说这么做老大。但是要留意,当本身落成WM_PAINT新闻的重载管理时,前面3个步骤就都不发生了。

定制颜色倒是很简短,依据控件的档案的次序管理WM_ERASEBKGND、WM_CTLCOLORxxx、WM_DRAWITEM、WM_NOTIFY音信了,经常情形下,定制WM_ERASEBKGND和WM_CTLCOLO途乐xxx就能够了;对于背景位图相当多控件却特地费劲,像ListBox,你把背景位图涂刷好,结果因为顾客操作滚动条或鼠标滚轮或按方向键,背景位图也发生滚动,这就只好重绘位图,对于背景颜色就平素不那个难题,不管怎么滚动,颜色依旧特别颜色,位图就特别,须要和睦重载发生滚动操作的各个信息以得以达成位图重绘。微软就如并不即便你会改过控件的背景位图,它并未有对这些状态作图谋,总是不暇思索的对控件画布试行Scroll操作。真正兑现背景位图的艺术日常倒逼大家要阻拦这么些导致窗口内容产生滚动的各个操作,由此位图背景的功力完结也总令人以为多少标准、不那么可靠。

最终要注脚的是:如果父控件还蕴藏背景透明的子控件,你应有重载父控件的WM_ERASEBKGND音信,不然那三个透明背景的子控件可能就从未有过精确的背景内容。

上边那几个步骤是自己个人的知道,不必然对啊!仅供参照他事他说加以考察。

 

3 实现控件的晶莹背景

  

超级多动静下,我们需求控件的背景是晶莹的,正是要求直接见到控件父窗口的背景颜色、背景位图,举个例子标签控件、单选Radio控件、复选Check控件,平时都供给在父窗口的背景上开展绘图。不过供给控件的画布透明,那一个工夫在GDI的文书档案中未有见到Microsoft作其余表明,当然依旧有别的格局。

 

那些:假设程序辅助桌面大旨服务以来,则可调用宗旨服务的API来贯彻背景。大家先看看那个API:

HRESULT DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc);

本条函数便是特地用来绘制父窗口的背景的,个中的hwnd参数是子窗口的句柄,hdc也时子窗口的画布句柄,prc是子窗口需绘制的区域,这么些函数实际是把父窗口的背景拷贝到子窗口上来,以这种措施达到透明。

 

其二:尽管程序不扶植桌面主旨服务,则不能够选用方面包车型地铁主意,举个例子程序运营在Windows 二〇〇四上。当时大家能够向父窗口发送WM_PAINT音信,然则此消息所附带的wParam参数是一个画布句柄:

HDC dc = GetDC(NULL);

HWND cWnd = ...;//子窗口句柄

HWND pWnd = ...;//父窗口句柄

RECT cRect;

GetClientRect(cWnd, &cRect);

HBITMAP bitmap = CreateCompatibleBitmap(dc, cRect.right, cRect.bottom);

ReleaseDC(dc);

HDC memDC = CreateCompatibleDC(NULL);

HGDIOBJ oldBitmap = SelectObject(memDC, bitmap);

//此处能够调用SetClipRect()等函数来节制绘制范围

SendMessage(pWnd, WM_ERASEBKGND, (WPARAM)memDC, 0); 

SendMessage(pWnd, WM_PAINT, (WPARAM)memDC, 0);

//至此memDC樱笋时经保存了父窗口的背景内容

//客户可以调用BitBlt(...)等函数拷贝memDC的内容到子窗口的有个别区域,那样就完毕了晶莹剔透效果;

SelectObject(memDC, oldBitmap);

DeleteDC(memDC); 

DeleteObject(bitmap);

下边包车型的士艺术当然有限制,因为不是装有的父窗口都得以选用这种奇特的WM_PAINT消息成效,可是MSDN中涉嫌大多数控件都有那几个作用,大家要在乎读它的文书档案内容。

 

其三:假使地方的不二等秘书技都万分的话,就剩下最笨的方式了,用GDI函数涂刷子窗口的背景,但您事先将在领悟父窗口的背景颜色、背景位图等音信。比方拿父窗口的颜色来填充子窗口的背景,能够调用FillRect()等:

//-------------------父窗口的背景是颜色的情状

COLO逍客REF pColor = ...;//父窗口的水彩

HDC cDC = ...;//子窗口的画布句柄

RECT cRect = ...;//子窗口需刷新的区域 

HBRUSH brush = CreateSolidBrush(pColor);

FillRect(cDC, &cRect, brush);

DeleteObject(brush);

 

//-------------------父窗口的背景是位图的气象

HBITMAP pBitmap = ...;父窗口的背景位图

HDC cDC = ...;//子窗口的画布句柄

RECT cRect = ...;//子窗口需刷新的区域 

POINT rp;

SetBurshOrgEx(cDC, x, y, &rp);假诺是位图刷子,则还索要调治画布的刷子原点偏移确认保证无缝

HBRUSH brush = CreatePatternBrush(pBitmap);

FillRect(cDC, &cRect, brush);

DeleteObject(brush);

SetBurshOrgEx(cDC, rp.x, rp.y, NULL);还原画布的刷子偏移

本文由奥门新萄京8522发布于成人娱乐,转载请注明出处:如何用易语言自绘gdi,实现系统滚动条换肤功能

关键词: