如何使用 gtk+ 用 cairo 重绘文本
How redraw text with cairo using gtk+
我正在使用 cairo 绘制一些圆形小部件,例如 this。
我使用"draw"绘图区事件绘制了所有的小部件,但我不知道如何更新小部件中的数据。
这是我编写的代码:
gboolean hald_circular_gauge (GtkWidget *widget,cairo_t *cr, gdouble max, gdouble min, gdouble value, gchar *pcname ,gchar *unit){
cairo_text_extents_t extents, extentsTemp, extentsLabel, extentsTempMin, extentsTempMax;
int width, height;
gint percentage, linewidth;
double x,y;
gdouble declive = (360.0-180.0)/(max-min);
gdouble origin = 180.0 - declive*min;
gchar pcTemp[BUFSIZ];
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
double angle1 = 180.0 * (M_PI/180.0); /* angles are specified */
double angle2 = 360.0 * (M_PI/180.0); /* in radians */
if(min > value || value >max)
return FALSE;
linewidth = (MIN (width, height) / 2.0 * 30.0) / 100.0;
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6);
cairo_set_line_width (cr, linewidth);
cairo_arc(cr, width/2.0, height/2.0, MIN (width, height) / 2.0 - linewidth, angle1, angle2);
cairo_stroke (cr);
cairo_set_source_rgba (cr, 0.0, 0.9, 0.0, 1.0);
cairo_set_line_width (cr, linewidth);
cairo_arc(cr, width/2.0, height/2.0, MIN (width, height) / 2.0 - linewidth, 180.0 * (M_PI/180.0),(declive*value+origin) * (M_PI/180.0) );
cairo_stroke (cr);
cairo_select_font_face (cr, "Roboto Thin", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, linewidth);
cairo_set_source_rgb (cr, 1.0, 1.0, 1);
cairo_text_extents (cr, unit, &extents);
x = width/2.0-(extents.width/2 + extents.x_bearing);
y = height/2.0 - (extents.height/2 );
cairo_move_to (cr, x, y);
cairo_show_text (cr, unit);
cairo_select_font_face (cr, "Roboto", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size (cr, linewidth*1.3);
sprintf(pcTemp,"%.1f",value);
cairo_text_extents (cr, pcTemp, &extentsTemp);
x = width/2.0-(extentsTemp.width/2 + extentsTemp.x_bearing);
y = height/2.0 - extentsTemp.y_bearing;
cairo_move_to (cr, x, y);
cairo_show_text (cr, pcTemp);
cairo_select_font_face (cr, "Roboto Thin", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, linewidth);
cairo_text_extents (cr, pcname, &extentsLabel);
x = width/2.0-(extentsLabel.width/2 + extentsLabel.x_bearing);
y = height/2.0 - extentsTemp.y_bearing - extentsLabel.y_bearing*1.20;
cairo_move_to (cr, x, y);
cairo_show_text (cr, pcname);
cairo_select_font_face (cr, "Roboto Thin", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, linewidth*0.5);
sprintf(pcTemp,"%.1f",min);
cairo_text_extents (cr, pcTemp, &extentsTempMin);
x = width/2.0 - MIN (width, height) / 2.0 + linewidth - (extentsTempMin.width/2 + extentsTempMin.x_bearing);
y = height/2.0 - extentsTempMin.y_bearing*1.20;
cairo_move_to (cr, x, y);
cairo_show_text (cr, pcTemp);
cairo_select_font_face (cr, "Roboto Thin", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, linewidth*0.5);
sprintf(pcTemp,"%.1f",max);
cairo_text_extents (cr, pcTemp, &extentsTempMax);
x = width/2.0 + MIN (width, height) / 2.0 - linewidth + (-extentsTempMax.width/2 + extentsTempMax.x_bearing);
y = height/2.0 - extentsTempMax.y_bearing*1.20;
cairo_move_to (cr, x, y);
cairo_show_text (cr, pcTemp);
return TRUE;
}
结果是this
GtkWidget *drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, 100, 100);
gtk_box_pack_start (GTK_BOX(gtk_builder_get_object(builder, "box30")),drawing_area,FALSE,TRUE,0);
我创建了一个绘图区并请求了尺寸,但我没有得到这个尺寸。
所以我的问题是:
如何更新绘图区域内的数据(生成绘图事件??)?
为什么我不能请求绘图区域小部件的大小?
欢迎提出意见。
回答
1) 每次更新数据时,强制绘制更新:
gtk_widget_queue_draw(GTK_WIDGET(drawing_area))
2) 您可以请求一个大小,但如果容器设置为展开,则小部件最终可以展开; set_size_request function/method 将设置绘图区域的最小尺寸 "have"。从您的代码中我们可以看到,绘图区域位于 GtkBox 内。检查展开和填充标志。
提示 1:您可以在 GtkFixed 容器中使用 drawing_area 来测试 set_size_request
提示 2:尝试创建一个自定义小部件,这将是一个更好的解决方案。
我正在使用 cairo 绘制一些圆形小部件,例如 this。
我使用"draw"绘图区事件绘制了所有的小部件,但我不知道如何更新小部件中的数据。 这是我编写的代码:
gboolean hald_circular_gauge (GtkWidget *widget,cairo_t *cr, gdouble max, gdouble min, gdouble value, gchar *pcname ,gchar *unit){
cairo_text_extents_t extents, extentsTemp, extentsLabel, extentsTempMin, extentsTempMax;
int width, height;
gint percentage, linewidth;
double x,y;
gdouble declive = (360.0-180.0)/(max-min);
gdouble origin = 180.0 - declive*min;
gchar pcTemp[BUFSIZ];
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
double angle1 = 180.0 * (M_PI/180.0); /* angles are specified */
double angle2 = 360.0 * (M_PI/180.0); /* in radians */
if(min > value || value >max)
return FALSE;
linewidth = (MIN (width, height) / 2.0 * 30.0) / 100.0;
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6);
cairo_set_line_width (cr, linewidth);
cairo_arc(cr, width/2.0, height/2.0, MIN (width, height) / 2.0 - linewidth, angle1, angle2);
cairo_stroke (cr);
cairo_set_source_rgba (cr, 0.0, 0.9, 0.0, 1.0);
cairo_set_line_width (cr, linewidth);
cairo_arc(cr, width/2.0, height/2.0, MIN (width, height) / 2.0 - linewidth, 180.0 * (M_PI/180.0),(declive*value+origin) * (M_PI/180.0) );
cairo_stroke (cr);
cairo_select_font_face (cr, "Roboto Thin", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, linewidth);
cairo_set_source_rgb (cr, 1.0, 1.0, 1);
cairo_text_extents (cr, unit, &extents);
x = width/2.0-(extents.width/2 + extents.x_bearing);
y = height/2.0 - (extents.height/2 );
cairo_move_to (cr, x, y);
cairo_show_text (cr, unit);
cairo_select_font_face (cr, "Roboto", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size (cr, linewidth*1.3);
sprintf(pcTemp,"%.1f",value);
cairo_text_extents (cr, pcTemp, &extentsTemp);
x = width/2.0-(extentsTemp.width/2 + extentsTemp.x_bearing);
y = height/2.0 - extentsTemp.y_bearing;
cairo_move_to (cr, x, y);
cairo_show_text (cr, pcTemp);
cairo_select_font_face (cr, "Roboto Thin", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, linewidth);
cairo_text_extents (cr, pcname, &extentsLabel);
x = width/2.0-(extentsLabel.width/2 + extentsLabel.x_bearing);
y = height/2.0 - extentsTemp.y_bearing - extentsLabel.y_bearing*1.20;
cairo_move_to (cr, x, y);
cairo_show_text (cr, pcname);
cairo_select_font_face (cr, "Roboto Thin", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, linewidth*0.5);
sprintf(pcTemp,"%.1f",min);
cairo_text_extents (cr, pcTemp, &extentsTempMin);
x = width/2.0 - MIN (width, height) / 2.0 + linewidth - (extentsTempMin.width/2 + extentsTempMin.x_bearing);
y = height/2.0 - extentsTempMin.y_bearing*1.20;
cairo_move_to (cr, x, y);
cairo_show_text (cr, pcTemp);
cairo_select_font_face (cr, "Roboto Thin", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, linewidth*0.5);
sprintf(pcTemp,"%.1f",max);
cairo_text_extents (cr, pcTemp, &extentsTempMax);
x = width/2.0 + MIN (width, height) / 2.0 - linewidth + (-extentsTempMax.width/2 + extentsTempMax.x_bearing);
y = height/2.0 - extentsTempMax.y_bearing*1.20;
cairo_move_to (cr, x, y);
cairo_show_text (cr, pcTemp);
return TRUE;
}
结果是this
GtkWidget *drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, 100, 100);
gtk_box_pack_start (GTK_BOX(gtk_builder_get_object(builder, "box30")),drawing_area,FALSE,TRUE,0);
我创建了一个绘图区并请求了尺寸,但我没有得到这个尺寸。 所以我的问题是:
如何更新绘图区域内的数据(生成绘图事件??)?
为什么我不能请求绘图区域小部件的大小?
欢迎提出意见。
回答
1) 每次更新数据时,强制绘制更新:
gtk_widget_queue_draw(GTK_WIDGET(drawing_area))
2) 您可以请求一个大小,但如果容器设置为展开,则小部件最终可以展开; set_size_request function/method 将设置绘图区域的最小尺寸 "have"。从您的代码中我们可以看到,绘图区域位于 GtkBox 内。检查展开和填充标志。
提示 1:您可以在 GtkFixed 容器中使用 drawing_area 来测试 set_size_request
提示 2:尝试创建一个自定义小部件,这将是一个更好的解决方案。