如何写入一个(位?) 像缓冲区更快GDI+显示?
题
使用C++。净我有一流的数据,我想显示作为一个滚动的图像。每次我得到了一些新的数据,我想要增加它作为一个新的行(128x1素)和滚动中以前的内容在一边。
我的第一个刺在所涉及的问题呈现整个数据集每次我得到了一个新行。这一工作,但是速度太慢,所以我想它可能会更有意义写入一个缓冲区的某一类(a bitmap也许?).问题是,我不能看我怎么可以做到这一点; Graphic
对象能让你画画很愉快,但我不能看到一个明显的方式来告诉我的控制使用 Bitmap
对象,因为它的缓冲器?同样,我不能看到一种方法来绘制在一位这是我然后写到屏幕上。
这必须是可能的,但我谷歌-foo已失败,因此我远...
[Edit1] 只是为了澄清,数据是一个光谱图。下图显示了这样的事情我想要实现的:
数据,我密谋涉及在阵列的浮动。没有什么可以限制许多我会的,所以我只是想忘记的数据,因为它降低一侧的情节。
目前,我继承 System::Windows::Forms::UserControl
, 但可以切换到别的东西如果有一个更好的变质?
解决方案
看一看的滚屏的win32方法。您可以在屏幕上滚动的现有数据,然后只绘制新的数据。这是非常快。
其他提示
位图bmpImage =新位图(512512);
有(INT iRow = 0; iRow <512; iRow ++)
{
for (int iCol = 0; iCol <512; iCol++)
{
Color clr;
bmpImage.SetPixel(iCol, iRow, clr);
}
}
(图像)bmpImage.save()
一种可能战略:
画上一个backbuffer从左到右环绕当达到的结束。执行滚动的逻辑,只有当幅画画面(在某些指定的framerate).使用DrawImage源矩形和目的的矩形,以实现这一点。
使用图。LockBits(...)和位图。UnlockBits(...)方法,以修改原位的数据。小心只有锁的矩你是要修改,因为这些职能实际上使得副本的图数据从不受管理,以管理,存储器。一个例子如何做到这一描述这里 位..::.LockBits方法(矩形,ImageLockMode,PixelFormat).
替代LockBits是使用SetPixel在位图。但SetPixel被称为是缓慢的。
- 当块传输图像屏幕上确保CompositingMode在图形的实例是设bmpg.CompositingMode=CompositingMode.SourceCopy,这素格式的回的缓冲区是PixelFormat.Format32bppPArgb.
我不是很清楚到底是什么你想画(某种程度的控制在对话框?),但在猜测它应该工作是这样的:
class Foo {
...
Gdiplus::Bitmap* m_pBitmap;
};
void Foo::DrawItem(LPDRAWITEMSTRUCT lpDraw) {
// update bitmap if needed
if(some_condition_requiring_bitmap_redraw) {
// do expensive drawing into bitmap
Gdiplus::Graphics graphics(m_pBitmap);
}
// create a graphics object to draw the control from the bitmap
Gdiplus::Graphics graphics(lpDraw->hDC);
graphics.DrawImage(m_pBitmap, ...);
}
这是它一个非常粗略的猜测反正。该DRAWITEM电话,如果你正在使用.NET可能看上去完全不同的(我不熟悉...),但基本的逻辑应该是大致相同的。
根据究竟是什么你的数据是,它可能不是高效的同时绘制1个像素行。你可能会更好拉大面积只显示所需的它位 - 尽管这显然将取决于你的数据是怎么来的。
您还可能需要做一些更新到您的位图“滚动”的内容。我会离开,你: - )
试试下面的:
- 开始一个新的VC++它的应用程序。
- 添加一个用户的控制命名为'谱图'的项目
- 增加一个定时器控制的'光谱图'的用户控制和设置"已启用"财产的真实
- 添加下面的私人变量来的'光谱图'的用户控制
private:
Graphics ^m_gfxBuffer;
Graphics ^m_gfxOriginal;
Bitmap ^m_bmpBuffer;
Bitmap ^m_bmpOriginal;
- 添加以下代码来的'光谱图'的构造:
m_bmpBuffer = gcnew Bitmap(this->ClientSize.Width, this->ClientSize.Height);
m_gfxBuffer = Graphics::FromImage(m_bmpBuffer);
m_bmpOriginal = gcnew Bitmap(this->ClientSize.Width, this->ClientSize.Height);
m_gfxOriginal = Graphics::FromImage(m_bmpOriginal);
this->SetStyle(::ControlStyles::AllPaintingInWmPaint | ::ControlStyles::DoubleBuffer | ::ControlStyles::UserPaint | ::ControlStyles::OptimizedDoubleBuffer, true);
this->UpdateStyles();
- 添加以下代码来的'光谱图'漆的事件:
array<unsigned char, 1> ^bytes = gcnew array<unsigned char, 1>(m_bmpBuffer->Height * 3);
Random ^r = gcnew Random();
r->NextBytes(bytes);
m_gfxOriginal->DrawImage(m_bmpBuffer, -1, 0);
int y = 0;
for (int i = 0; i < m_bmpOriginal->Height * 3; i += 3)
{
m_bmpOriginal->SetPixel(m_bmpOriginal->Width - 1, y++, ::Drawing::Color::FromArgb(255, bytes[i], bytes[i + 1], bytes[i + 2]));
}
m_gfxBuffer->DrawImage(m_bmpOriginal, 0, 0);
e->Graphics->DrawImage(m_bmpOriginal, 0, 0);
- 添加以下代码的'光谱图'的定时器tick事件
this->Invalidate(false);
- 保存你的项目
- 清理和重建
- 运行的项目
- 附近运行的形式
- 频谱用户控制现在应该在工具箱'
- 拖它从工具箱'的形式和你应该看到一个滚动的随机的色谱图。
这应该给你一个一般性想法的一位缓冲控制。这里的关键是"SetStyle"电话在构造和偏位图通过-1在涂料的事件。
你将得到妥善处置的图形和位的对象以及处理破坏和重建他们在调整的事件。
希望这会有所帮助。让我知道如何去。