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;
}