自绘按钮利用drawitemstruct怎么判断各个状态,如正常、鼠标放上点燃、按下、鼠标离开等等,

自绘按钮利用drawitemstruct怎么判断各个状态,如正常、鼠标放上点燃、按下、鼠标离开等等,,第1张

来由:DRAWITEMSTRUCT 为需要自绘的控件或者菜单项提供了必要的信息。在需要绘制的控件或者菜单项对应的WM_DRAWITEM消息函数中得到一个指向该结构的指针。 例子: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); (h中声明) void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) (cpp中定义) 这里LPDRAWITEMSTRUCT即指向DRAWITEMSTRUCT结构体的指针。 DRAWITEMSTRUCT结构的定义如下: typedef struct tagDRAWITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; ULONG_PTR itemData; } DRAWITEMSTRUCT, NEAR PDRAWITEMSTRUCT, FAR LPDRAWITEMSTRUCT;结构成员: 成员: CtlType 指定了控件的类型,其取值如下表所示。 ODT_BUTTON:按钮控件 ODT_COMBOBOX:组合框控件 ODT_LISTBOX:列表框控件 ODT_LISTVIEW:列表视图控件 ODT_MENU:菜单项 ODT_STATIC:静态文本控件 ODT_TAB:Tab控件 CtlID 指定了自绘控件的ID值,而对于菜单项则不需要使用该成员 itemID 表示菜单项ID,也可以表示列表框或者组合框中某项的索引值。对于一个空的列表框或组合框,该成员的值为–1。这时应用程序只绘制焦点矩形(该矩形的坐标由rcItem 成员给出)虽然此时控件中没有需要显示的项,但是绘制焦点矩形还是很有必要的,因为这样做能够提示用户该控件是否具有输入焦点。当然也可以设置itemAction 成员为合适值,使得无需绘制焦点。 itemAction 指定绘制行为,其取值可以为下表中所示值的一个或者多个的联合。 ODA_DRAWENTIRE:当整个控件都需要被绘制时,设置该值 ODA_FOCUS:如果控件需要在获得或失去焦点时被绘制,则设置该值。此时应该检查itemState成员,以确定控件是否具有输入焦点。 ODA_SELECT 如果控件需要在选中状态改变时被绘制,则设置该值。此时应该检查itemState 成员,以确定控件是否处于选中状态。 itemState 指定了当前绘制 *** 作完成后,所绘项的可见状态。例如,如果菜单项应该被灰色显示,则可以指定ODS_GRAYED状态标志。其取值可以为下表中所示值的一个或者多个的联合。 ODS_CHECKED:如果菜单项将被选中,则可设置该值。该值只对菜单项有用。 ODS_COMBOBOXEDIT:在自绘组合框控件中只绘制选择区域。 ODS_DEFAULT:默认值。 ODS_DISABLED:如果控件将被禁止,则设置该值。 ODS_FOCUS:如果控件需要输入焦点,则设置该值。 ODS_GRAYED:如果控件需要被灰色显示,则设置该值。该值只在绘制菜单时使用。 ODS_HOTLIGHT:Windows 98/Me, Windows 2000/XP: 如果鼠标指针位于控件之上,则设置该值,这时控件会显示高亮颜色。 ODS_INACTIVE:Windows 98/Me, Windows 2000/XP: 表示没有激活的菜单项。 ODS_NOACCEL:Windows 2000/XP: 控件是否有快速键盘。 ODS_NOFOCUSRECT:Windows 2000/XP: 不绘制捕获焦点的效果。 ODS_SELECTED:选中的菜单项。 hwndItem 指定了组合框、列表框和按钮等自绘控件的窗口句柄;如果自绘的对象时菜单项,则表示包含该菜单项的菜单句柄。 hDC 指定了绘制 *** 作所使用的设备环境。 rcItem 指定了将被绘制的矩形区域。这个矩形区域就是上面hDC的作用范围。系统会自动裁剪组合框、列表框或按钮等控件的自绘制区域以外的部分。也就是说rcItem中的坐标点(0,0)指的就是控件的左上角。但是系统不裁剪菜单项,所以在绘制菜单项的时候,必须先通过一定的换算得到该菜单项的位置,以保证绘制 *** 作在我们希望的区域中进行。 itemData 对于菜单项,该成员的取值可以是由 CMenu::AppendMenu、 CMenu::InsertMenu或者 CMenu::ModifyMenu 等函数传递给菜单的值。 对于列表框或这组合框,该成员的值可以为由 ComboBox::AddString、 CComboBox::InsertString、 CListBox::AddString或者 CListBox::InsertString 等传递给控件的值。 如果ctlType 的取值是ODT_BUTTON或者ODT_STATIC, itemData的取值为0。

