1.GTK+简介
Linux
下大多数的开发都是基于字符界面的,但是在Linux
下也可以开发出美观大方的图形界面,其中较为常用的是Qt
和GTK+
;
为什么我们要在这里说GTK+
呢?
因为GTK+
使用C
语言作为开发语言,GTK+
是开放源代码而且免费的,简单易用,执行效率高,Linux
的桌面环境GNOME
就是建立在GTK+
的基础上;
2.GTK+的简单操作
2.1.Deeping安装GTK+
sudo apt-get install libgtk-3-dev
2.2如何编译写好的程序
首先使用GTK+
要加上头文件
#include <gtk/gtk.h>
然后在编译时加上
gcc gtk.c `pkg-config --libs --cflags gtk±2.0`
2.3创建一个简单的窗口
#include <stdio.h>
#include <gtk/gtk.h>
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
// 设置窗口
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
// 设置标题
gtk_window_set_title((GtkWindow *)window, "Hello World!");
// 设置窗口大小
gtk_widget_set_size_request(window, 400, 400);
// FALSE设置为不可伸缩,默认可伸缩
gtk_window_set_resizable((GtkWindow *)window, FALSE);
// 窗口在显示器位置,第二个参数GTK_WIN_POS_...4种NONE不固定 CENTER居中 MOUSE鼠标位置CENTER_ALWAYS总是居中
gtk_window_set_position((GtkWindow *)window, GTK_WIN_POS_MOUSE);
gtk_widget_show(window);
gtk_main();
return 0;
}
运行上面的程序就会出现一个这样的界面,但是这个界面点击右上角叉号后窗口是关闭了,但是程序并没有结束运行,需要我们ctrl+c
手动结束;
所以我们要用到一个函数,设置点击了这个按钮以后产生的反应;
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
这里的gtk_main_quit
就是点击以后产生的回调函数,这个就是用来终止gtk_main
的循环的;
gtk_main()
就相当于while(1)
如果不这样,那我们的创建的窗口闪一下就没了;
2.4创建一个按钮,把按钮加入到窗口中
#include <stdio.h>
#include <gtk/gtk.h>
int main(int argc, char *argv[])
{
// 窗口
GtkWidget *window;
// 按钮
GtkWidget *button;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request(window, 800, 800);
// 创建按钮
button = gtk_button_new_with_label("Hello World");
// 添加按钮到window
gtk_container_add((GtkContainer *)window, button);
// 获取按钮的内容
const char *result = gtk_button_get_label((GtkButton *)button);
printf("result = %s\n", result);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
在GTK+
中我们创建的控件一定要记得加入到窗口中,不然最后调用
gtk_widget_show_all(window)
的时候就不会显示了;
如果不设置控件的大小那么我们创建的这个按钮就会布满我们的整个窗口;
就像这样;
2.5GTK+预设的数据类型及回调函数
这里不说太多,gchar
什么和C
语言的char
没有什么区别;
我们来说一下gpointer
;
这个相当于C
语言的void *
这个用在设置回调函数的第二个参数;当我们按下一个按钮以后必然想要产生一些效果;这个时候就需要回调函数;
void callback(GtkButton *button, gpointer arg)
这是回调函数的类型;
g_signal_connect(控件, 操作, 回调函数, 传入的参数gpointer arg)
#include <stdio.h>
#include <gtk/gtk.h>
// 回调函数类型,gpointer 相当于void *
void fun(GtkButton *button, gpointer arg)
{
printf("hello world!!\n");
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button;
int a = 8;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request(window, 600, 600);
button = gtk_button_new_with_label("Hello!");
gtk_container_add((GtkContainer *)window, button);
// 调函数第二个参数是操作名称, 第三个参数是掉的函数名这里的clicked是点击,最后一个参数是传递的参数
g_signal_connect(button, "clicked", G_CALLBACK(fun), NULL);
// 点击关闭退出gtk_main_quit是库里用来退出gtk_main的
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
2.6布局
2.6.1水平布局
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *button1;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title((GtkWindow *)window, "Hello!");
gtk_widget_set_size_request(window, 600, 600);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
button = gtk_button_new_with_label("hello");
button1 = gtk_button_new_with_label("world");
// 创建一个水平布局容器,第二个参数是间距
hbox = gtk_hbox_new(TRUE, 5);
// 创建一个标签
GtkWidget *label = gtk_label_new("1");
GtkWidget *label1 = gtk_label_new("2");
// 先把hbox添加到window里
gtk_container_add((GtkContainer *)window, hbox);
// 再把两个按钮添加到水平容器hbox中
gtk_container_add((GtkContainer *)hbox, button);
gtk_container_add((GtkContainer *)hbox, button1);
gtk_container_add((GtkContainer *)hbox, label);
gtk_container_add((GtkContainer *)hbox, label1);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
当我们创建好一个布局时我们要将我们创建好的布局加入到窗口中,然后再将按钮添加到布局里;
2.6.2表格布局
把按钮加入到表格布局里用到的函数就不再是gtk_container_add()
了;而是
gtk_table_attach_defaults((GtkTable *)table, button, 0, 1, 0, 1);
后面的4个数字分别代表,左右上下;
如果我们要把这个放在第一个方框,后面的4个数字就是0, 1, 0, 1
;
2.6.3综合布局和行编辑
我们一般不会只简单使用一个布局通常我们要把几个布局合在一起使用,这里我们用一个小项目来体会一下;
当我们点击add
时加一个1
点击del
时删除文本框里的内容点击print
时打印文本框里的内容;
这里我们先来说这个行编辑;
创建一个行编辑:
GtkWidget *entry = gtk_entry_new();
获取行编辑里的内容
const gchar *str = gtk_entry_get_text(entry);
注意这里返回是const gchar *
所以当我们想向行编辑里面添加东西的时候我们不能单纯的使用strcat
函数
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
char text[1024];
strcpy(text, str);
strcat(text, "1");
gtk_entry_set_text(entry, text);
这个小项目的源代码在这里,可以自己先动手写一下;
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
void add(GtkButton *button, gpointer arg)
{
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
char text[1024];
strcpy(text, str);
strcat(text, "1");
gtk_entry_set_text(entry, text);
}
void del(GtkButton *button, gpointer arg)
{
GtkEntry *entry = (GtkEntry *)arg;
gtk_entry_set_text(entry, "");
}
void print(GtkButton *button, gpointer arg)
{
GtkEntry *entry = (GtkEntry *)arg;
const gchar *str = gtk_entry_get_text(entry);
printf("str = %s\n", str);
}
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title((GtkWindow *)window, "hello");
gtk_widget_set_size_request(window, 400, 600);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *button_add = gtk_button_new_with_label("add");
GtkWidget *button_del = gtk_button_new_with_label("del");
GtkWidget *button_print = gtk_button_new_with_label("print");
// 垂直布局
GtkWidget *vbox = gtk_vbox_new(TRUE, 5);
// 水平布局
GtkWidget *hbox = gtk_hbox_new(TRUE, 5);
// 行编辑
GtkWidget *entry = gtk_entry_new();
gtk_container_add((GtkContainer *)window, vbox);
gtk_container_add((GtkContainer *)vbox, entry);
gtk_container_add((GtkContainer *)vbox, hbox);
gtk_container_add((GtkContainer *)hbox, button_add);
gtk_container_add((GtkContainer *)hbox, button_del);
gtk_container_add((GtkContainer *)vbox, button_print);
g_signal_connect(button_add, "clicked", G_CALLBACK(add), entry);
g_signal_connect(button_del, "clicked", G_CALLBACK(del), entry);
g_signal_connect(button_print, "clicked", G_CALLBACK(print), entry);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
3.图形化计算器
如果把上面那个小项目写出来那么这个图形化的计算器应该很简单;就是按钮多了点,回调函数多了点,这里我们直接放源代码
// 计算器
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <math.h>
#include <stdlib.h>
#define EMPTY 0
#define NOEMPTY 1
#define MORE 1
#define LESS 0
// 运算数栈
typedef struct {
double num[1024];
int top;
} Num;
// 操作符栈
typedef struct {
char c[1024];
int top;
} Char;
/* --------------------------------- */
Num lnum;
Char lchar;
// 求次方的函数
double power(int n)
{
double a = 1;
if (n == 0) {
return 1;
}
n = n * (-1);
if (n > 0) {
for (int i = 0; i < n; i++) {
a /= 10;
}
return a;
}
}
// 判断栈不是为空
int Empty(int num) {
if (num == -1) {
return EMPTY;
} else {
return NOEMPTY;
}
}
// 操作数入栈
void PopNum(Num *lnum, double num)
{
lnum->num[++lnum->top] = num;
}
// 操作数出栈
void PushNum(Num *lnum, double *num)
{
*num = lnum->num[lnum->top--];
}
// 运算符入栈
void PopChar(Char *lchar, char x)
{
lchar->c[++lchar->top] = x;
}
// 运算符出栈
void PushChar(Char *lchar, char *x)
{
*x = lchar->c[lchar->top--];
}
// 比较运算符优先级
int Judge(char a, char b)
{
switch(a) {
case '+':
if (b == '+' || b == '-') {
return MORE;
} else {
return LESS;
}
case '-':
if (b == '-' || b == '+') {
return MORE;
} else {
return LESS;
}
case '*':
case '/':
return MORE;
default:break;
}
}
void Zero(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "0");
gtk_entry_set_text(entry, temp);
}
void One(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "1");
gtk_entry_set_text(entry, temp);
}
void Two(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "2");
gtk_entry_set_text(entry, temp);
}
void Three(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "3");
gtk_entry_set_text(entry, temp);
}
void Four(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "4");
gtk_entry_set_text(entry, temp);
}
void Five(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "5");
gtk_entry_set_text(entry, temp);
}
void Six(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "6");
gtk_entry_set_text(entry, temp);
}
void Seven(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "7");
gtk_entry_set_text(entry, temp);
}
void Eight(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "8");
gtk_entry_set_text(entry, temp);
}
void Nine(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "9");
gtk_entry_set_text(entry, temp);
}
void Point(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, ".");
gtk_entry_set_text(entry, temp);
}
void Add(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "+");
gtk_entry_set_text(entry, temp);
}
void Jian(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "-");
gtk_entry_set_text(entry, temp);
}
void Cheng(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "*");
gtk_entry_set_text(entry, temp);
}
void Chu(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
strcat(temp, "/");
gtk_entry_set_text(entry, temp);
}
void Clear(GtkButton *button, gpointer arg)
{
GtkEntry *entry = (GtkEntry *)arg;
gtk_entry_set_text(entry, "");
}
void Del(GtkButton *button, gpointer arg)
{
char temp[1024];
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
strcpy(temp, str);
int k = strlen(temp);
if (k > 0) {
temp[k-1] = '\0';
gtk_entry_set_text(entry, temp);
}
}
// 获取操作数栈顶元素
void GetTop(Char *lchar, char *x)
{
*x = lchar->c[lchar->top];
}
void Result(GtkButton *button, gpointer *arg)
{
GtkEntry *entry = (GtkEntry *)arg;
const char *str = gtk_entry_get_text(entry);
char temp[100];
double a = 0;
double b = 0;
char x;
int j = -1;
int k = strlen(str);
for (int i = 0; i < k; i++) {
if (str[i] >= '0' && str[i] <= '9') {
a = b = 0;
while (i < k && str[i] != '+' && str[i] != '-' && str[i] != '*' && str[i] != '/' && str[i] != '.') {
a = ((int)str[i] - 48) + a * 10;
i++;
}
if (i < k && str[i] == '.') {
i++;
while (str[i] != '+' && str[i] != '-' && str[i] != '*' && str[i] != '/' && i < k) {
b = ((int)str[i] - 48) * power(j) + b;
j--;
i++;
}
}
i--;
a += b;
PopNum(&lnum, a);
a = 0;
b = 0;
j = -1;
} else {
if (Empty(lchar.top) == EMPTY) {
PopChar(&lchar, str[i]);
} else {
GetTop(&lchar, &x);
while (Judge(x, str[i]) == MORE) {
PushChar(&lchar, &x);
PushNum(&lnum, &b);
PushNum(&lnum, &a);
switch(x) {
case '+':
a += b;
break;
case '-':
a -= b;
break;
case '*':
a *= b;
break;
case '/':
a /= b;
break;
default:break;
}
PopNum(&lnum, a);
a = 0;
b = 0;
if (Empty(lchar.top) == EMPTY) {
break;
}
GetTop(&lchar, &x);
}
PopChar(&lchar, str[i]);
}
}
}
PushChar(&lchar, &x);
PushNum(&lnum, &b);
PushNum(&lnum, &a);
switch(x) {
case '+':
a += b;
break;
case '-':
a -= b;
break;
case '*':
a *= b;
break;
case '/':
a /= b;
break;
default:break;
}
lchar.top = -1;
lnum.top = -1;
sprintf(temp, "%lf", a);
gtk_entry_set_text(entry, temp);
}
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
// 数据结构初始化
lnum.top = -1;
lchar.top = -1;
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title((GtkWindow *)window, "计算器");
gtk_widget_set_size_request(window, 400, 600);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
// 垂直布局
GtkWidget *vbox = gtk_vbox_new(TRUE, 10);
// 表格布局
GtkWidget *table = gtk_table_new(5, 4, TRUE);
// 行编辑
GtkWidget *entry = gtk_entry_new();
// 将垂直布局加入到window中
gtk_container_add((GtkContainer *)window, vbox);
// 将行编辑添加到垂直布局里
gtk_container_add((GtkContainer *)vbox, entry);
// 将表格布局添加到垂直布局里
gtk_container_add((GtkContainer *)vbox, table);
// 设置按钮
GtkWidget *button_clear = gtk_button_new_with_label("C");
GtkWidget *button_del = gtk_button_new_with_label("DEL");
GtkWidget *button_division = gtk_button_new_with_label("/");
GtkWidget *button_multiplication = gtk_button_new_with_label("*");
GtkWidget *button_subtraction = gtk_button_new_with_label("-");
GtkWidget *button_add = gtk_button_new_with_label("+");
GtkWidget *button_result = gtk_button_new_with_label("=");
GtkWidget *button_point = gtk_button_new_with_label(".");
GtkWidget *button1 = gtk_button_new_with_label("1");
GtkWidget *button2 = gtk_button_new_with_label("2");
GtkWidget *button3 = gtk_button_new_with_label("3");
GtkWidget *button4 = gtk_button_new_with_label("4");
GtkWidget *button5 = gtk_button_new_with_label("5");
GtkWidget *button6 = gtk_button_new_with_label("6");
GtkWidget *button7 = gtk_button_new_with_label("7");
GtkWidget *button8 = gtk_button_new_with_label("8");
GtkWidget *button9 = gtk_button_new_with_label("9");
GtkWidget *button0 = gtk_button_new_with_label("0");
// 将上面的按钮添加到表格布局中
gtk_table_attach_defaults((GtkTable *)table, button_clear, 0, 1, 0, 1);
gtk_table_attach_defaults((GtkTable *)table, button_del, 1, 2, 0, 1);
gtk_table_attach_defaults((GtkTable *)table, button_division, 2, 3, 0, 1);
gtk_table_attach_defaults((GtkTable *)table, button_multiplication, 3, 4, 0, 1);
gtk_table_attach_defaults((GtkTable *)table, button_subtraction, 3, 4, 1, 2);
gtk_table_attach_defaults((GtkTable *)table, button_add, 3, 4, 2, 3);
gtk_table_attach_defaults((GtkTable *)table, button_result, 3, 4, 3, 5);
gtk_table_attach_defaults((GtkTable *)table, button1, 0, 1, 3, 4);
gtk_table_attach_defaults((GtkTable *)table, button2, 1, 2, 3, 4);
gtk_table_attach_defaults((GtkTable *)table, button3, 2, 3, 3, 4);
gtk_table_attach_defaults((GtkTable *)table, button4, 0, 1, 2, 3);
gtk_table_attach_defaults((GtkTable *)table, button5, 1, 2, 2, 3);
gtk_table_attach_defaults((GtkTable *)table, button6, 2, 3, 2, 3);
gtk_table_attach_defaults((GtkTable *)table, button7, 0, 1, 1, 2);
gtk_table_attach_defaults((GtkTable *)table, button8, 1, 2, 1, 2);
gtk_table_attach_defaults((GtkTable *)table, button9, 2, 3, 1, 2);
gtk_table_attach_defaults((GtkTable *)table, button0, 0, 2, 4, 5);
gtk_table_attach_defaults((GtkTable *)table, button_point, 2, 3, 4, 5);
// 设置回调函数
g_signal_connect(button_add, "clicked", G_CALLBACK(Add), entry);
g_signal_connect(button_clear, "clicked", G_CALLBACK(Clear), entry);
g_signal_connect(button_del, "clicked", G_CALLBACK(Del), entry);
g_signal_connect(button_division, "clicked", G_CALLBACK(Chu), entry);
g_signal_connect(button_multiplication, "clicked", G_CALLBACK(Cheng), entry);
g_signal_connect(button_subtraction, "clicked", G_CALLBACK(Jian), entry);
g_signal_connect(button_point, "clicked", G_CALLBACK(Point), entry);
g_signal_connect(button_result, "clicked", G_CALLBACK(Result), entry);
g_signal_connect(button1, "clicked", G_CALLBACK(One), entry);
g_signal_connect(button2, "clicked", G_CALLBACK(Two), entry);
g_signal_connect(button3, "clicked", G_CALLBACK(Three), entry);
g_signal_connect(button4, "clicked", G_CALLBACK(Four), entry);
g_signal_connect(button5, "clicked", G_CALLBACK(Five), entry);
g_signal_connect(button6, "clicked", G_CALLBACK(Six), entry);
g_signal_connect(button7, "clicked", G_CALLBACK(Seven), entry);
g_signal_connect(button8, "clicked", G_CALLBACK(Eight), entry);
g_signal_connect(button9, "clicked", G_CALLBACK(Nine), entry);
g_signal_connect(button0, "clicked", G_CALLBACK(Zero), entry);
gtk_widget_show_all(window);
gtk_main();
return 0;
}