在对话框和视图的背景中使用彩色渐变






4.92/5 (51投票s)
一篇初学者文章,展示如何创建水平、垂直和对角线背景。还告诉您要注意什么,以避免在进行复杂绘图时出现闪烁。
渐变
渐变是美丽的,一直如此,并且将继续保持美丽。 哎呀! 我在这里做什么? 我想我有点得意忘形了。 请原谅我。 嗯,说真的,有时为我们的窗口设置渐变背景会很好。 我想我第一次记得看到渐变是在 Install Shield 生成的安装程序中。 即使在 Windows 3.11 时代,他们也有安装程序,通常使用蓝色渐变作为其背景。 最近,当我使用 PowerPoint 制作 CP 统计信息时,我使用橙色渐变作为演示文稿的背景。 嗯,正如我发现的那样,创建渐变没什么大不了的。
水平渐变
这个使用两种深色来创建渐变效果
这个使用绿色和白色作为两种边框颜色,并在这些颜色之间平滑地填充渐变
嗯,您所需要做的就是在您的 CWnd
类中重写 OnEraseBkgnd
。 我们从一种颜色开始,然后慢慢改变 RGB 值,直到我们得到另一种颜色。 这基本上是数学,而我真的不擅长数学。 因此,我使用的算法可能并不完美,我为此向您道歉。 但它描绘了如何获得渐变效果,这正是我想要的。 如果比我更好的数学家能给我一个更简单的公式,我会很高兴。
CDialog::OnEraseBkgnd(pDC); CRect rect; GetClientRect(&rect); int r1=127,g1=127,b1=56; //Any start color int r2=5,g2=55,b2=165; //Any stop color for(int i=0;i<rect.Width();i++) { int r,g,b; r = r1 + (i * (r2-r1) / rect.Width()); g = g1 + (i * (g2-g1) / rect.Width()); b = b1 + (i * (b2-b1) / rect.Width()); pDC->FillSolidRect(i,0,1,rect.Height(),RGB(r,g,b)); } return true;
垂直渐变
我在这里使用黑色到红色的渐变
这使用两种荧光色,我不建议使用这种组合,因为它会伤害眼睛
与水平渐变类似,我们重写 OnEraseBkgnd
CDialog::OnEraseBkgnd(pDC); CRect rect; GetClientRect(&rect); int r1=127,g1=127,b1=56; //Any start color int r2=5,g2=55,b2=165; //Any stop color for(int i=0;i<rect.Height();i++) { int r,g,b; r = r1 + (i * (r2-r1) / rect.Height()); g = g1 + (i * (g2-g1) / rect.Height()); b = b1 + (i * (b2-b1) / rect.Height()); pDC->FillSolidRect(0,i,rect.Width(),1,RGB(r,g,b)); } return true;
对角渐变
一个美丽的蓝色渐变。 就像那些 Installshield 背景一样
粉色,献给这里的 *咳咳* 女士们 :-)
对角渐变有点棘手。 与水平和垂直渐变不同,我们这里不处理矩形。 所以我们将无法使用 FillSolidRect
来达到我们的目的。 事实上,我们需要在一个相当繁重的循环中使用 MoveTo
和 LineTo
。 作为这个 GDI 方面的新手,我将所有代码都放在 OnEraseBkgnd
中。 绘画速度非常慢,几乎就像动画一样。 至少可以说我很失望。 那时这里的一些大师建议我使用内存 DC。 所以我使用了 CreateCompatibleDC
来创建一个内存 DC,并直接在这个 DC 上绘制。 然后我使用 BitBlt
将其爆破到实际的 DC 中。 嗯,有了相当大的改进。 现在动画效果消失了。 但仍然存在非常明显的闪烁。 这真的很糟糕。 但是绘画代码中的循环太多了。 那时我想到了保留 CBitmap
成员的这个想法。 在初始化期间,我将所有渐变内容绘制到此 CBitmap
中。 现在我需要在 OnEraseBkgnd
中做的一切就是将这个位图 BitBlt
到 DC 中,瞧,事情再次变得快速而流畅。
CDialog::OnEraseBkgnd(pDC); CRect rect; GetClientRect(&rect); CDC dc2; dc2.CreateCompatibleDC(pDC); CBitmap *oldbmap=dc2.SelectObject(&m_bitmap); /*We copy the bitmap into the DC*/ pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dc2,0,0,SRCCOPY); dc2.SelectObject(oldbmap); return true;
我写了一个名为 MakeBitmap
的函数,它创建渐变位图并将其放入我们的 CBitmap
成员中。 在我的基于对话框的应用程序中,我在 OnInitDialog
中调用了 MakeBitmap
。 在您的 SDI 程序中,我猜您应该在 OnInitialUpdate
中调用 MakeBitmap
。
void CYourClassName::MakeBitmap() { CPaintDC dc(this); CRect rect; GetClientRect(&rect); int r1=245,g1=190,b1=240; int r2=130,g2=0,b2=0; int x1=0,y1=0; int x2=0,y2=0; CDC dc2; dc2.CreateCompatibleDC(&dc); if(m_bitmap.m_hObject) m_bitmap.DeleteObject(); m_bitmap.CreateCompatibleBitmap(&dc,rect.Width(), rect.Height()); CBitmap *oldbmap=dc2.SelectObject(&m_bitmap); while(x1 < rect.Width() && y1 < rect.Height()) { if(y1 < rect.Height()-1) y1++; else x1++; if(x2 < rect.Width()-1) x2++; else y2++; int r,g,b; int i = x1+y1; r = r1 + (i * (r2-r1) / (rect.Width()+rect.Height())); g = g1 + (i * (g2-g1) / (rect.Width()+rect.Height())); b = b1 + (i * (b2-b1) / (rect.Width()+rect.Height())); CPen p(PS_SOLID,1,RGB(r,g,b)); CPen *oldpen = dc2.SelectObject(&p); dc2.MoveTo(x1,y1); dc2.LineTo(x2,y2); dc2.SelectObject(oldpen); } dc2.SelectObject(oldbmap); }
结论
本文中的所有屏幕截图都使用Adobe Photoshop 6调整了大小,我想感谢Ravi Bhavnani的图像大小调整技巧。