CopyFromScreen明显是类似屏幕截图的意思,你上面的代码pictureBox1的角色只用来定义大小,和内容没用半毛钱关系(你可以试试即便没用panel,保存之前用别的窗口遮住一部分,看是什么效果)。

私信帮改

QQ2009自绘的按钮 意思就是说他的窗口处理函数是主窗口处理函数 自己是没有的

简单点说就是 你自己做个windows程序 上面画个方框代表按钮 然后通过主窗口捕捉鼠标消息或者Hotkey来决定是否该按钮

被点击,在执行重绘、发送任务

你要捕捉的话也就是捕捉上面两个消息就够了,只不过鼠标点击消息要自己转换到聊天窗口里面确定是不后在QQ画的按钮上点击了

=============================================================================

简单说哦,QQ发送不是控件,你搜不到,狠不?

下面这个可以作为参考,具体还要自己实践:

一、准备工作

在开始编码之前,首先应该确定好,更准确的说应该是设计好按钮在各种状态下的外观。按钮控件的几中基本状态包括:

Normal状态,就是按钮一开始显示时的样子。

Over状态,鼠标指针移动到按钮上面时按钮显示的样子。

Down状态,按下按钮时显示的样子。

Focus状态,按钮按下后松开的样子,例如标准按钮按下松开之后会看到按钮内部有一个虚线框。

Disable状态,当然就是按钮被设置成无效的时候的样子啦。

我参考了一下WindowsXP中普通按钮的实际样子,设计出XP按钮各种状态的外观,如下图所示:

至于Down状态主要是在Over状态的基础上将文字往右下的方向稍微平移,以实现下压的效果。

二、实现原理及难点

下面我们开始类的创建,在Workspace的ClassView页中右击列表树的根结点,选择New Class…

在d出窗口中进行派生类的定义,如下图所示,注意,你需要填写的只有Name和Base class两项,其余的选项保持默认值就可以了。

下面简要叙述一下按钮的实现原理:

1 在控件初始化时为按钮添加Owner

Draw的属性。这是因为在MFC中,要想激活控件的自绘功能,要求该控件的属性中必须包含属性值BS_OWNERDRAW,这一步我们可以通过类向导为

CXPButton类添加PreSubclassWindow()函数,在该函数中完成属性值的设置。当激活控件的自绘功能之后,每次控件状态改变的时候

都会运行函数DrawItem(),该函数的作用就是绘制控件在各种状态下的外观。

2 添加WM_MOUSELEAVE消息函数,当鼠标指针离开按钮时,触发该消息函数,我们在函数中添加代码,通知DrawItem函数鼠标指针已经离开了,让按钮重绘。

3 添加WM_MOUSEHOVER消息函数,当鼠标指针位于按钮之上时,触发该消息函数,我们在函数重添加代码,通知DrawItem函数鼠标指针现在正在按钮的上面,让按钮重绘。

4 添加DrawItem函数。在DrawItem中根据按钮当前的状态绘制按钮的外观。可以说自绘控件的大部分功能都是在这个函数中实现的。DrawItem函数包含了一个LPDRAWITEMSTRUCT的指针,本篇会在稍后予以讲解。

这里有两个难点,首先是WM_MOUSELEAVE和

WM_MOUSEHOVER不是标准的Windows消息函数,它们不能通过类向导来添加,所有的添加工作都需要通过手工输入代码来完成。另一个难点是

DrawItem中的LPDRAWITEMSTRUCT指针,它指向了一个DRAWITEMSTRUCT的结构,这个结构中包含了控件的各种细节,为我们

提供了实现自绘功能的必要信息。

难点一:

事实上WM_MOUSELEAVE和WM_MOUSEHOVER两个Windows消息是通过WM_MOUSEMOVE消息触发

的,而 WM_MOUSEMOVE是标准的Windows消息,因此我们可以通过类向导来为CXPButton类添加WM_MOUSEMOVE消息函数。

函数的代码见如下,这段代码非常有用,在其它的自绘控件中,如果想触发WM_MOUSELEAVE和WM_MOUSEHOVER消息,也是使用类似的方法实现的。

void CXPButton::OnMouseMove(UINT nFlags, CPoint point)

