将网格绘制为背景的更好方法
Posted
技术标签:
【中文标题】将网格绘制为背景的更好方法【英文标题】:a better way to draw grid as background 【发布时间】:2012-09-01 04:43:20 【问题描述】:我想画网格,如下图。
我知道一个技巧,可以通过绘制 6 条垂直和水平线而不是 6 x 6 小矩形来绘制它。
但是如果我想要更小的缩放(查看图片的缩放),线条很多。例如,假设我的视图窗口大小为 800 x 600,并查看大小为 400 x 300 的图片(因此放大为 2)。将有 400 x 300 大小为 2 x 2 的矩形(每个矩形代表一个像素)。
如果我绘制每个单元格(在一个循环中,比如 400 x 300 次),它会非常慢(当我移动窗口时......)。 使用技巧可以解决问题。
我仍然很好奇在winapi GDI(+)中是否有更好的方法来完成这项任务。比如DrawGrid(HDC hdc, int x, int y, int numOfCellsH, int numOfCellsV)
?
另一个问题是:如果我不调整大小、移动窗口或不更改放大倍数,则不会更改网格。所以即使我不断更新图片(抓屏),也不需要重新绘制网格。但是我使用StretchBlt
和BitBlt
来截屏(到内存DC然后是窗口的hdc),如果我没有在内存DC中重绘网格,那么网格就会消失。有没有办法让网格粘在那里并更新屏幕截图的位图?
ps:这不是一个真正的问题。由于我想在缩放不小于 10 时绘制网格(因此每个单元格的大小为 10 x 10 或更大)。在这种情况下,最多可以绘制 100 + 100 = 200 条线,而且速度很快。我只是好奇是否有更快的方法。
【问题讨论】:
你仍然只需要画 700 条线。很快地做到这一点是微不足道的。画 700 条线真的有问题吗? @David,我已经提到这对我来说不是问题。但是我没有权利知道是否有更好的方法吗? 其实 SO 更喜欢关于真实实际问题的问题。我不认为 GDI 特别慢。我怀疑你会做得比它好得多。 【参考方案1】:您是否考虑过使用CreateDIBSection 这将允许您使用指针,以便您可以快速操作 R、G、B 值,例如以下创建 256x256x24 位图并以 64 像素间隔绘制绿色方块:
BITMAPINFO BI = 0;
BITMAPINFOHEADER &BIH = BI.bmiHeader;
BIH.biSize = sizeof(BITMAPINFOHEADER);
BIH.biBitCount = 24;
BIH.biWidth = 256;
BIH.biHeight = 256;
BIH.biPlanes = 1;
LPBYTE pBits = NULL;
HBITMAP hBitmap = CreateDIBSection(NULL, &BI, DIB_RGB_COLORS, (void**) &pBits, NULL, 0);
LPBYTE pDst = pBits;
for (int y = 0; y < 256; y++)
for (int x = 0; x < 256; x++)
BYTE R = 0;
BYTE G = 0;
BYTE B = 0;
if (x % 64 == 0) G = 255;
if (y % 64 == 0) G = 255;
*pDst++ = B;
*pDst++ = G;
*pDst++ = R;
HDC hMemDC = CreateCompatibleDC(NULL);
HGDIOBJ hOld = SelectObject(hMemDC, hBitmap);
BitBlt(hdc, 0, 0, 256, 256, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOld);
DeleteDC(hMemDC);
DeleteObject(hBitmap);
【讨论】:
【参考方案2】:一般来说,这类图形操作的主要限制因素是填充率和函数调用次数。
填充率是机器改变像素值的速度。通常,blit(复制矩形区域)非常快,因为它们经过高度优化并且旨在以缓存友好的顺序访问内存。但是一个 blit 会触及该区域中的所有像素。如果您要过度绘制,或者如果大多数像素并不真正需要更改,那么只绘制您需要的像素可能会更有效,即使这对缓存不太友好。
如果你通过制作 n 个东西来绘制 n 个图元,那么随着 n 变大,可能成为一个限制因素,寻找一个 API 调用可以让你绘制多个一次(或所有)行。
您的“技巧”展示了这两种优化。与 100 个矩形相比,绘制 20 条线的调用次数更少,而且它触及的像素也少得多。随着窗口的增长或网格大小的减小,lines 方法的调用次数和触摸的像素都会线性增加,而 rectangle 方法将增长为 n^2。
我认为在触及最小像素数方面你可以做得更好。但是我想如果你要画很多线,函数调用的数量可能会成为一个因素。我不知道 GDI+,但是在普通的 GDI 中,有像 Polyline
和 PolyPolyline
这样的函数可以让你在一次调用中绘制多条线。
【讨论】:
以上是关于将网格绘制为背景的更好方法的主要内容,如果未能解决你的问题,请参考以下文章
Visual Studio 2010中,采用chart插件绘制图表,怎样将背景中的网格线去掉呢?具体操作能详细叙述一下吗?