如何在linux下用gtk开发图形界面应用程序

如何在linux下用gtk开发图形界面应用程序,第1张

  使用 GTK+ 和 Glade 快速开发 Linux 图形界面

   GTK+ 简介

   基本概念

  GTK+ 是一种用于创建图形界面的库 嗯, gnome 用的就是它, 不过并不是说只

  有在 gnome 环境中才能用, 只要系统上装有 GTK 的库 (基本上有图形系统的个

  人机都会有的啦) 就能运行基于 GTK 的程序 除了 UNIX-like 平台, 它还移植

  到 windows 上, 还有面向嵌入设备的 framebuffer 版本等等

  GTK 依赖两个重要的库 一个是 GLib, 这并不是一个图形库, 也和 glibc 不同

  , 它大抵上提供了一些接口以屏蔽系统的不同, 比如 gint 在哪里都是 32bit

  的, 等等; 另一个是 GDK, 它是一个设备无关的图形库, 支持基本的画点, 以及

  与窗口管理器沟通等任务, 由于 GTK 被设计成能在各个平台, 而非仅仅在

  XWindow 环境下使用, 所以这个库也是必要的 而在他们上面的 GTK 库, 就提

  供了一些 widget --- 可以理解为控件啦, 不过窗口也是一个 widget 的说, 给

  我们使用, 并提供了包装良好的事件响应机制

   GTK+ 开发基础

  要开发基于 GTK 的软件, 必须先安装 GTK+ 的开发包 检查是否正确安装的办

  法是在安装后执行 ``pkg-config --cflags --libs gtk+-20'', 如果安装不正

  确, 会提示找不到相应的包

  GTK 本身是基于 C 的库, 当然也有 C++ 等语言的 wrap, 但它的整个体系是面

  向对象的 其最基本的类是 GObject, GtkObject 继承了它, GtkObject 又派生

  出我们最经常用到的 GtkWidget, 我们使用的所有窗体控件都派生于它 于是,

  在 C 环境中我们就要手动处理这些类转换, GTK 和底层的 GLib 等提供了一种

  统一的转换方法, 比如把类型为 GtkWidget 的 button 转换成 GtkButton 形,

  写法是: GTK_BUTTON(button), 就酱子

  我不打算在这里列一个 GTK 的 hello world 占页面, 这个程序随便 google 一

  下就能找到 我们可以自己想一想一个图形界面应该如何建立

  首先我们要进行初始化, GTK 提供了 gtk_init() 作为初始化, 它检查程序参数

  中的一些特定部分, 进行自己的设置 调用方法如下:

  gtk_init(&argc, &argv);

  将 argc 和 argv 传指针的目的是 gtk_init 会对他们进行加工, 把 GTK 自己

  用到的一些参数抽取出来

  接着, 我们必须要创建这些控件吧, GTK 中, 创建一个控件会返回一个

  GtkWidget 类型 (或它的派生类) 的指针, 所有创建控件的函数的格式是

  gtk_控件类型_new(参数表) 比如创建一个窗口的写法是:

  GtkWidget window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

  然后, 我们要设定事件响应函数, GTK 中的事件叫做 signal GTK 的事件响应

  函数接口应该是类似这样的

  void

  destroy(GtkWidget widget, gpointer data)

  我们把它连入到一个控件中的方法是这样的

  g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);

  应该很好理解吧

  我们创建的咚咚, 要说明他们的位置和包含关系, GTK 用 container 来解决这

  个问题, 它可以保证在窗口缩放的时候控件的摆放依然合理, container 的具体

  使用不详细说, 后面经常要跟 container 打交道, 但基本上不用管 C 代码, 嗯

   不过其实我们的任何的可视控件都继承自 container, 比如 button 也是一个

  container, 它很多时候装的是一个 GtkLabel, 也就是用来显示纯文本的控件,

  于是我们就能见到一个文本按钮, 嗯 使用 container 的方法如下

  gtk_container_add(GTK_CONTAINER(window), button);

  这样 button 就会占满整个 window 的控件, 我们后面可以看到可以用

  GtkVBox, GtkHBox 等 container 分隔窗体

  好了, 我们可以准备启动程序了, 我们可以用 gtk_widget_show() 来显示各个

  控件, 然后我们就应该进入到所谓的事件响应循环了, 这就要使用 gtk_main()

  在程序运行过程中, 我们要 *** 纵控件, 比如说我们要在一个 entry 控件(文本框

  ) 中取出其中的文字, 这样的 *** 作使用 gtk_控件类型_动作(对象, 参数) 的形

  式完成的, 比如刚才所说的任务, 做法是 gtk_entry_get_text(entry)

  顺便讲讲 GTK 程序的退出, 关闭 GTK 的窗口 (即使是所有窗口) 也不代表程序

  退出, 因为那说到底只是一个界面而已, 我们当然可以使用 exit() 的自爆法退

  出, 但最好还是给 GTK 一个料理后事的机会, 在主窗口的 destroy 事件响应函

  数上用 gtk_main_quit() 就好了

  编译 GTK 程序的办法也很简单

  gcc -o foo fooc `pkg-config --cflags --libs gtk+-20`

   使用 Glade 快速定制用户界面

  好了, 说了一堆有的没的, 如果我现在说我上面说的那一堆中的大部分我们都不

  会用到, 是不是觉得偶很歉扁 前面的介绍只是给大家 GTK 这个库的一些基本

  概念, 概念就好了, 我们倒真的不用拿这些来编程的 想想, 一个复杂一点的界

  面, 十几个控件, 再加上各种各样的 container, 自己挂事件, 再加上超常的命

  名, 想想都恐怖

  这时候, Glade 横空出世了! 这是一个可视化的界面编辑器 --- 但它仅仅是一

  个界面编辑器而已, 甚至连代码编辑框也没有给出 先不管了, 打开 glade (安

  装省略, 饶了我把, 记得装 libglade-dev), 应该很好懂了, 指指点点就能弄好

  一个界面, 然后在属性窗的信号一栏中选取需要的信号, 设定响应函数, 非常好

  弄

  玩了几分钟, 问题来了, 怎么把它变为程序啊 提供类似功能的 IDE 如

  Borland C++ Builder, 在点击创建新控件的时候, 我们能即使在代码窗看到自

  动生成的代码, Glade 也可以采用这种形式, 在设计好界面并保存后, 按一下主

  窗口的 build 按钮, 它就自动生成了界面代码, 根本不用自己写的 打开代码

  目录, callbacksc 里已经有自动创建的事件响应的空函数, 在里面填处理, 然

  后 configure make 就行了

  但是, 这样的开发方式还是有问题的 第一, 自动生成的代码非常复杂, 可是很

  多时候我们还是不能完全不看它, 处理和界面是混在一起了, 理解他们变得困难

  ; 其二, 由于以上的原因, 修改界面变得非常痛苦; 其三, 它给你生成那堆有的

  没的配置文件不一定是你想要的

  因此 glade 提供了另一种方法, glade 编辑所得的 glade 文件是一个 XML 文

  件, 其实它已经完整地描述了界面, 我们能否采用一种简单的方式直接载入, 配

  置它呢 这样做, 我们的代码中就真真正正地去处了烦人的界面生成代码, 而专

  注于处理部分了

  libglade 正是由于这个而来, 它能很好地完成上面所说的工作 当我们用

  glade 创建了一个 glade 界面后, 用这种方法我们就可以建立界面, 运行程序

  了

  #include <gtk/gtkh>

  #include <glade/gladeh>

  GladeXML GUI;

  int

  main(int argc, char argv)

  {

  gtk_init(&argc, &argv);

  / load the interface /

  GUI = glade_xml_new("frameglade", NULL, NULL);

  / connect the signals in the interface /

  glade_xml_signal_autoconnect(GUI);

  / start the event loop /

  gtk_main();

  return 0;

  }

  剩下的事情很简单, 如果你的 button 的 clicked 控件有一个响应函数

  on_button_clicked, 你写

  void

  on_button_clicked(GtkWidget widget, gpointer data)

  {

  // balabalabala

  }

  就可以了 所以, 上面讲的一堆创建界面的方法, 其实大部分时候都用不着

  由于用到了 libglade, 我们的编译方法变为

  gcc -o foo fooc `pkg-config --cflags --libs libglade-20`

   开发举例

  一个很简单的程序, 密码学对称加密算法要用到的, 如果说是界面, 就是三个文

  本框: 明文, 密码, 密文, 三个按钮, 加密, 解密, 清除, 完了 为了实验众多

  的算法, 我们加了一个下拉窗口, 用来选择算法 我把它设计成一个 wrapper

  和框架, 它不实现任何算法, 只是在界面中获取用户输入, 调用外部程序, 并把

  结果显示出来而已 这样, 实际的算法实现可以用纯 C 写的文本界面程序完成,

  移植起来很方便, 在 windows 随便做个一样的界面做前端就整个移植过去了

  于是, 我们需要的窗体元素是 GtkEntry, GtkComboBoxEntry, GtkButton, 查查

  手册, 我们用到的界面相关的函数只有以下几个:

  - gtk_entry_get_text(), 用于获取文本框输入

  - gtk_entry_set_text(), 用于在文本框中显示结果

  - gtk_combo_box_get_active_text(), 用于在 ComboBoxEntry (派生自

  ComboBox) 取出用户选中的算法

  另一个问题是, 他们都需要相应的对象指针做参数, 这应该怎样获得呢 我们使

  用 glade_xml_get_widget(GUI, "控件名") 就能取得控件了