{

// TODO: Add your message handler code here and/or call default

if (!m_bTracking)

{

TRACKMOUSEEVENT tme;

tmecbSize = sizeof(tme);

tmehwndTrack = m_hWnd;

tmedwFlags = TME_LEAVE | TME_HOVER;

tmedwHoverTime = 1;

m_bTracking = _TrackMouseEvent(&tme);

}

CButton::OnMouseMove(nFlags, point);

}

我们接着添加WM_MOUSELEAVE和WM_MOUSEHOVER消息消息函数。在CXPButton类的声明中(即在

XPButtonh文件中)找到afx_msg void OnMouseMove(UINT nFlags, CPoint

point);的函数声明,紧接其下输入

afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);

afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam);

然后在XPButtoncpp文件中找到ON_WM_MOUSEMOVE(),紧接其后输入

ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)

ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)

难点二:

下面我们看看DRAWITEMSTRUCE结构为我们提供了哪些有用信息呢?

DRAWITEMSTRUCT结构的定义如下:

typedef struct tagDRAWITEMSTRUCT {

UINT CtlType; //控件类型

UINT CtlID; //控件ID

UINT itemID; //菜单项、列表框或组合框中某一项的索引值

UINT itemAction; //控件行为

UINT itemState; //控件状态

HWND hwndItem; //父窗口句柄或菜单句柄

HDC hDC; //控件对应的绘图设备句柄

RECT rcItem; //控件所占据的矩形区域

DWORD itemData; //列表框或组合框中某一项的值

}

DRAWITEMSTRUCT, PDRAWITEMSTRUCT,

LPDRAWITEMSTRUCT;其实不仅是按钮控件,其它控件,如ComboBox、ListBox、StaticText等都是通过

DRAWITEMSTRUCT来记录控件信息的。关于这个结构的详细文档可参考本篇的附录。

也许你早已看到许多自绘按钮的例子,实际上自绘按钮本身的函数结构都是差不多的,它们显示效果的区别主要取决于代码编写者对GDI作图函数的运用与

掌握程度。有兴趣的朋友可以研究一下CXPButton类中DrawItem函数的数据结构,其实只要修改一下其中GDI绘图函数的部分代码,马上又能做

出另一个自绘按钮控件了。

三、按钮类的使用

下面演示CXPButton类的使用。往对话框中添加一个按钮控件,假设它的ID值为IDC_BUTTON1。进入类向导(Class

Wizard)的Member

Variables属性页,为IDC_BUTTON1添加一个变量m_btnNormal。确定退出后再进行编译,就可以看到重新定义过XP风格按钮了。

如果你是之间把CXPButton的源文件引入自己的工程中的,那么在上图的Variable type中是看不到CXPButton选项的。但是可以通过以下方法加入:

1 首先保存工程后退出。

2 在工程的目录下找到一个后缀名为clw的文件,将其删除。但是为了以防万一还是建议你实现备份一下。

3 重新打开工程,进入类向导,此时会看到一下一个d出对话框,我们选择“是(Yes)”。

4 再选择“Add All”,这样我们就可以在类向导中使用CXPButton的变量类型了。

四、小结与提示

对于按钮来说,当按钮上面任何可见的部分发生变换的时候,都要调用DrawItem函数进行重绘。自绘制按钮必须设定BS_OWNERDRAW的属

性,设置的代码在PreSubclassWindows函数中完成。另外为了防止系统字体设置的变化影响控件的表达效果,还可以在该函数中为控件指定某种

固定的字体。但是要注意的是这个

让我们来回顾一下实现自绘按钮的基本步骤:

a 确定设计方案;

b 初始化,但是记得要在函数退出前恢复先前的GDI对象,并释放所占领的资源;

c 添加相应消息函数;

d 添加绘图函数DrawItem,在DrawItem中作图的顺序一般是先画外边框,再上底色,接着写文字,最后是画内边框。不过有些人也喜欢把边框放到最后画,这问题不大。

TlistView 控件是vcl 对windows公用控件库的一个封装 用户TlistView控件并未提供自绘表头的事件 一般情况下 要想自绘表头比较困难 但是windows 所有控件的绘制都是由于消息WM_PAINT的产生 而由窗口过程来绘制的 这样我们似乎就有可能通过WM_PAINT消息能够绘制TlistView表头 经过分析发现TlistView 的组成实际上包括了两部分 一部分是TlistView本省 另外一部分就是TlistView的表头 该表头实际上是一个嵌入TlistView里面的独立的窗口 该窗口的类名为 SysHeader (可以使用ccrun写的窗口探测工具spy win观察的到) 综合上述依据 实现TlistView表头的自绘可以分为一下几个步骤:

