将网格绘制为背景的更好方法

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)?

这样的函数

另一个问题是:如果我不调整大小、移动窗口或不更改放大倍数,则不会更改网格。所以即使我不断更新图片(抓屏),也不需要重新绘制网格。但是我使用StretchBltBitBlt来截屏(到内存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 中,有像 PolylinePolyPolyline 这样的函数可以让你在一次调用中绘制多条线。

【讨论】:

以上是关于将网格绘制为背景的更好方法的主要内容,如果未能解决你的问题,请参考以下文章

更改 JButtons 背景的最佳方法

Qt / PyQt 绘制网格背景源码

Qt / PyQt 绘制网格背景源码

Visual Studio 2010中,采用chart插件绘制图表,怎样将背景中的网格线去掉呢?具体操作能详细叙述一下吗?

Qt / PyQt 绘制网格背景源码

我应该使用啥来获得更好的性能、九个补丁或可绘制的 xml 资源?