HyperButtonEx:一个全功能的按钮类

介绍 这个类介绍了HyperButtonEx,一个集所有功能于一身的按钮类。它支持位图透明度,自定义字体,圆角矩形,和更多!超链接和外壳功能已经内置到类中。 使用的代码 默认按钮样式是在hyperbuttonexx .cpp文件顶部的构造函数中定义的。当前的演示代码默认设置创建了一个相当乏味的“普通”窗口样式的按钮,带有鼠标滑过文本的效果。虽然你可以通过初始化时的函数调用来完全定制你的按钮的外观,但是如果你想让你的应用程序的大部分按钮看起来是某种样子的,你可以通过改变构造函数的默认值来创建默认的外观。 在您熟悉这些代码之前,我建议您对这个源文件做一个备份,这样您就可以随时将其恢复到原始状态——以防万一。 如果您想使用自定义鼠标光标而不是Windows OEM的“手动”光标,那么在设置的第二部分中有关于导入和加载自定义光标的说明。 隐藏,收缩,复制Code

CHyperButtonEx::CHyperButtonEx()
{
     /*******************************************************************
                             DEFAULT SETTINGS

           Defaults to NORMAL button with mouseover text effect
     *******************************************************************/
    m_bTransparent = FALSE; //these 2 must be both false or only 1 true
    m_bFlat = FALSE;    //is button flat


    m_bRounded = TRUE; //if rounded button-only works with flat buttons
    ptRRect.x = 13;    //x and y coords for button rounding
    ptRRect.y = 13;
    m_crBorder = SHADOW;

    nBitmapRes = 0; //UINT_ID of normal image (zero disables images)
    nBitmapDis = 0; //UINT_ID of disabled image (zero uses grayout effect)

    m_nMouseover = 0;  //0-NONE, 1-IMAGE, 2-COLOR
    m_crMouseFrom = SILVER; //holds transparency color map values
    m_crMouseTo = SILVER;    //NORMAL mouseover color image effect
    m_crMouseHover=SILVER;    //HOVER mouseover color image effect
    m_idMouseImg = 0;    //holds mousover image UINT_ID


    m_nUnderline = NEVER; //options: NEVER/HOVER/ALWAYS
    m_crNText = RGB(0,0,0);    //normal text = bright blue
    m_crHText = RGB(0,0,255);    //hover text = bright blue
    m_crSystem = GetSysColor(COLOR_ACTIVEBORDER); //transparent color
    m_crNBackground = m_crSystem;  //transparent normal background
    m_crHBackground = m_crSystem;  //transparent hover background
    m_bBold = FALSE;     //force all fonts to boldface
    m_nBgStyle = SOLID;  //0-solid, 1-bitmap, 2-hatch
    m_nPattern = SOLID;  //if above is not SOLID then this must reflect
                         //appropriate pattern

    //image transparency bit defaults to silver - RGB(192,192,192)
    cm.from = 0x00C0C0C0; //colormap for making bitmap appear transparent


///////////////////////////////////////////////////////////////////////////////////////
//
//    If you prefer to load a cursor image from resource instead of using an OEM
//    then import a cursor image into your project resources then use the second
//    LoadCursor() statement to load it by resource ID. Be sure to comment out 
//    the above ::LoadCursor() statement if you choose this option
//
//    If you are targeting your app to Win98 or earlier systems you will have to use this
//    second option as the OEM hand cursor is only available in Win2000 or later.
//
//
///////////////////////////////////////////////////////////////////////////////////////


    m_hHand = ::LoadCursor(NULL, MAKEINTRESOURCE(32649)); // OCR_HAND in winuser.h

//    m_hHand = AfxGetApp()->LoadCursor(IDC_CURSOR1);
/*******************************************************************************
                           END DEFAULT SETTINGS
*******************************************************************************/

现在您已经定义了“默认”按钮,现在是实现类的时候了。 实现类 添加这三个文件,HyperButtonEx。h, HyperButtonEx。cpp和项目定义。h。确保添加#include <span class="code-string">"HyperButtonEx.h"</斯潘>到所有类的头文件,其中将有定制的按钮。 接下来,删除项目的.clw文件,然后调用类向导,并允许它重新构建类向导文件,以便添加新的类。 现在,每当您从资源编辑器添加一个按钮时,选择该按钮,按CTRL_W访问类向导,单击成员变量选项卡,将一个变量分配给类型为CONTROL的按钮,以及类的HyperButtonEx。您看!你的按钮现在被转换成一个“默认的”超级按钮控件。 现在,让我们假设你的默认按钮是一个普通的按钮,鼠标移到上面时会改变文本颜色…但是,你刚刚添加了一个你想要成为超链接按钮的按钮,链接到http:// URL。没有问题。在我向你具体展示如何做到这一点之前,让我们看看下面列出的可用公共函数调用: 隐藏,收缩,复制Code

public:
    void SetCustomFont(LOGFONT &nlf);
    void SetCustomFont(LPCTSTR szName="Default", 
                       int nSize=0, int nWeight=0, BOOL bItalic=FALSE);
    void SetBoldFont(BOOL bBold = TRUE);
    void IsTransparent(BOOL bTransparent = TRUE);
    void IsFlat(BOOL bFlat, int nRound=NONE, COLORREF crBorder=SHADOW);
    void SetToolTip(LPCTSTR szToolTip, COLORREF crBkColor=LTYELLOW, 
                    COLORREF crTextColor=BLACK);
    void SetBitmap(UINT nNormal=0, UINT nMouseover=0, BOOL bIsTrans=TRUE,
                    COLORREF crTrans=RGB(192,192,192), UINT nDisabled=0);
    void SetBitmapEx(UINT nNormal, COLORREF crFrom, COLORREF crNormal,
                    COLORREF crHover, UINT nDisabled=0);
    void SetBGStyle(int nStyle=0, UINT nPattern=0);
    void SetBgImage(BOOL bIsImage, UINT BitmapID=0)

    void SetButtonText(LPCTSTR szText) { m_szButtonText = szText; }
    void SetUnderline(int nUnderline = HOVER) { m_nUnderline = nUnderline; }
    void SetNormalText(COLORREF crNewColor) { m_crNText = crNewColor; }
    void SetHoverText(COLORREF crNewColor) { m_crHText = crNewColor; }
    void SetNormalBackground(COLORREF crNewColor) { m_crNBackground = crNewColor; }
    void SetHoverBackground(COLORREF crNewColor) { m_crHBackground = crNewColor; }

    BOOL OpenUrl(LPCTSTR szUrl);
    BOOL Explore(LPCTSTR szPath);
    BOOL RunApp(LPCTSTR szPath);
    BOOL OpenFileDefaultApp(LPCTSTR szPath);
    BOOL PrintLocalFile(LPCTSTR szPath);

其中大多数都是不言自明的。我要注意的是,当调用IsTransparent(TRUE)或IsFlat(TRUE)时,你不必发出一个单独的调用来设置另一个为FALSE…这个类会处理这个问题。但是,如果您将其中一个属性设置为FALSE,它不会自动将其对等物的属性设置为TRUE(两个都允许为FALSE,只允许一个为TRUE)。 现在,回到我们想要将新添加的按钮创建为超链接按钮的情况。这非常简单。您只需在OnInitDialog()或OnInitialUpdate(),甚至在类构造函数中重写默认设置。代码是这样的: 隐藏,复制Code

myUrlButton.IsTransparent();  //same as IsTransparent(TRUE);
myUrlButton.SetUnderline();   //same as SetUnderline(HOVER);

myUrlButton.SetNormalText(RGB(0,0,255));
myUrlButton.SetHoverText(RGB(0,0,255));

如果您想定制它们,还可以调用SetTooltip()或SetButtonText()。现在,剩下的就是处理按钮单击。正常添加消息处理程序。 那么,与从button类内部处理事件相比,处理按钮事件有什么优势呢?原因有很多。例如,您的按钮事件可能基于单选按钮选择链接到在线文档或本地文档。或者您可能希望在将URL传递到web服务器之前对其进行自定义。假设你在访问在线帮助数据库的对话框上有一个搜索功能。在用户键入搜索条件并单击搜索按钮之后,您可能希望从编辑框中获取搜索词,并将它们附加到URL以传递到在线搜索引擎。您的消息处理程序可能看起来像这样: 隐藏,复制Code

void MyViewClass::OnSearch()
{
    UpdateData();
    //assumes CString member var linked to edit box via DDX

    CString szUrl = "http://www.myhelpsite.com/help?search=";
    szUrl += m_szSearchTerms;
    //assumes string already validated and url encoded

    myUrlButton.OpenUrl(szUrl); 
}

并不是所有功能都在演示程序中演示,但其他功能,比如打印文件,或者运行外部应用程序,工作起来完全一样……只需调用该方法,在函数调用中传递完整的路径/文件名作为字符串。 稍微摆弄一下演示应用程序,您就会看到,只需使用一个类和几个简单的函数调用,就可以快速而轻松地从根本上改变按钮的外观和行为。 对未来发展的设想 最明显的想法似乎是在不强制使用位图资源的情况下实现渐变背景的透明度。然而,困难在于,有这么多可能的梯度绘制算法,没有办法确保你可以复制一个100%的精确匹配。唯一的解决方案似乎是父窗口和控件共享的一个同伴类(一个渐变绘制类),这样窗口和MEM DC都是用完全相同的算法绘制的。如果任何人对这个主题有任何其他意见,或者想处理这个项目,请随意分享。我有点不喜欢使用GDI aPI要求这样做是因为DLL分布问题,但我愿意接受建议。 其他想法:可以创建一个同伴类,作为预定义枚举LogFonts的“嵌入式数据库”。然后,您可以在CHyperButtonEx中添加一个方法,您可以简单地传递一个描述性名称,例如:ChangeFont(“DisorientedArialBold”)。该函数将此请求引用到伴生类(比如CLogFontColl),后者将搜索集合以查找匹配项,初始化日志字体,并将其返回到button类。 位图也可以完成类似的任务,以简化通用(或不太通用)按钮位图的收集和合并。 进一步的改进是将所有这些合并到一个DLL中。 结论 我希望这堂课对你有用。如果您有任何问题、意见和建议,请随时与我联系。好的编码! 更新信息- 2006年3月24日 这次更新包含了一些小的调整/修复,大部分与透明度和图像背景有关(更快的性能,快速重绘时较少的闪烁)。 它还修复了调试模式下的GDI断言。 我添加的主要增强功能是为扁平/圆角矩形按钮指定边框/阴影颜色。我只是在IsFlat()函数协议中添加了一个COLORREF变量。你只需调用myButton。IsFlat(真的,13日,RGB (0, 0, 0));——它是向后兼容的,如果你在函数调用中省略了colorref变量,它默认为系统的3D阴影颜色。 更新资料- 2006年3月7日 此更新修复了使用图像背景擦除方法的异常。在绘制控件之前,我们对对话框/表单上的客户区域进行了“快照”。但是,如果您的窗口是在最顶层的窗口后打开的,那么快照将会是最顶层窗口的快照,而不是您隐藏的窗口的快照。虽然这种情况不太可能经常发生,但它可能产生相当意外的结果。由于没有办法强迫您的窗口在其他最顶层的窗口之上,我选择了另一种解决方案。 我选择将这个类改为默认使用“像素颜色检测”,因为除了在图像背景上使用超链接或圆角样式按钮外,这在所有情况下都适用。然后,当你想在图像背景上使用透明的超链接/圆角样式按钮时,你只需调用myButton。SetBgImage(真的,IDB_MYBITMAPBG);当您初始化按钮时。这设置了一个使用图像擦除的标志。控件原始位图的客户区被复制到成员位图变量中,该成员位图变量保存在内存中直到销毁。当OnEraseBkgnd()被调用时,它将位图复制回父窗口的客户端区域。通过只将位图的客户端部分存储在内存中,这样可以最大限度地减少开销,并且消除了每次调用时加载、计算和复制位图的需要,从而提高了性能。 [性能提升- 3月24日更新] 这个方法的优点是,不管你的窗口是否被隐藏,它都能完美地工作。它有一个小缺点,如果你使用“渐变填充”背景下,必须使用“梯度图”而不是一幅算法,或者你需要解决一些困难问题与梯度相关的绘画方法和透明度——除非你回到使用“快照”方法,这(我们已经显示)有一个致命弱点。 更新信息- 2006年3月5日 这次更新向button类添加了完全的透明性,并向SetToolTip()方法添加了自定义文本和背景颜色。它还包括一些小的代码修改。 我将在这里讨论透明度。不仅按钮本身是透明的(例如,当使用圆角或透明/超链接按钮时),而且按钮图像也是完全透明的,无论它们是显示在一个实际的按钮上还是在对话框背景下(当使用透明/超链接按钮时)。即使在禁用状态下,它们也显示为透明的。见下图: 我必须将我为这个类修改和修改的位图掩码归功于一个未知的编码器(只知道为ScoobyDownUnder)。 总体透明特性有两个要素。第一个发生在OnEraseBkgrnd()中。根据布尔标志bImageBg的状态,这里合并了两个方法。这一切都发生在“第一次绘制”之前,任何控件已经绘制到对话框窗口。如果这个标志被设置为TRUE(通过调用SetBgImage())并且m_background包含一个位码资源ID(那不是零),那么OnEraseBkgnd()将加载位图并附加到一个内存DC,然后重新绘制控件的客户端部分的图像回到父窗口。[感谢Ali Rafiee的代码,这是这个想法的基础] 第二个抹除方法(如果bImageBg为FALSE,这是默认值)是使用CDC::GetPixel()方法来识别控件的客户端矩形区域中点像素的背景颜色,并存储COLORREF成员变量m_crSystem中的值。然后,每当需要擦除背景时,OnEraseBkgnd()使用SolidRectFill()用这种颜色绘制背景。 同样,像素颜色选择是默认模式,除了在图像/渐变背景上使用透明/超链接按钮外,在所有情况下都适用。在后一种情况下,您需要在初始化按钮时通过调用myButton设置图像模式。SetBgImage(真的,IDB_BITMAPID)。 现在,在按钮表面透明地绘制位图的问题是另一段代码,与OnEraseBkgnd()无关。但是,按钮图像可能是透明的,也可能不是,这取决于您想要的效果。控制按钮图像显示有两种函数调用: 下面是您将在大多数情况下使用的方法。注意所有设置的默认值(可以通过调用SetBitmap()来禁用图像,而不需要任何参数。 如果您希望在按钮上显示透明的位图,而不需要鼠标悬停,使用默认的银色像素作为透明颜色,并使用3D灰度显示禁用的图像效果,您只需调用myButton.SetBitmap(IDB_MYBITMAP);。 但是,您还可以指定用于鼠标悬停状态的图像,指定是否透明显示图像,指定透明颜色,以及指定用于禁用状态的图像(而不是使用3D灰度效果)。 隐藏,复制Code

void SetBitmap(UINT nNormal=0, UINT nMouseover=0, BOOL bIsTrans=TRUE, 
               COLORREF crTrans=RGB(192,192,192), UINT nDisabled=0);

第二种方法只在你想要一个colormap鼠标滑过效果而不是使用两个单独的位图鼠标滑过的情况下使用。此方法只是将原始位图的指定像素颜色在显示之前转换为另一个指定的颜色。显然,透明绘图在这个方法中是禁用的,因为透明位已经被用于包含颜色效果。这个特性通常只适用于实体正方形图像,比如复选框等,这些图像的边框周围没有空白(在“关于纯色”小框上的“关闭窗口”按钮就是这种按钮样式的一个例子)。你可以用myButton调用这个方法。SetBitmapEx(IDB_MYBITMAP,银色,白色,黄色); 函数协议如下: 隐藏,复制Code

void SetBitmapEx(UINT nBitmapID, COLORREF crTransparent, COLORREF crNormal,
                 COLORREF crMouseOver, UINT nDisabled=0);

有一些代码重新工作,一些函数协议已经被重新定义。我将在下面的文章正文中更新这些内容,但是如果您已经在使用较早的版本,请检查这些更改。 更新信息- 2006年2月25日 此更新增加了平模式下对圆角矩形按钮的支持。IsFlat ();方法已修改以适应此特性,如下所示: 隐藏,复制Code

//MODIFIED FUNCTION
//because nRound defaults to zero if omitted, calling this function
//in the oldstyle IsFlat(TRUE); will still create a square flat
//button, and IsFlat(FALSE); will still cancel flat mode.
//Supplying a non-zero integer for the second parameter will create 
//a symmetric rounded rectangle with both the X and Y axis set to 
//the value of nRound.

//The nRound parameter can be any integer, however negative integers
//behave as if they are unsigned, and ZER0 will disable rounded corners.
//For most cases the desirable value will fall in the range of 5-20.

//The crBorder parameter allows you to specify the
//border/shadow color for flat/rounded buttons. If omitted it
//defaults to system button shadow color. It is ignored if FALSE
//is passed as the boolean variable.


IsFlat(BOOL bFlat, int nRound=NONE, COLORREF crBorder=SHADOW);

这次更新还增加了一个工具来演示应用程序的主菜单允许您选择的任何字体/尺寸/样子的字体对话框中,和它会为你生成LOGFONT结构代码,你可以复制/粘贴到你的应用,你将只需要传递变量按钮类使用这个自定义字体的按钮(例:myButton.SetCustomFont(低频);。 关于自定义字体,需要注意的一点是:如果您要发布您的应用程序,除非您使用的是通用字体(Arial, Courier New等),否则您需要在应用程序安装程序中发布/安装这些字体(如果您的许可证允许的话),这样字体才能在目标机器上运行;所以,一定要选择相应的字体。 更新信息- 2006年2月22日 我添加了位图支持(包括3D灰度和鼠标滑过效果),自定义字体支持,画笔模式和阴影填充背景。这向原始类添加了4个非常简单的方法。你将使用代码来实现这些功能如下: 隐藏,收缩,复制Code

CHyperButtonEx m_myButton;

//FUNCTION 1:  to add a bitmap to the button
//see code in March 05, 2006 update section above for all bitmap function
//protocols


//the following code will add a transparent bitmap using silver as
//the tranparent color, it will have no mouseover effect, and will use
//3D grayout effect for disabled state

m_myButton.SetBitmap(IDB_MYBITMAP);

//FUNCTION 2:  to force all fonts to bold
m_myButton.SetBoldFont(TRUE);  //or FALSE if turning off bold

//FUNCTION 3:  to set a custom font
//SetCustomFont(LOGFONT nlf);
//           or
//SetCustomFont(LPCTSTR szName, int nSize, int nWeight, BOOL bItalic);

m_myButton.SetCustomFont("Verdana", 12, FW_MEDIUM, FALSE);

//to reset the default system font
m_myButton.SetCustomFont();  //variable defaults will take effect

//FUNCTION 4: to set background to brush pattern, hatch, or solid fill
//set solid fill
m_myButton.SetBGStyle(SOLID, SOLID);

//set bitmap brush patter
m_myButton.SetBGStyle(PATTERN, IDB_BITMAP_PATTERN1);
//set diagonal crosshatch fill
//see PBRUSH in MSDN or demo code for all options)

m_myButton.SetBGStyle(HATCH, HS_DIAGCROSS);

这些特性在创建“工具栏”类型的按钮时非常有用。你可能想要使用阴影和填充按钮(没有文本)绘制/填充工具按钮。如果你想要“工具栏”类型图像按钮在一个对话框或钢筋,要么是不可能的,添加一个工具栏,或不可取的,因为你只需要几个图片按钮,您可以创建小广场透明按钮没有文本并设置位图按钮图像,这将创建一个工具栏按钮的效果。您可以使用图像鼠标移过功能来为这些按钮创建OEM或自定义鼠标移过效果(例如:凸起的按钮、边框、颜色变化等)。 如果您发挥您的想象力和创造力,您会发现这个类几乎适用于需要任何类型的按钮对象的所有情况。 历史 13 - 2月- 2006 在CodeProject上的初始版本。 16 - 2月- 2006 增加了粗体文本,位图图像,模式/阴影背景。 2月18 - - 2006 增加了完全字体支持。 19 - 2月- 2006 固定字体init。bug。修正了大型自定义字体和禁用状态下的字体对齐问题。增加了禁用状态图像支持。在“关于”对话框上增加了鼠标移过图像的演示。 21日- 2月- 2006 对鼠标放下和禁用状态的小修正/改进。 22 - 2月- 2006 修正了调试模式下的CFont断言。ON_MESSAGE处理器现在返回LRESULT (VC7 issue).Adde3D灰度图像到禁用按钮(感谢Koen zager的代码)。增加了鼠标在图像上的支持。 2月25 - - 2006 增加了圆形矩形按钮在平模式。添加了LOGFONT代码生成工具到演示应用程序。 05 - mar - 2006 增加了完整的按钮/图像透明度。添加自定义文本/背景颜色到工具提示。一些函数协议被重新定义。 07 - 3月- 2006 固定闪烁时,按住鼠标按钮和移动失去控制。将错位的COLORMAP cm变量从public更改为protected。固定glitch与图像背景擦除方法时窗口隐藏的最顶层窗口在重画。 24 - 3月- 2006 修正了GDI在调试模式下的断言。提高了图像背景的透明度(在快速重绘时减少闪烁)。增加了指定平面/圆形按钮的边框/阴影颜色的功能(参见IsFlat()函数协议)。 本文转载于:http://www.diyabc.com/frontweb/news452.html

posted @ 2020-08-07 02:59  Dincat  阅读(164)  评论(0编辑  收藏  举报