你貌似没明白gtk的基础知识

单选按钮和复选按钮都是从按钮那个类派生出来的

  GObject

   +----GInitiallyUnowned

         +----GtkWidget

               +----GtkContainer

                     +----GtkBin

                           +----GtkButton

                                 +----GtkToggleButton

                                       +----GtkCheckButton

                                             +----GtkRadioButton

,所以回调函数和普通的按钮是一样的。所以我们的思路很简单,就是把每个按钮(单选/复选)加上回调函数,通过判断给回调函数传入的参数确定具体是那个按钮,回调函数原型是

 g_signal_connect(instance, detailed_signal, c_handler, data);

 //第一个参数是控件的名字,第二个参数是触发信号的名字,第三个参数是触发信号后传入  //的参数

举个例子

void button_clicked(GtkWidget widget, gpointer data)

{

   g_print("%d clicked\n", (int)data);

}

GtkRadioButton radio_button;

GtkRadioButton last_button;

int n = 0;

while (/ more buttons to add /)

  {

     radio_button = gtk_radio_button_new ();

     gtk_radio_button_join_group (radio_button, last_button);

     g_signal_connect(G_OBJECT(button), "clicked",  G_CALLBACK(button_clicked), (gpointer)n);

     n++;

     last_button = radio_button;

  }

