我正在开发用于可视化图算法的软件。图形可以变得非常大(数万个节点)。在这种情况下,绘制图形的当前状态很慢。现在,绘图代码的格式为:
cairo_push_group(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
... // drawing vertices and edges with styles
// corresponding to the current stage of the algorithm
cairo_stroke(cr);
cairo_pop_group_to_source(cr);
cairo_paint(cr);
cairo_surface_flush(surface);
XFlush(d);
我正在努力的功能是拖动图表,用户可以点击任意点并拖动整个图表。重新绘制(即上述代码中的“......”部分)根本无法跟上。
问题是:有没有办法让转换矩阵的变化(即cairo_translate
的应用)反映在屏幕上而不重新绘制?
我编写了以下小型完整程序来试验这个,但是我没有成功地产生积极的结果。这在main()
:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cairo-xlib.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <unistd.h>
//This function should give us a new x11 surface to draw on.
cairo_surface_t* create_x11_surface(Display *d, int *x, int *y)
{
Drawable da;
int screen;
cairo_surface_t* sfc;
Screen *scr;
screen = DefaultScreen(d);
scr = DefaultScreenOfDisplay(d);
if (!*x || !*y) {
*x = WidthOfScreen(scr)/2; *y = HeightOfScreen(scr)/2;
da = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, *x, *y, 0, 0,
0);
//fullscreen (d, da);
}
else
da =
XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, *x, *y, 0, 0, 0);
XSelectInput(d, da, ButtonPressMask | ButtonReleaseMask | KeyPressMask | ButtonMotionMask | StructureNotifyMask);
XMapWindow(d, da);
sfc = cairo_xlib_surface_create(d, da, DefaultVisual(d, screen), *x, *y);
return sfc;
}
int main(int argc, char** argv)
{
Display *d = XOpenDisplay(NULL);
if (d == NULL) {
fprintf(stderr, "Failed to open display\n");
return 1;
}
int x=500, y=500;
cairo_surface_t* surface = create_x11_surface(d, &x, &y);
cairo_t* cr = cairo_create(surface);
char *text = argv[1];
size_t text_len = 0;
XEvent e;
if (argc != 2)
text = NULL;
else
text_len = strlen(text);
int last_delta_x = 0, last_delta_y = 0;
int drag_start_x, drag_start_y;
bool firstDraw = true;
while(1)
{
if (XPending(cairo_xlib_surface_get_display(surface))) {
XNextEvent(cairo_xlib_surface_get_display(surface), &e);
switch(e.type) {
case ButtonPress:
drag_start_x = e.xbutton.x; drag_start_y = e.xbutton.y;
break;
case ButtonRelease:
last_delta_x = 0; last_delta_y = 0;
break;
case MotionNotify:
cairo_translate(cr, e.xmotion.x - drag_start_x - last_delta_x,
e.xmotion.y - drag_start_y - last_delta_y);
last_delta_x = e.xmotion.x - drag_start_x;
last_delta_y = e.xmotion.y - drag_start_y;
break;
case ConfigureNotify:
cairo_xlib_surface_set_size(surface, e.xconfigure.width, e.xconfigure.height);
break;
default:
fprintf(stderr, "Dropping unhandled XEevent.type = %d.\n",
e.type);
}
}
if (firstDraw) {
cairo_push_group(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
cairo_set_source_rgb(cr, 0, 1, 0);
cairo_move_to(cr, 0, 0);
cairo_line_to(cr, 256, 256);
cairo_move_to(cr, 256, 0);
cairo_line_to(cr, 0, 256);
cairo_set_line_width(cr, 10.0);
cairo_stroke(cr);
cairo_pop_group_to_source(cr);
// firstDraw = false;
// If the above is uncommented, translation is not reflected
}
cairo_paint(cr);
cairo_surface_flush(surface);
XFlush(d);
sleep(0.1);
}
cairo_destroy(cr);
cairo_surface_destroy(surface);
return 0;
}