手动绘制按钮,工具栏,标签等渐变?

时间:2010-01-18 19:10:51

标签: c++ user-interface visual-c++ mfc winapi

我想更新一些类似工具栏的代码,我们必须为它们提供Vista / Win7渐变舍入。

目前,这些按钮具有Windows 2000外观和功能。感觉:块状,单音。

我玩过XP主题,并使用DrawThemeBackground,DrawThemeEdge等;但我对主题绘图机制非常不满意(按钮很大,主题将它们画成双色调,上半部分和下半部分,当按钮很小时看起来还不错 - 它给了它们一个中等体面的外观是一个渐变或具有圆润的质量。但是,与这些按钮一样大,它们看起来很愚蠢。

通过简单地观察在各种应用程序和控件中绘制了多少控件来进行实验,我可以看到它们中的大多数似乎都使用了渐变 - 控件的顶部显示为浅色并且向下淡化为更暗颜色 - 或者 - 它比顶部的背景颜色浅,在中间增加到接近白色,然后逐渐淡化为底部的颜色。

我不确定从哪里开始。 DrawThemeXXX似乎不够。我真的不想用一个改进了绘图的新控件来替换整个控件,但是我需要交换一些代码以了解当前自定义控件的工作方式,并且冒一些其他库的风险。 我宁愿选择以我正在运行的当前Windows版本的方式绘制任意对象。我原本认为主题绘图功能会涵盖这一点。但正如我所描述的那样,它们相当大脑受损。

有人能指出我'现代C ++应用程序应该如何绘制自定义GUI元素,以便他们可以合理地期望XP,Vista和Windows 7下的优雅外观?'

我们目前在代码中使用MFC,Gdiplus和原始Win32 API。

这是希望有人知道很多关于在Windows下用C ++绘制现代GUI的方法!

只是这不是一个文本墙,这里是当前版本的绘图处理程序,它在“热跟踪”时绘制带有蚀刻边框的按钮,并且蚀刻边框和图标+文本“按下“处于压力状态时”(移位1,1):

void CPlacesButton::PaintButton(CDC & dc, CRect & rcClient)
{
 const int kLabelHeight = 8;

 COLORREF clrHiLt = GetSysColor(COLOR_BTNHIGHLIGHT);
 COLORREF clrShdo = GetSysColor(COLOR_BTNSHADOW);
 COLORREF clrText = GetSysColor(COLOR_BTNTEXT);
 COLORREF clrFace = GetSysColor(COLOR_BTNFACE);

 // draw the button's background & border

 if (m_bPressed || m_bDrawPressed || m_bMouseOnButton)
 {
  COLORREF clrDarkened = Darken(clrFace, -0.01f);
  dc.FillRect(rcClient, &CBrush(clrDarkened));

  //dc.Draw3dRect(rcClient, clrShdo, clrHiLt);
  //dc.RoundRect(&rcClient, CPoint(10,10));
  dc.DrawEdge(&rcClient, EDGE_ETCHED, BF_RECT|BF_FLAT);
  //dc.DrawFrameControl(&rcClient, DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);
 }
//  else if (m_bMouseOnButton) // hot draw
//   //dc.Draw3dRect(rcClient, clrShdo, clrHiLt);
//   dc.DrawEdge(&rcClient, EDGE_ETCHED, BF_RECT);
//   //dc.RoundRect(&rcClient, CPoint(10,10));
 else
  dc.FillRect(rcClient, &CBrush(clrFace));

 // use transparent mode for everything that follows
 dc.SetBkMode(TRANSPARENT);

 // center icon
 CPoint ptIcon((rcClient.Width() - m_nIconSize) / 2, ((rcClient.Height() - m_nIconSize) / 2) - kLabelHeight);
 if (m_bPressed || m_bDrawPressed)
  ptIcon.Offset(1, 1);

 // determine the state to draw ourselves in
 const UINT nState = DST_ICON | (IsEnabled() ? DSS_NORMAL : DSS_DISABLED);

 // draw our icon
 dc.DrawState(ptIcon, CSize(m_nIconSize, m_nIconSize), m_hIcon, nState, (HBRUSH)NULL);

 // create & select the font to use for the button's label
 CFont guiFont;
 VERIFY(guiFont.CreateStockObject(DEFAULT_GUI_FONT));
 AutoSelectGDIObject select_font(dc, guiFont);

 // determine clipping rect for label
 CRect rcText(0, ptIcon.y+m_nIconSize+kLabelHeight, rcClient.Width(), ptIcon.y+m_nIconSize+kLabelHeight);
 rcText.InflateRect(0,20);
 if (m_bPressed || m_bDrawPressed)
  rcText.OffsetRect(1, 1);

 dc.SetTextColor(clrText);
 if (IsEnabled())
  dc.DrawText(m_strCaption, rcText, DT_VCENTER|DT_SINGLELINE|DT_CENTER);
 else
  dc.GrayString(NULL, NULL, (LPARAM)(LPCTSTR)m_strCaption, 0, rcText.TopLeft().x, rcText.TopLeft().y, rcText.Width(), rcText.Height());
}

我在代码中留下了一些注释掉的变体,以指示我尝试过的其他可能性的一些提示。但是,它们只是一个暗示,因为没有完整的替代示例。

3 个答案:

答案 0 :(得分:4)

实际上,复制Windows各种风格的外观非常困难,尤其是如果您的应用程序可以在多个版本的Windows上运行。

我认为他们打算在Win2k / Win95时代给你这样做的答案,但随后WinXP出现了阴影和叠加,旧的API完全不合适。

所以他们提出了主题内容,这些内容实际上并不是一个API,因为API和一组图形基元都挤在一起。但是他们没有遵循并允许扩展或替换一组图形基元,因此主题仅在您的控件与标准集紧密匹配时才有效。

所以,对于Win9x / Win2k。你用

DrawFrameControl
DrawEdge

对于WinXP

DrawTheme

对于WinVista / 7

DrawTheme
DwmXXX functions
GradientFill ??

现在我怀疑Windows实际上并没有使用GradientDraw。我怀疑它实际上是使用内置于窗口管理器代码中的一些DX10着色器,但我不知道如何实现,我一直在使用GradientDraw。此代码将为您提供从控件顶部到底部的线性淡入淡出。

INLINE void SetTrivertex(TRIVERTEX & vtx, int x, int y, COLORREF cr)
{
   vtx.x      = x;
   vtx.y      = y;
   vtx.Red    = (SHORT)(GetRValue(cr) * 256L);
   vtx.Green  = (SHORT)(GetGValue(cr) * 256L);
   vtx.Blue   = (SHORT)(GetBValue(cr) * 256L);
   vtx.Alpha  = (SHORT)(255 * 256L);
}

...

  // fill the interior from the top down with a gradient that starts at crTop
  // and ends with the crBottom
  TRIVERTEX vtx[2];
  SetTrivertex (vtx[0], prc->left+1, prc->top+1, crTop);
  SetTrivertex (vtx[1], prc->right-1, prc->bottom-1, crBottom);

  GRADIENT_RECT gRect = { 0, 1 };
  GradientFill(hdc, vtx, 2, &gRect, 1, GRADIENT_FILL_RECT_V); 

答案 1 :(得分:4)

您从未提及过MFC功能包。你看过它了吗?下载VS2008,包含在VS2008 SP1中。 CDrawingManager有很多特效。它对应用程序主题有很大的支持。

答案 2 :(得分:1)

单独的MFC并不完全是皮肤友好的。除了使用另一个GUI(Qt非常适合自定义蒙皮),您可以查看SkinCrafter等解决方案。