复选按钮就不说了,和那个差不多。就把radiobutton 换成 checkbutton就好了,传什么参数自己定。

关于滚动条 我给你在我工程里面找几句代码,自己加在自己的demo里面就可以了

progressBar = gtk_hscale_new_with_range( 1, 100, 1);//最小值/最大值/步长

gtk_widget_set_size_request( progressBar, 480, 15 );//控件大小

gtk_scale_set_draw_value(GTK_SCALE(progressBar), TRUE);//是否显示当前值

gtk_scale_set_value_pos(GTK_SCALE(progressBar), GTK_POS_RIGHT);//显示当前值的位置

gtk_range_set_update_policy( GTK_RANGE(progressBar), GTK_UPDATE_DELAYED);//更新方式

g_signal_connect(G_OBJECT(progressBar),"value_changed",G_CALLBACK(on_progressBar_value_changed),NULL);//这里的触发信号名字用value_changed

void on_progressBar_value_changed( GtkWidget widget,gpointer gdata )

{

double val;

val = gtk_range_get_value(GTK_RANGE(progressBar));

n = val;

printf("%f\n", val );

}

音量的图标可以用系统图标。

完了。。。不知道再问

你用的是gtk+20,我习惯用30。我看你是在ubuntu上写的,那完全可以用gtk+-30阿。下面是我用30改写的代码,有注释。如果还有不清楚再问吧。