查找TlistView的表头窗口句柄

替换表头窗口的窗口过程

表头的WM_PAINT消息

在窗口过程中编写绘制代码

这样就能绘制TlistView 的表头了 具体实现方式如下 :

查找表头有三种方式

一 使用FindWindowEx :

以类名 SysHeader 来查找TlistView的子窗口 由于TlistView只有一个名为 SysHeader 的子窗口(就是表头) 所以一定能够获取到表头窗口的句柄

二 使用windows提供的帮助宏ListView_GetHeader

这种方式实际上是通过发送消息来获取表头句柄 返回值即表头句柄

替换表头的窗口过程

使用SetWindowLong这个API 就可以替换掉一个窗口的窗口过程 (详细步骤请参看MSDN)

请参看示例代码

请参看示例代码

具体代码

h文件    //

#ifndef Unit H    #define Unit H    //     #include    #include    #include    #include    #include

//     class TForm : public TForm    {    __published: // IDE managed Components        TListView ListView ;

private: // User declarations    public: // User declarations        __fastcall TForm (TComponent Owner);        __fastcall~TForm ();    };

//     extern PACKAGE TForm Form ;    //     #endif

cpp文件    //

#include    #pragma hdrstop

#include Unit h     //     #pragma package( art_init)    #pragma resource dfm     TForm Form ;    typedef LRESULT(CALLBACK TCallBack)(HWND UINT WPARAM LPARAM);

TCallBack g_oldListViewWndProc;    HWND g_hListViewHeader;

LRESULT CALLBACK ListViewWindowProc(HWND hwnd UINT uMsg WPARAM wParam         LPARAM lParam)    {        PAINTSTRUCT ps ={ };        RECT rect = { };        HDC hPen = NULL;        HDC hBrush = NULL;        int iCount = ;        int i = ;        BYTE red = green = blue = ;        BYTE red = green = blue = ;        BYTE red green blue;        int j m n;

switch(uMsg)        {        case WM_PAINT:            BeginPaint(g_hListViewHeader             hPen = SelectObject(ps hdc GetStockObject(DC_PEN));            iCount = Header_GetItemCount(g_hListViewHeader); // 获取表头数目    // 本文转自 C++Builder研究 i=             SetDCPenColor(ps hdc ColorToRGB((TColor)( x EFDBCE)));            red = GetRValue((TColor)( x EFDBCE));            green = GetGValue((TColor)( x EFDBCE));            blue = GetBValue((TColor)( x EFDBCE));            for (int i = ; i Font >Handle);                i = ((rect bottom rect top) abs(Form >Font >Height)) / ;                hBrush = SelectObject(ps hdc GetStockObject(NULL_BRUSH));                SetBkMode(ps hdc TRANSPARENT); // 这是设置背景为透明的                TextOut(ps hdc rect left + rect top + i                     Form >ListView >Columns >Items[i] >Caption c_str()                     Form >ListView >Columns >Items[i] >Caption Length());                SelectObject(ps hdc hBrush);            }            hPen = SelectObject(ps hdc hPen);            EndPaint(g_hListViewHeader             break;        default:            return CallWindowProc((FARPROC)g_oldListViewWndProc g_hListViewHeader                 uMsg wParam lParam);        }

return ;    }

//     __fastcall TForm ::TForm (TComponent Owner) : TForm(Owner)    {        g_hListViewHeader = FindWindowEx(ListView >Handle NULL SysHeader             NULL);        g_oldListViewWndProc = (TCallBack)GetWindowLong            (g_hListViewHeader GWL_WNDPROC);        SetWindowLong(g_hListViewHeader GWL_WNDPROC long(ListViewWindowProc));    }

lishixinzhi/Article/program/c/201311/11101

以上就是关于自绘按钮利用drawitemstruct怎么判断各个状态,如正常、鼠标放上点燃、按下、鼠标离开等等,全部的内容,包括:自绘按钮利用drawitemstruct怎么判断各个状态,如正常、鼠标放上点燃、按下、鼠标离开等等,、WINFORM中获取PICTUREBOX图像问题,如果不使用PANEL,PICTURBOX的自绘内容就可以存下来,反之、怎样枚举出自绘控件的句柄等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9664328.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-30
下一篇 2023-04-30

发表评论

登录后才能评论

评论列表(0条)

保存