• “剥皮”UI控件库(vc++)


    介绍 这个库承诺通过利用图像、GDI、合成和多重继承的强大功能,为那些想开发定制UI (curves等人)的用户提供非windows UI外观(只做了一点小小的修改——使其非常通用)。 灵感来自…… 几年前,当我第一次在Winamp (MP3播放器)上看到很酷的皮肤时,我感到很兴奋,并面临着编写一个用于未来开发的库的挑战,这会让那些认为漂亮的UI只在web应用程序和Flash应用程序中可行的人们感到震惊! 图书馆里面有什么? 该库由以下类组成: 所有控件的父类,包含公共的functionalityCSkinnedStatic自定义类作为静态控件或标签 继承自:Cwnd, CSkinControl 作为按钮控件的自定义类 继承自:Cwnd, CSkinControl 自定义类作为编辑控件 继承自:Cwnd, CSkinControl CSkinnedComboBox -自定义类作为组合框控件 继承自:Cwnd, CSkinControl 由:CSkinnedEdit, CSkinnedButton和CSkinnedListBox组成 自定义类作为一个列表框控件 继承自:Cwnd, CSkinControl 组成:CSkinnedButton CSkinnedScrollBar -自定义类,用作滚动条控件 继承:Cwnd, cskincontrol组成:CSkinnedButton 自定义类作为滑块控件 继承:Cwnd, cskincontrol组成:CSkinnedButton 建筑上的细节…… 其思想是将尽可能多的常用功能存储在一个类(CSkinControl)中,然后通过继承在具体的控制类中使用它。基类包含对四个不同图像(id)的引用,一个用于正常状态,一个用于禁用状态,一个用于悬停状态,还有一个用于按下状态。存储它的函数是SetImageResources(正常、悬停、按下、禁用)。基类还包含以下功能: 位置和尺寸: 顶部SetCoordinates(左)SetDimensions(宽度、高度)GetLeft () GetTop () GetWidth()获得() 颜色和字体: GetTextColor GetCurrentBackgroundColor () () GetBackgroundColor(状态)SetBackgroundColor(状态、颜色)SetForegroundColor(颜色)SetTextColor(颜色)SetFontName(名字)SetFontStyle(风格)SetFontSize(大小)GetFontName () GetFontStyle () GetFontSize () 最重要的函数是UpdateMemoryDC(),它负责绘制和更新屏幕上每个控件的视觉效果,无论该控件处于默认状态还是由某些用户操作(鼠标事件)触发。 隐藏,收缩,复制Code

    // This function attempts to load image
    // resources from a DLL and renders the same on the screen
    
    int CSkinControl::UpdateMemoryDC()
    {
        HBITMAP hBitmap = NULL;
        BITMAP bmpTemp;
    // If gifs are the preferred resources, use conversion
    #ifdef USE_GIF_IMAGES
        hBitmap = LoadGIF(GetDllInstance((LPCTSTR)m_csDLLFileName),
                          MAKEINTRESOURCE(GetID()));
    #else
        hBitmap = LoadBitmap(GetDllInstance((LPTSTR)(LPCTSTR)m_csDLLFileName), 
                             MAKEINTRESOURCE(GetID()));
    #endif
        if(hBitmap != NULL)
        {
            ::GetObject(hBitmap, sizeof(BITMAP), &bmpTemp);
            m_lImageWidth = bmpTemp.bmWidth;
            m_lImageHeight = bmpTemp.bmHeight;
            ::SelectObject(m_dcMemory.GetSafeHdc(),hBitmap);
        }
        // If the object is of text type (edit)
        else if(m_nPressedID == -1 && m_nUnPressedID == -1 && m_nHoverID == -1)
        {        
            m_dcMemory.SetTextColor(m_crTextColor);
            m_dcMemory.DrawText(m_csText, CRect(0, 0, m_nWidth, m_nHeight), DT_CENTER);
        }
        return 0;
    }

    具体类提供了它们的标准对等物所需要的功能。例如,CSkinnedEdit支持文本选择,插入,删除(没有实现复制粘贴-抱歉!!),以及其他定制功能,如“只读”,“小数点验证”等。类似地,CSkinnedScrollBar提供了设置最小范围、最大范围、检索滚动条按钮位置等功能。代码和函数名是不言自明的。我很抱歉没有提供很多内联代码注释,你可以随时联系我。 所有控件都是动态创建的。它们每个都有一个CreateSkinControl函数(名称、rect、父类、id、标志),它接受前面提到的参数。最后一个(标志)是一个有趣的参数,它包含创建所需的任何“额外”信息(您将在不同的控件中看到)。例如,下面显示的是CSkinnedButton控件的创建代码: 隐藏,收缩,复制Code

    BOOL CSkinnedButton::CreateSkinControl(LPCTSTR lpszWindowName, LPRECT lpRect, 
                         CWnd *pParentWnd, UINT nControlID, long lFlags)
    {
        // Set windows name, location, size, parent, and control id
        m_csText = lpszWindowName;
        m_nLeft = lpRect->left;
        m_nTop = lpRect->top;
        m_nWidth = lpRect->right - lpRect->left;
        m_nHeight = lpRect->bottom - lpRect->top;
        m_pParentWnd = pParentWnd;
        m_nControlID = nControlID;
        
        // Assign a default font and defaut colors
        m_csFontName = "Arial";
        m_nFontSize = 16;
        m_nFontStyle = FONT_NORMAL;
        m_crBackgroundColorHover = RGB(255,255,255);
        m_crBackgroundColorPressed = RGB(255,255,255);
        m_crBackgroundColorUnPressed = RGB(255,255,255);
        m_crForegroundColor = RGB(0,0,0);
    
        // Store special button information
        m_lButtonType = lFlags;
    
        // If the control is already created, return false
        if(m_hWnd != NULL)
        {
            return FALSE;
        }
    
        // Create the control using CWnd::Create() and bring it to the top
        // Notice the flag WS_CLIPSIBLINGS; this is necessary
        // for proper rendering of composite controls
        if(CWnd::Create(NULL, m_csText, WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, 
                        *lpRect, pParentWnd, nControlID, NULL))
        {
            CWnd::BringWindowToTop();
    
            return TRUE;
        }
        
        return FALSE;
    }

    步骤来实现… 在想要使用控件(例如按钮)的窗口/对话框中,定义一个成员变量,该成员变量是指向该控件的指针。隐藏,CodeCSkinnedButton * m_pOkButton复印件; 在对话框OnCreate()或OnInitDialog()的创建逻辑中,在创建用于背景绘制的内存DC的一些初始化之后,插入按钮的创建逻辑。隐藏,OnCreate(LPCREATESTRUCT LPCREATESTRUCT) { 如果(CDialog:: OnCreate (lpCreateStruct) = = 1) { 返回1; } CClientDC直流(这个); m_memDC.CreateCompatibleDC(及直流); m_memBmp.CreateCompatibleBitmap(及直流、1024、768); m_memDC.SelectObject(及m_memBmp); / /其他代码 … / /创建按钮 m_pOkButton = new CSkinnedButton; //分配4个图像id m_pOkButton。SetImageResource(ID_NORMAL, ID_HOVER, ID_PRESSED, ID_DISABLED); //这个标志(true)表示按钮 //是一个不规则形状,将使用 // a透明算法,达到预期效果 m_pOkButton.SetShapedFlag(真正的); / /其他代码 … } 按钮创建和渲染的自定义代码在CSkinnedButton类中实现,如下所示: 隐藏,收缩,复制Codeint CSkinnedButton::OnCreate(LPCREATESTRUCT lpCreateStruct) { 如果(CWnd:: OnCreate (lpCreateStruct) = = 1) 返回1; CClientDC直流(这个); CBitmap bmpTemp; m_dcMemory.CreateCompatibleDC(及直流); 如果(bmpTemp.CreateCompatibleBitmap(和直流、m_nWidth m_nHeight) ! = 0) { m_dcMemory.SelectObject(及bmpTemp); 如果(PrepareFont ()) { } UpdateMemoryDC (); / /创建地区如果不规则形状 如果(m_bShape) { m_hRgn =应用(0,0,0,0); 如果(m_hRgn ! = NULL) { 如果(GetWindowRgn (m_hRgn) = =错误) { m_hRgn =零; 返回1; } } 其他的 { 返回1; } } } 返回0; } int CSkinnedButton: UpdateMemoryDC () { 位图bmpTemp; memset(和bmpTemp 0 sizeof(位图)); 如果(m_dcMemory = = NULL) { 返回1; } # ifdef USE_GIF_IMAGES 如果(m_hBitmap ! =零,,m_hBitmap = = GetCurrentStateBitmap ()) { 返回1; } m_hBitmap = GetCurrentStateBitmap (); 其他# hBitmap = GetCurrentStateBitmap (); # endif 如果(m_hBitmap ! = NULL) { :: GetObject (m_hBitmap sizeof(位图),bmpTemp); m_lImageWidth = bmpTemp.bmWidth; m_lImageHeight = bmpTemp.bmHeight; :: SelectObject (m_dcMemory.GetSafeHdc (), m_hBitmap); } else if (m_nPressedID = = 1,,m_nUnPressedID = = 1,,m_nHoverID = = 1) { CClientDC直流(这个); m_dcMemory.SetMapMode (dc.GetMapMode ()); m_dcMemory.SetWindowExt (dc.GetWindowExt ()); m_dcMemory.SetViewportExt (dc.GetViewportExt ()); m_dcMemory。SetWindowOrg (0,0); CBitmap cbmpTemp; cbmpTemp.CreateCompatibleBitmap(及直流m_nWidth m_nHeight); 如果(m_dcMemory.SelectObject(及cbmpTemp) ! = NULL) { m_dcMemory。FillSolidRect (0, 0, m_nWidth m_nHeight, GetCurrentBackgroundColor ()); } } / /这是不规则形状代码最重要的部分 如果(m_bShape ! = 1,,m_bFindEdges) { m_bFindEdges = FALSE; FindControlEdge(这和m_dcMemory、COLOR_MAGENTA m_hRgnWindow); } 返回0; } FindControlEdge()(不是一个非常直观的名字!)实现了透明的算法,使用红色颜色面具,遍历图像,剪一个地区。你可能会认为,为什么不使用GDI函数TransparentBlt()来达到相同的。好点!然而,当我试图使用TransparentBlt实现,它没有运行在Windows 98 SE(尽管女士声称支持版本的Windows !)。不管怎么说,可能是我没有正确的补丁的Windows或SDK。我决定写我自己的。你有一个选择使用TransparentBlt将承诺在我的技术优化性能确定;) 同时,我的技术引入了严格要求的所有图像受四个像素的红色背景! !例子: 那些可能面临类似的问题TransparentBlt()可以自由使用这里显示的算法或一个你自己的。 隐藏,收缩,复制代码/ /通过形象和创建这个函数遍历 / /区域消除“红色”像素并设置窗口句柄 BOOL FindControlEdge (CWnd * pWnd,疾控中心* dcControl, 也就是说colToSkip HRGN和HRGN) { int nCurrentX = 0; int nCurrentY = 0; int nTempX = 0; int nTempY = 0; BOOL bStop = FALSE; int nDirection = 0; int nCurDirection = 0; int nFirstX = 0; int nFirstY = 0; int nXMap = 0; int nYMap = 0; int nIterate = 0; 点ptTempCoord; CList<点,在ptCoord; 绘图用的矩形类rcWindow (0, 0, 0, 0); 绘图用的矩形类rcClient (0, 0, 0, 0); pWnd→GetWindowRect(及rcWindow); pWnd→GetClientRect(及rcClient); pWnd→ClientToScreen(及rcClient); nXMap = rcClient。左- rcWindow.left; nYMap = rcClient。最高- rcWindow.top; nIterate = 0; bStop = FALSE; nCurrentX = 0; nCurrentY = 0; nDirection =东南; nFirstX = 0; nFirstY = 0; 而(! bStop) { 如果((dcControl→获取像素(nCurrentX + 1, nCurrentY + 1)) ! = colToSkip) { bStop = TRUE; 如果(nCurrentX = = 0,,nCurrentY = = 0) { 返回错误; } } 其他的 { nCurrentX + +; nCurrentY + +; } } bStop = FALSE; 而(! bStop) { nIterate + +; 开关(nDirection) { 例:东南部 如果((dcControl→获取像素(nCurrentX + 1, nCurrentY + 1)) ! = colToSkip) { nDirection =东; 继续; } 其他的 { 数控urrentX + +; nCurrentY + +; } 打破; 东: 如果((dcControl→获取像素(nCurrentX + 1, nCurrentY)) ! = colToSkip) { nDirection =东北; 继续; } 其他的 { nCurrentX + +; } 打破; 东北地区: 如果((dcControl→获取像素(nCurrentX + 1, nCurrentY-1)) ! = colToSkip) { nDirection =北; 继续; } 其他的 { nCurrentX + +; nCurrentY——; } 打破; 北: 如果((dcControl→获取像素(nCurrentX nCurrentY-1)) ! = colToSkip) { nDirection =西北; 继续; } 其他的 { nCurrentY——; } 打破; 西北: 如果((dcControl→获取像素(nCurrentX-1 nCurrentY-1)) ! = colToSkip) { nDirection =西方; 继续; } 其他的 { nCurrentX——; nCurrentY——; } 打破; 西方: 如果((dcControl→获取像素(nCurrentX-1 nCurrentY)) ! = colToSkip) { nDirection =西南; 继续; } 其他的 { nCurrentX——; } 打破; 西南地区: 如果((dcControl→获取像素(nCurrentX-1, nCurrentY + 1)) ! = colToSkip) { nDirection =南; 继续; } 其他的 { nCurrentX——; nCurrentY + +; } 打破; 南: 如果((dcControl→获取像素(nCurrentX, nCurrentY + 1)) ! = colToSkip) { nDirection =东南; 继续; } 其他的 { nCurrentY + +; } 打破; } nCurDirection = nDirection; 如果((dcControl→获取像素(nCurrentX + 1, nCurrentY + 1)) ! = colToSkip) { nDirection =东南; } 如果((dcControl→获取像素(nCurrentX + 1, nCurrentY)) ! = colToSkip) { nDirection =东; } 如果((dcControl→获取像素(nCurrentX + 1, nCurrentY-1)) ! = colToSkip) { nDirection =东北; } 如果((dcControl→获取像素(nCurrentX nCurrentY-1)) ! = colToSkip) { nDirection =北; } 如果((dcControl→获取像素(nCurrentX-1 nCurrentY-1)) ! = colToSkip) { nDirection =西北; } 如果((dcControl→获取像素(nCurrentX-1 nCurrentY)) ! = colToSkip) { nDirection =西方; } 如果((dcControl→获取像素(nCurrentX-1, nCurrentY + 1)) ! = colToSkip) { nDirection =西南; } 如果((dcControl→获取像素(nCurrentX, nCurrentY + 1)) ! = colToSkip) { nDirection =南; } 点ptTemp; 如果(ptCoord.GetCount()在0) { ptTemp = ptCoord.GetTail (); } 其他的 { ptTemp。x = 0; ptTemp。y = 0; } 如果(nCurrentX ! = ptTemp。x | | nCurrentY ! = ptTemp.y) { nTempX = nCurrentX; nTempY = nCurrentY; 开关(nCurDirection) { 北: 西北: nTempX + +; 打破; 东北地区: 东: nTempY + +; 打破; } ptTempCoord。x = nTempX; ptTempCoord。y = nTempY; ptCoord.AddTail (ptTempCoord); } 如果(nFirstX = = 0,,nFirstY = = 0) { nFirstX = nCurrentX; nFirstY = nCurrentY; } else if (nCurrentX = = nFirstX,,nCurrentY = = nFirstY) { 打破; } } 点* ptAll; ptAll = new点[ptCoord.GetCount ()); int nLen = ptCoord.GetCount (); for (int idx = 0;idx< nLen;idx + +) { ptAll [idx] = ptCoord.GetHead (); ptCoord.RemoveHead (); } hRgn = CreatePolygonRgn (ptAll nLen,备用); 删除[]ptAll; 如果(hRgn ! = NULL) { 如果(pWnd→SetWindowRgn (hRgn,真)! = 0) { 返回TRUE; } } 返回错误; } 最后,您实现消息处理程序来控制反应事件和消息(LButtonDown /按钮,OnChar编辑,等等),并适当地玩不同控制状态(正常、悬停、残疾人,等等)和更新相应的“看”通过调用UpdateMemoryDC()。 一些好处…… 如果如果设计得当,你可以为你的应用程序提出并行的“主题”;基本上,不同的图像集叠加在您的应用程序和控件上,并使用配置文件轻松切换。 本文转载于:http://www.diyabc.com/frontweb/news12204.html

  • 相关阅读:
    java、javaw和javaws的区别
    Hibernate4教程二:基本配置(2)
    Maven入门指南10:Maven的生命周期和插件
    Java中的断言(assert)
    MySQL的数据类型:文本、数字、日期/时间
    面向对象的三大基本特征和五大基本原则
    高内聚低耦合的介绍
    9.7 模拟赛
    16-17学期计划(每周)
    JZOJ 5281 钦点
  • 原文地址:https://www.cnblogs.com/Dincat/p/13473705.html
Copyright © 2020-2023  润新知