来由: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的自绘内容就可以存下来,反之、怎样枚举出自绘控件的句柄等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)