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-&gt;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_memdupg_free。还显示更多代码确实会有所帮助(最小的可编译示例)。 我有一个类似的问题,我从另一个线程中更新状态栏 - 不执行此状态更新删除了严重的错误消息 - 但是,我怎样才能安全地从线程中更新我的状态栏???

以上是关于gtk绘图实时更新的主要内容,如果未能解决你的问题,请参考以下文章

如果使用 Glade 进行绘图,GtkDrawingArea 不会更新

Gtk::Label 更新标签速度

实时移动 GTK+ 窗口

带有g_timeout_add服务的GTK3并不总是更新GTK小部件

gtk 窗口停止更新,即使应用程序似乎正在运行

时间变化时更新 Gtk.Label dynamicall