C语言 GTK3/Pango 实现生成动态福字应用
基于 C 语言开发一款桌面端工具,借助 GTK3 图形框架和 Pango 文本排版引擎,动态检索系统已安装的多种字体族,以网格形式生成并渲染带有背景的“福”字界面。用户可一键触发事件,使程序自动切换字体样式,满足个性化展示需求。
主要代码
第1步:定义数据结构与全局变量
首先需要声明显示用的字符串常量,以及用于存储 GUI 控件指针的二维数组。为了高效管理系统中的字体信息,定义结构体 custom_PangoFontFace_t 来记录每个字体家族(family)下的子字体面(face)数量与指针集合,并设置相关索引标识当前使用的状态。
#define FONT_DISPLAY "福"
// g_fu_label中的每一个控件都是一个福字
static GtkWidget *g_fu_label[3][3];
// 记录所有的字体family
typedef struct {
int n_faces;
PangoFontFace **faces;
}custom_PangoFontFace_t;
//字体family 的总数
static int n_families=0;
//当前正在使用的family 字体的索引
static int family_id=0;
// 记录每个字体family中的face(字模)
static custom_PangoFontFace_t *custom_PangoFontFace;
第2步:实现刷新回调函数
创建单击事件回调函数 change_fu_cb。该函数负责遍历 3×3 网格中的每个位置,根据当前的索引状态从字体池中选取下一个可用的字体描述对象。接着使用 Pango markup 语法组装包含特定字体属性与粗细的富文本字符串,最后将生成的标记化文本应用到对应的标签控件上,完成界面样式的即时更替。
static void
change_fu_cb(GtkButton *button , gpointer user_data)
{
char *markup_fu_str = NULL;
// 3*3 的矩阵中一共有9个福字,分别设置每个福字的字体
for(int i=0;i<3;++i)
{
for(int j=0;j<3;++j)
{
// 获取当前family中的下一个字模,如果当前family中的字模都是用了,自动更新family_id 指向下一个family
if(family_id >= n_families) family_id=0;
if(++face_id >= custom_PangoFontFace[family_id].n_faces){
++family_id;
if(family_id >= n_families)
family_id=0;
face_id = 0;
}
markup_fu_str = g_markup_printf_escaped("<span font-weight=\"Bold\" font_desc=\"%s 99\">%s</span>",
pango_font_description_to_string(pango_font_face_describe(custom_PangoFontFace[family_id].faces[0])),
FONT_DISPLAY);
gtk_label_set_markup(GTK_LABEL(g_fu_label[i][j]),markup_fu_str);
g_free(markup_fu_str);
}
}
}
第3步:构建应用程序初始化逻辑
在应用激活信号的处理函数 activate 中执行完整的界面搭建流程。首先创建窗口、主容器与覆盖层,并配置红黑配色的 CSS 样式表。随后调用 Pango API pango_font_map_list_families 扫描操作系统本地已安装的所有字体资源,填充之前定义的全局字体数据池。接下来在循环中初始化 9 个网格单元:为每个单元添加图片作为底图,并将无初始内容的标签覆盖在图片之上,实现图文分层。最后绑定按钮点击信号至刷新回调函数。
static void
activate (GtkApplication* app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *mainGrid;
GtkWidget *overlay;
GtkWidget *picture;
GtkCssProvider *cssProvider;
const char *cssMainGrid = "grid {background-color:#ed3c43;}";
const char *cssButton = "* {background-color:#FF0000;}";
PangoFontMap *pangoFontMap;
GtkWidget *box;
GtkWidget *button;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "");
gtk_window_set_default_size (GTK_WINDOW (window), 900, 900);
mainGrid = gtk_grid_new();
gtk_widget_set_hexpand(mainGrid,TRUE);
gtk_widget_set_vexpand(mainGrid,TRUE);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL,0);
gtk_widget_set_hexpand(box,TRUE);
gtk_widget_set_vexpand(box,TRUE);
gtk_box_append(GTK_BOX(box),mainGrid);
button = gtk_button_new_with_label("换一批");
gtk_widget_set_hexpand(button,TRUE);
gtk_widget_set_vexpand(button,TRUE);
cssProvider = gtk_css_provider_new();
gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(cssProvider),
cssButton,
-1);
gtk_style_context_add_provider(gtk_widget_get_style_context(button),
GTK_STYLE_PROVIDER(cssProvider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
gtk_style_context_add_provider(gtk_widget_get_style_context(gtk_widget_get_first_child(button)),
GTK_STYLE_PROVIDER(cssProvider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
g_object_unref(cssProvider);
g_signal_connect(button,"clicked",G_CALLBACK(change_fu_cb),NULL);
gtk_box_append(GTK_BOX(box),button);
gtk_window_set_child(GTK_WINDOW(window),box);
cssProvider = gtk_css_provider_new();
gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(cssProvider),
cssMainGrid,
-1);
gtk_style_context_add_provider(gtk_widget_get_style_context(mainGrid),
GTK_STYLE_PROVIDER(cssProvider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
g_object_unref(cssProvider);
//获取当前系统中可用的字体 family
PangoFontFamily **families;
pangoFontMap = pango_cairo_font_map_get_default();
pango_font_map_list_families(pangoFontMap,&families,&n_families);
custom_PangoFontFace = (custom_PangoFontFace_t *)g_malloc0(n_families*sizeof(custom_PangoFontFace_t));
for(int i=0;i<n_families;++i)
{
//获取每个字体 family 中可用的face
pango_font_family_list_faces(families[i],
&custom_PangoFontFace[i].faces,
&custom_PangoFontFace[i].n_faces);
}
g_free(families);
// 初始化每个福字控件
for(int i=0;i<3;++i)
{
for(int j=0;j<3;++j)
{
overlay = gtk_overlay_new();
gtk_widget_set_hexpand(overlay,TRUE);
gtk_widget_set_vexpand(overlay,TRUE);
// 福字的背景图,需要放在执行程序所在的目录
picture = gtk_picture_new_for_filename("./fu.png");
gtk_widget_set_hexpand(picture,TRUE);
gtk_widget_set_vexpand(picture,TRUE);
g_fu_label[i][j] = gtk_label_new("");
gtk_widget_set_hexpand(g_fu_label[i][j],TRUE);
gtk_widget_set_vexpand(g_fu_label[i][j],TRUE);
gtk_overlay_set_child(GTK_OVERLAY(overlay),picture);
gtk_overlay_add_overlay(GTK_OVERLAY(overlay),g_fu_label[i][j]);
gtk_grid_attach(GTK_GRID(mainGrid),overlay,i,j,1,1);
}
}
//初始化福字
change_fu_cb(GTK_BUTTON(button) , NULL);
gtk_window_set_resizable(GTK_WINDOW(window),FALSE);
gtk_widget_show (window);
}
完整源码
程序入口函数需实例化 GtkApplication,绑定激活信号,并通过消息循环运行应用。在退出前执行必要的资源回收逻辑,释放申请的字体结构与面数组内存。
int
main(int argc, char *argv[])
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
//释放资源
for(int i=0;i<n_families;++i){
g_free(custom_PangoFontFace[i].faces);
}
g_free(custom_PangoFontFace);
return status;
}
效果展示
以上就是 C语言结合 GTK3与Pango实现生成新春福字的详细内容,更多关于C语言生成动态福字的内容请持续关注本站相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