#include <gtk/gtkh>

typedef struct {

    GtkWidget window;

    GtkWidget combo;

} CallbackData;

static void on_login_button_clicked(GtkWidget  button, gpointer data);

static GtkWidget create_new_window(const gchar  text);

int main(int argc, char argv[])

{

    gtk_init(&argc, &argv);

    GtkWidget 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), 350, 350);

    gtk_window_set_title(GTK_WINDOW(window), "XX大学教务管理系统");

    gtk_container_set_border_width(GTK_CONTAINER(window), 120);

    g_signal_connect(G_OBJECT(window), "destroy",

                     G_CALLBACK(gtk_main_quit), NULL);

    GtkWidget box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    gtk_container_add(GTK_CONTAINER(window), box);

    GtkWidget label =

        gtk_label_new("欢迎进入XX大学教务管理系统");

    gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);

    label = gtk_label_new("请选择身份登录");

    gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);

    / 下面创建下拉按钮GtkComboBoxText,

      如果下拉框中只有文字的话,这样做就行了,

      如果还有那就要用到GtkComboBox和GtkTreeModel,

      具体这里就不说了/

    GtkWidget combo = gtk_combo_box_text_new();

    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo),

                                   "学生登录");

    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo),

                                   "教职工登录");

    gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo),

                                   "管理员登录");

    gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);

    gtk_box_pack_start(GTK_BOX(box), combo, FALSE, FALSE, 10);

    / 按钮 /

    GtkWidget button = gtk_button_new_with_label("登录");

    gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 40);

    static CallbackData cdata;

    cdatawindow = window;

    cdatacombo = combo;

    g_signal_connect(G_OBJECT(button), "clicked",

                     G_CALLBACK(on_login_button_clicked), &cdata);

    gtk_widget_show_all(window);

    gtk_main();

    return 0;

}

static void on_login_button_clicked(GtkWidget  button, gpointer data)

{

    CallbackData cdata = (CallbackData ) data;

    GtkWidget combo = cdata->combo;

    GtkWidget window = cdata->window;

    gchar text =

        gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));

    GtkWidget new_window = create_new_window(text);

    / 先屏蔽回调函数再删除原有窗口 /

    g_signal_handlers_block_by_func(G_OBJECT(window), gtk_main_quit, NULL);

    gtk_widget_destroy(window);

    / 不删除原有窗口,只是隐藏 /

    /gtk_widget_hide(window); /

    / 显示新窗口 /

    gtk_widget_show_all(new_window);

    g_free(text);

}

static GtkWidget create_new_window(const gchar  text)

{

    GtkWidget window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    gtk_window_set_title(GTK_WINDOW(window), text);

    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_MOUSE);

    gtk_window_set_default_size(GTK_WINDOW(window), 360, 250);

    g_signal_connect(G_OBJECT(window), "destroy",

                     G_CALLBACK(gtk_main_quit), NULL);

    return window;

}

GdkCursor pCursor = gdk_cursor_new(GDK_HAND1);

gdk_window_set_cursor(widget->window, pCursor);

gdk_cursor_destroy(pCursor);

pCursor=NULL;

你可以用gtk_widget_hide(windowi)使第i个界面隐藏 也可以用gtk_widget_destory(window) ,这个函数一般用于关闭子窗口 子界面 具体怎么用你再看看吧 呵呵 其实界面多的话可以用notebook控件 也就是笔记本控件 可以省却很多窗口关闭 打开的麻烦!!!你把界面做在笔记本的不同页面里面,再用gtk_set_current_page(notebook,n)就可以调用相应页面的界面了

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/12180927.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存