Mor*_*hai 3 c++ user-interface winapi mfc visual-c++
我想更新一些类似工具栏的代码,我们必须让它们具有 Vista/Win7 渐变圆度。
目前,这些按钮具有 Windows 2000 的外观和感觉:块状、单色调。
我玩过 XP 主题,并使用过 DrawThemeBackground、DrawThemeEdge 等;但我对主题绘制机制非常不满意(按钮很大,主题将它们绘制为 2 色调,上半部分和下半部分,当按钮较小时看起来还可以-这使它们看起来像对它们来说是渐变的或圆润的。但是,尽管这些按钮很大,但它们看起来很愚蠢。
通过简单地观察在各种应用程序和控件中绘制了多少控件进行实验,我可以看到它们中的大多数似乎都使用了渐变——控件的顶部显示为浅色,然后渐变到底部为更深的颜色——或者- 它比顶部的背景颜色浅,在中间逐渐接近白色,然后在底部逐渐变回较深的颜色。
我真的不确定从这里去哪里。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());
}
Run Code Online (Sandbox Code Playgroud)
我在代码中留下了一些注释掉的变体,以表明一些关于我尝试过的其他可能性的提示。但是,它们只是一个提示,因为不存在完整的替代示例。
实际上,复制各种风格的 Windows 的外观是非常困难的,尤其是当您的应用程序可以在多个版本的 Windows 上运行时。
我认为他们打算在 Win2k/Win95 时代为您提供 api 来执行此操作,但后来 WinXP 出现了阴影和覆盖,而旧的 API 完全不够用。
所以他们想出了主题的东西,它甚至不是一个真正的 API,而是一个 API 和一组图形基元都挤在一起。但它们并没有贯彻执行并允许扩展或替换图形基元集,因此主题仅在您的控件与标准集非常匹配时才有效。
所以,对于Win9x/Win2k。你用
DrawFrameControl
DrawEdge
Run Code Online (Sandbox Code Playgroud)
对于 WinXP
DrawTheme
Run Code Online (Sandbox Code Playgroud)
对于 WinVista/7
DrawTheme
DwmXXX functions
GradientFill ??
Run Code Online (Sandbox Code Playgroud)
现在我怀疑 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);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3426 次 |
| 最近记录: |