您不必在on_draw 中绘制所有内容。我从您的帖子中了解到,您有一个实时波形绘图应用程序,其中可以在固定周期(我假设每隔几毫秒)提供样本。您可以遵循三种方法。
方法 1
当您的内存有限并且不关心在调整窗口大小或未覆盖时保留绘图时,这非常有用。以下可能是接收样本的函数(一个接一个)。
注意:以 m_ 为前缀的变量是类成员。
void DrawingArea::PlotSample(int nSample)
{
Cairo::RefPtr <Cairo::Context> refCairoContext;
double dNewY;
//Get window's cairo context
refCairoContext = get_window()->create_cairo_context();
//TODO Scale and transform sample to new Y coordinate
dNewY = nSample;
//Clear area for new waveform segment
{
refCairoContext->rectangle(m_dPreviousX
+ 1,
m_dPreviousY,
ERASER_WIDTH,
get_allocated_height()); //See note below on m_dPreviousX + 1
refCairoContext->set_source_rgb(0,
0,
0);
refCairoContext->fill();
}
//Setup Cairo context for the trace
{
refCairoContext->set_source_rgb(1,
1,
1);
refCairoContext->set_antialias(Cairo::ANTIALIAS_SUBPIXEL); //This is up to you
refCairoContext->set_line_width(1); //It's 2 by default and better that way with anti-aliasing
}
//Add sub-path and stroke
refCairoContext->move_to(m_dPreviousX,
m_dPreviousY);
m_dPreviousX += m_dXStep;
refCairoContext->line_to(m_dPreviousX,
dNewY);
refCairoContext->stroke();
//Update coordinates
if (m_dPreviousX
>= get_allocated_width())
{
m_dPreviousX = 0;
}
m_dPreviousY = dNewY;
}
在清除区域时,X 坐标必须偏移 1,否则“橡皮擦”将清除最后一列的抗锯齿,并且您的跟踪将具有锯齿状边缘。它可能需要大于 1,具体取决于您的线条粗细。
就像我之前说的,使用这种方法,如果小部件被调整大小或“显示”,您的跟踪将被清除。
方法 2
即使在这里,样本的绘制方式也与以前相同。唯一的区别是接收到的每个样本都被直接推入缓冲区。当窗口被调整大小或“陶醉”时,小部件的 on_draw 被调用,您可以一次绘制所有样本。当然,您需要一些内存(如果队列中有 350K 样本,则需要很多内存),但无论如何跟踪都会保留在屏幕上。
方法 3
这也占用了一点内存(可能更多取决于您的小部件的大小),并使用屏幕外缓冲区。在这里,我们存储渲染结果而不是存储样本。覆盖小部件的 on_map 方法和 on_size_allocate 以创建一个离线缓冲区。
void DrawingArea::CreateOffscreenBuffer(void)
{
Glib::RefPtr <Gdk::Window> refWindow = get_window();
Gtk::Allocation oAllocation = get_allocation();
if (refWindow)
{
Cairo::RefPtr <Cairo::Context> refCairoContext;
m_refOffscreenSurface =
refWindow->create_similar_surface(Cairo::CONTENT_COLOR,
oAllocation.get_width(),
oAllocation.get_height());
refCairoContext = Cairo::Context::create(m_refOffscreenSurface);
//TODO paint the background (grids may be?)
}
}
现在当您收到样本时,而不是直接绘制到窗口中,而不是直接绘制到屏幕外表面。然后通过将此表面设置为窗口的 cairo 上下文的源来阻止复制屏幕外表面,然后绘制一个矩形以绘制新绘制的样本。同样在您的小部件的 on_draw 中,只需将此表面设置为小部件的 cairo 上下文的源并执行 Cairo::Context::paint()。如果您的小部件可能没有调整大小,这种方法特别有用,并且优点是 blitting(将一个表面的内容传输到另一个表面)比绘制单个线段要快得多。