gtk绘图实时更新
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gtk绘图实时更新相关的知识,希望对你有一定的参考价值。
我要把下位机实时采集的数据,通过绘图实时显示到屏幕上,用c写,gtk编程,做一个界面,把串口读来的数据绘图显示并实时更新,有哪位大神有程序给我参考一下
参考技术A 以下是个人测试程序第一版,有较多问题,但基本能运行,rs232.h 和rs232.c可以在网上找到//main.c
#include<stdio.h>
#include<stdlib.h>
#include<gtk/gtk.h>
#include"rs232.h"
#include<pthread.h>
#include<unistd.h>
#include"plot.h"
GtkWidget *window;
GtkBuilder *builder;
GtkWidget *openbt,*sendbt,*comportin,*baudratein,*databit,*stopbitin,*checkin;
GtkWidget *display,*input_send;
GtkWidget *da;
float volshow[500];
float xdata[500];
int get_data_count;
int port_opened;
int cport_n;
pthread_t thread1;
char text[2000];
GString *datatext;
int connected;
static cairo_surface_t *surfacd = NULL;
int data_count;
static void *read_thread(void *pdata)
int len;
unsigned char buf[256];
char m[10];
int di;
data_count = 0;
get_data_count = 0;
GtkWidget *da1 = (GtkWidget *)pdata;
while(1)
if(port_opened)
len = RS232_PollComport(cport_n, buf, 256);
if(len > 7)
int k = 0;
for(k = 0;k<len-7;k++)
if((buf[k] == 0xff) && (buf[k+1] == 0xff) && (buf[k+2] == 0xff) && (buf[k+3] == 0xff))
if(get_data_count<500)
volshow[get_data_count] = (buf[k+4] + buf[k+5] * 256)*0.000806;
get_data_count ++;
else
int ik;
for(ik = 0;ik<499;ik++)
volshow[ik] = volshow[ik+1];
volshow[499] = (buf[k+4] + buf[k+5] * 256)*0.000806;
void send_clicked(GtkWidget *widget,gpointer data)
connected = 0;
if(!port_opened)
return;
printf("send data\n");
unsigned char sdata[4];
sdata[0] = 0x02;
sdata[1] = 0x01;
RS232_SendBuf(cport_n,sdata,2);
//usleep(100);
static gboolean draw_cb(GtkWidget *w,cairo_t *cr,gpointer data)
surfacd = gdk_window_create_similar_surface(gtk_widget_get_window(w),CAIRO_CONTENT_COLOR,gtk_widget_get_allocated_width(w),gtk_widget_get_allocated_height(w));
cairo_set_source_surface(cr,surfacd,0,0);
plot_xy(cr, gtk_widget_get_allocated_width(w),gtk_widget_get_allocated_height(w),xdata,volshow,1,499);
cairo_stroke(cr);
return TRUE;
void open_clicked(GtkWidget *widget,gpointer data)
connected = 0;
//printf("open clecked \n");
char mode[]='8','N','1',0;
int bdrate=115200;
if(port_opened ==1)
port_opened = 0;
printf("port closeed \n");
return;
else
char *strport = (char *) gtk_combo_box_text_get_active_text ((GtkComboBoxText *)comportin);
if(strncmp(strport,"USB0",4) == 0)
cport_n = 16;
if(RS232_OpenComport(cport_n, bdrate, mode))
printf("Can not open comport\n");
return(0);
port_opened = 1;
printf("port opened ! creating read thread......\n");
pthread_create(&thread1,NULL,read_thread,(void *)da);
printf("thread created!\n");
void build_ui()
builder = gtk_builder_new();
gtk_builder_add_from_file(builder,"comui.glade",NULL);
window = (GtkWidget*)gtk_builder_get_object(builder,"window1");
g_signal_connect(window,"destroy", G_CALLBACK (gtk_main_quit), NULL);
openbt = (GtkWidget*)gtk_builder_get_object(builder,"button1");
g_signal_connect(openbt,"clicked",G_CALLBACK(open_clicked),NULL);
sendbt = (GtkWidget*)gtk_builder_get_object(builder,"button2");
g_signal_connect(sendbt,"clicked",G_CALLBACK(send_clicked),NULL);
comportin = (GtkWidget*)gtk_builder_get_object(builder,"comboboxtext1");
display = (GtkWidget*)gtk_builder_get_object(builder,"label6");
da = (GtkWidget *)gtk_builder_get_object(builder,"drawingarea1");
g_signal_connect(da,"draw",G_CALLBACK(draw_cb),NULL);
//buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(display));
//gtk_text_buffer_set_text(buffer,"wellcome to comtest!",-1);
gtk_widget_show_all(window);
gboolean timer(gpointer data)
gtk_widget_queue_draw(da);
return TRUE;
int main(int argc,char *argv[])
int di = 0;
GTimer *tim = g_timer_new();
for(di = 0;di<500;di++)
xdata[di] = di;
volshow[di] = di * 2 * 0.000806;
// printf(" %f | %f \n",xdata[di],volshow[di]);
datatext = g_string_new ("hello, this is com: \n");
port_opened = 0;
gtk_init(&argc,&argv);
build_ui();
//g_timeout_add_seconds(1,(GSourceFunc)timer,tim);
g_timeout_add(200,timer,NULL);
gtk_main();
return 0;
//plot.c
#include"plot.h"
double max_arr(double x[],int lenth)
double res = x[0];
int i;
for(i = 0;i<lenth;i++)
//if(x[i] != 0)
//printf("%f \n",x[i]);
if(res < x[i])
res = x[i];
return res;
double min_arr(double x[],int lenth)
double res = x[0];
int i;
for(i = 0;i<lenth;i++)
if(res > x[i])
res = x[i];
return res;
void plot_xy(cairo_t *cr,int w,int h,double x[],double y[],int type,int datanum)
int startx = w/10;
int starty = h/10;
int endx = w - startx;
int endy = h - starty;
cairo_set_source_rgb(cr,250,0,0);
cairo_move_to(cr,startx,starty);
cairo_line_to(cr,startx,endy);
cairo_line_to(cr,endx,endy);
cairo_set_source_rgb(cr,0,0,250);
char dstr[20];
double minx,miny,maxx,maxy;
minx = 0.0;//min_arr(x,datanum);
miny = 0.0;//min_arr(y,datanum);
maxx = max_arr(x,datanum);
// printf("%f || %f \n",max_arr(x,datanum),max_arr(y,datanum));
maxy = 100;//max_arr(y,datanum);
//printf("%f",minx);
int imd;
int i,j;
for(i = 1;i<10;i++)
cairo_move_to(cr,startx ,starty * i);
cairo_line_to(cr,startx + startx/8,starty * i);
cairo_move_to(cr,0,starty * i);
sprintf(dstr,"%f",maxy - (i - 1.00) * (maxy - miny)/8.00);
cairo_show_text(cr,dstr);
cairo_set_source_rgb(cr,200,0,200);
for(j = 1;j<10;j++)
cairo_move_to(cr,startx * j,endy);
cairo_line_to(cr,startx * j,endy - starty/8);
cairo_move_to(cr,startx * j,endy + starty - starty/5);
sprintf(dstr,"%f",minx + (j - 1.00) * (maxx - minx)/8.00);
cairo_show_text(cr,dstr);
//printf("plot xy\n");
if(type == 1)
for(imd = 0;imd<datanum - 1;imd++)
cairo_move_to(cr,startx + imd * (w)/500,endy - (y[imd] - miny) * starty * 8/(maxy - miny) );
cairo_line_to(cr,startx + (imd + 1) * (w)/500,endy - (y[imd+1] - miny) * (starty * 8)/(maxy - miny) );
else if(type == 0)
void hinst_bar(cairo_t *cr,int w,int h,double data[],int bar_div,int datanum)
本回答被提问者采纳 参考技术B #include <stdio.h>
#include <math.h>
#include <gtk/gtk.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>
gint i=0;/*外部变量声明区*/
gint j=0;
char buf[52];
char cpu[5];
char name2[1];
char name1;
struct label
GtkWidget *label1;
GtkWidget *label2;
;
void create_name()/*随机产生进程,并将名字显示*/
char name,the_max,the_min;
srand(i);
the_min='A';
the_max='z';
name=the_min+rand()%(the_max-the_min);
sprintf(name2,"%c",name);
strcat(buf,name2);
i++;
void decrease(GtkButton *button,gpointer data)
struct label *label0=(struct label*)data;
GtkWidget *label1=label0->label1;
GtkWidget *label2=label0->label2;
/*label1=label0->label1;
label2=label0->label2;*/
create_name();
j++;
sprintf(cpu,"%d",j);
gtk_label_set_text(label1,cpu);
gtk_label_set_text(label2,buf);
int main(int argc,char **argv)
GtkWidget *window;
GtkWidget *frame;
GtkWidget *minus;
static struct label *label0;
label0=g_malloc(sizeof(struct label));
gtk_init(&argc,&argv);
window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window),250,180);
gtk_window_set_title(GTK_WINDOW(window),"ceshi");
frame=gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window),frame);
minus=gtk_button_new_with_label("-");
gtk_widget_set_size_request(minus,80,35);
gtk_fixed_put(GTK_FIXED(frame),minus,50,80);
label0->label1=gtk_label_new("0");
gtk_fixed_put(GTK_FIXED(frame),label0->label1,190,35);
label0->label2=gtk_label_new("0");
gtk_fixed_put(GTK_FIXED(frame),label0->label2,190,95);
gtk_widget_show_all(window);
g_signal_connect(window,"destroy",
G_CALLBACK(gtk_main_quit),NULL);
g_signal_connect(minus,"clicked",G_CALLBACK(decrease),label0);
gtk_main();
return 0;
这只是一个测试程序,所以看的不必要纠结他是做什么的。追问
这个程序跟我问的问题有什么关系吗?
Gtk::Label 更新标签速度
【中文标题】Gtk::Label 更新标签速度【英文标题】:Gtk::Label update label speed 【发布时间】:2014-03-23 15:07:04 【问题描述】:我有一个程序试图以非常高的频率更新 Gtk::Label,并且表现出非常不稳定的行为。我收到了其中几个错误:
(gtkWindow:26559): Pango-CRITICAL **: pango_layout_copy: assertion 'PANGO_IS_LAYOUT (src)' failed
(gtkWindow:26559): Pango-CRITICAL **: pango_layout_set_width: assertion 'layout != NULL' failed
(gtkWindow:26559): Pango-CRITICAL **: pango_layout_get_pixel_extents: assertion 'PANGO_IS_LAYOUT (layout)' failed
(gtkWindow:26559): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed
直到程序最终崩溃:
Pango:ERROR:pango-layout.c:3916:pango_layout_check_lines: assertion failed: (!layout->log_attrs)
2921 中止(核心转储)
相关代码行:
while(1)
std::string sensorLine="";
_serial.readLine(&sensorLine); // read serial data with boost::asio
_output->set_label(sensorLine.data()); // _output -> Gtk::Label*
std::cout<<sensorLine<<std::endl;
//sleep(1);
如果我尝试使用_output->setlabel
,我只会收到错误消息,如果我评论这一行,一切都会顺利运行,输出会打印在控制台中。如果我在循环内调用sleep()
,也会发生同样的事情,Gtk::Label
会作为命令行更新,并且不会引发任何错误。
此循环在接收 _output 作为参数的单独线程上运行。
【问题讨论】:
说真的,对您提供给set_label
的数据进行完整性检查。它需要以空值结尾...
std::string
不是已经有这种检查了吗?
【参考方案1】:
将g_idle_add
(实际上是线程安全的)与回调一起实际修改(阅读:调用set_label
)你的GtkLabel
。
不要从不同的线程调用 UI 函数!永远不会!如果你打开了潘多拉的盒子。
【讨论】:
所以我应该放弃我的单独线程吗?还是先把数据传给g_idle_add
再调用set_label
?
这取决于传感器的 IO 是否长时间阻塞。如果是长时间操作(ms
的 10 秒),请使用单独的线程(循环并使用 g_idle_add
),否则您可以使用 g_timeout_add
并在回调中读取传感器。
现在我正在使用 g_idle_add
回调来读取由我的单独线程更新的共享 std::string*
,我遇到了几个分段错误和 Glib 错误。
嗯,您正在从 2 个不同的线程访问可能发生变化的数据。那会坏掉的。复制数据,只是 g_memdup
和 g_free
。还显示更多代码确实会有所帮助(最小的可编译示例)。
我有一个类似的问题,我从另一个线程中更新状态栏 - 不执行此状态更新删除了严重的错误消息 - 但是,我怎样才能安全地从线程中更新我的状态栏???以上是关于gtk绘图实时更新的主要内容,如果未能解决你的问题,请参考以下文章
如果使用 Glade 进行绘图,GtkDrawingArea 不会更新