创建过程:
在GUI里配置好了一个大概的界面。聊天界面需要一个滑动页、一个输入框、一个文本框、一个发送按键。其中文本框属于滑动页,并且给发送按键添加上事件。
保存界面后,打开工程代码。
第一件事,是打开键盘使用的宏定义
随后,进入generated/events_init.c。在这里,可以看到我刚添加的事件:输出There is button
我对这个按键的要求是,要在按下时,把输入框的字符串发送给服务器,并且在屏幕右侧新增一条文本框,其中内容由输入框中的内容填充。
大概是这样的:
其中My_Create_label()是我自己封装的函数,用来创建新的文本框。
函数的三个参数分别是:文本内容、第几条消息、接收/发送(我这里设定的接收消息陈列在界面左侧,发送的消息在右侧)。
消息的label组件设置是直接从generated/setup_src_screen.c中对label_1的设定复制的,也就是我一开始在界面设置中写了Halo的那个文本。这可以确保,我的消息条的大小、风格都是一样的。这里我的发送和接收消息条设置了两个颜色,所以在其中用了一个if条件判断,分别对flags==0和flags==1做出不同的设置。
lv_obj_t * My_Create_label(char *text,int msg_count,int flags)
{
//首先,创建文本框,其父对象是滑动页
lv_obj_t * my_screen_label_1 = lv_label_create(guider_ui.screen_tileview_1_tile);
int x=0;//设置一个消息条的起始横坐标参数
if(flags ==0){//如何创建的消息条需求为接收到的消息
x=20;
lv_obj_set_style_bg_color(my_screen_label_1,lv_color_hex(0x00c53c),LV_PART_MAIN|LV_STATE_DEFAULT);
}else if (flags==1)
{
x=800-75-(strlen(text)*16);
if(x<=100){
x=100;//避免消息过长,超出界面
}
lv_obj_set_style_bg_color(my_screen_label_1, lv_color_hex(0xff7f50),LV_PART_MAIN|LV_STATE_DEFAULT);
}
lv_obj_set_pos(my_screen_label_1, x, 40+35*msg_count);//纵坐标按照消息的条数依次增加
lv_obj_set_size(my_screen_label_1, strlen(text)*16, 30);//尺寸大小按照文本内容和字体大小设置
lv_label_set_text(my_screen_label_1, text);
lv_label_set_long_mode(my_screen_label_1, LV_LABEL_LONG_WRAP);
//Write style for my_screen_label_1, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT.
lv_obj_set_style_border_width(my_screen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_radius(my_screen_label_1, 10, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_color(my_screen_label_1, lv_color_hex(0x000000), LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_font(my_screen_label_1, &lv_font_montserratMedium_24, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_opa(my_screen_label_1, 200, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_letter_space(my_screen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_line_space(my_screen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_align(my_screen_label_1, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(my_screen_label_1, 226, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_grad_dir(my_screen_label_1, LV_GRAD_DIR_NONE, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_pad_top(my_screen_label_1, 1, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_pad_right(my_screen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_pad_bottom(my_screen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_pad_left(my_screen_label_1, 8, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_shadow_width(my_screen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
return my_screen_label_1;
}
紧接着,我在这个源文件中创建了新线程,用于客户通信
void custom_init(lv_ui *ui)
{
pthread_t tid;
pthread_create(&tid, NULL, (void *)Client_net_pthread,NULL);
}
//客户网络通信的线程
int ckd;
void * Client_net_pthread(void * arg){
pthread_mutex_init(&my_custom_mutex, NULL);//初始化一个互斥锁
//1.创建套接字
ckd = socket(AF_INET, SOCK_STREAM, 0);
//2.连接服务器
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
addr.sin_addr.s_addr = inet_addr("139.196.139.147");
int ret = connect(ckd, (struct sockaddr *)&addr, sizeof(addr));
if(ret<0){
printf("connect error\n");
exit(0);
}
printf("connected\n");
//3.读取信息
char readbuff[1024];
while ((1))
{
memset(readbuff,0,sizeof(readbuff));
//pthread_mutex_lock(&lv_mutex_lock);
int retu = read(ckd,readbuff,sizeof(readbuff));
//pthread_mutex_unlock(&lv_mutex_lock);
if(retu==0){
printf("server close\n");
close(ckd);
exit(0);
}
count++;
printf("count==%d\n",count);
//加互斥锁
pthread_mutex_lock(&my_custom_mutex);
lv_obj_t* mylabel_2 = My_Create_label(readbuff,count,0);
lv_obj_move_foreground(mylabel_2);
lv_obj_scroll_to_view(mylabel_2,LV_ANIM_ON);
//解锁
pthread_mutex_unlock(&my_custom_mutex);
}
}
这里,我写入的服务器和端口号是乱写的o,记得更改。
因为LVGL本身并不支持多线程控制组件,所以我们在创建新消息条的前后,分别对一开始初始化的互斥锁执行了加锁和解锁。
但目前,我按键按下创建发送消息条时还没有加互斥锁。所以,我直接在main.c里执行这个环节。
到此,聊天界面的基础功能已经结构清晰,但防止优化导致的错误,我在Makefile文件中,更改了优化等级为0。