类似于手机的滑屏解锁功能,只实现了简单的功能,现在还没有实现锁图大小的自适应适应功能和自己随意设置密码功能,需要在程序代码里先设置密码。
为了程序规范,创建一个 lock 文件夹,里面并包含 code、execute、image 三个文件夹。
1、在code里创建源代码文件:
main.c
#include "gtk_window.h"
WINDOW window;//定义结构体变量
int main (int argc, char *argv[])
{
gtk_init (&argc, &argv);
window_demo(&window); // 窗口的相关操作
gtk_main();
return 0;
}
gtk_window.c
#include "gtk_function.h"
#include "gtk_window.h"
int lock_image_place[9][4]={{250,325,90,165},
{360,435,90,165},
{470,545,90,165},
{250,325,200,275},
{360,435,200,275},
{470,545,200,275},
{250,325,310,385},
{360,435,310,385},
{470,545,310,385}};
int xy[9][2]={{288,128},
{398,128},
{508,128},
{288,238},
{398,238},
{508,238},
{288,348},
{398,348},
{508,348}};
int flag[]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int password[]={1,4,7,8,-2};
int count;
guint timer;
/*******************************************************************
* 函数功能:窗口控件的创建、设置、布局、信号连接
* 参数类型:data:WINDOW变量的地址
* 返回类型:无
********************************************************************/
void window_demo(gpointer data)
{
WINDOW *p_temp = (WINDOW *)data;
p_temp->main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); // 创建主窗口
gtk_window_set_title(GTK_WINDOW(p_temp->main_window), "window"); // 设置窗口标题
gtk_window_set_position(GTK_WINDOW(p_temp->main_window), GTK_WIN_POS_CENTER); // 设置窗口在显示器中的位置为居中
gtk_widget_set_size_request(p_temp->main_window, 800, 480); // 设置窗口的最小大小
gtk_window_set_resizable(GTK_WINDOW(p_temp->main_window), FALSE); // 固定窗口的大小
gtk_container_set_border_width(GTK_CONTAINER(p_temp->main_window), 1); // 窗口边距
chang_background(p_temp->main_window, 800, 480, "../image/background.jpg");// 设置主窗口背景图
gtk_widget_set_app_paintable(p_temp->main_window, TRUE); // 允许窗口可以绘图
p_temp->main_table = gtk_table_new(48, 80, TRUE);// 创建表格布局容器
gtk_container_add(GTK_CONTAINER(p_temp->main_window), p_temp->main_table);//把表格布局放入窗口
int i=0;
for(i=0;i<9;i++)
{
p_temp->lock_image[i]=image_new_from_file("../image/main.png",80,80);//创建锁点的图片
gtk_table_attach_defaults(GTK_TABLE(p_temp->main_table), p_temp->lock_image[i], 25+((i%3)*11), 33+((i%3)*11), 9+(i/3)*11, 17+(i/3)*11);//把锁点放入表格布局
}
gtk_widget_add_events(p_temp->main_window, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_RELEASE_MASK);// 窗口接收鼠标点击、移动、释放事件
g_signal_connect(p_temp->main_window, "motion-notify-event", G_CALLBACK(mouse_callback), p_temp);//接收鼠标滑动时间
g_signal_connect(p_temp->main_window, "button-release-event", G_CALLBACK(lock_callback), p_temp);//接收鼠标滑动时间
g_signal_connect(p_temp->main_window, "expose-event", G_CALLBACK(on_expose_event), p_temp);//曝光事件用于画线
gtk_widget_show_all(p_temp->main_window);//显示控件
}
/*******************************************************************
* 函数功能:鼠标处理回调函数
* 参数类型:widget:控件变量
event:鼠标信号
data:WINDOW变量的地址
* 返回类型:无
********************************************************************/
gboolean mouse_callback(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
WINDOW *p_temp = (WINDOW *)data;
int i=0;
p_temp->x=(int)event->x;
p_temp->y=(int)event->y;
for(i=0;i<9;i++)
{
if((p_temp->x>lock_image_place[i][0]&&p_temp->x<lock_image_place[i][1])&&(p_temp->y>lock_image_place[i][2]&&p_temp->y<lock_image_place[i][3]))//判断与锁点的坐标匹配
{
if(count==0)
{
load_image(p_temp->lock_image[i],"../image/right.png",80,80);
flag[0]=i;
count++;
}
else if(i!=flag[count-1]&&count<TOTAL_DOT)
{
load_image(p_temp->lock_image[i],"../image/right.png",80,80);
flag[count]=i;
count++;
}
}
}
return TRUE;
}
/*******************************************************************
* 函数功能:锁控制回调函数
* 参数类型:widget:控件变量
event:鼠标信号
data:WINDOW变量的地址
* 返回类型:无
********************************************************************/
gboolean lock_callback(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
WINDOW *p_temp = (WINDOW *)data;
int i=0;
while(flag[i]==password[i])//密码与输入匹配判断
i++;
if(password[i]==-2&&flag[i]<0)
{
for(i=0;i<count;i++)
{
load_image(p_temp->lock_image[flag[i]],"../image/main.png",80,80);
flag[i]=-1;//flag数组赋成-1,以备下次用
}
printf("****hello*****\n");
count=0;//赋成0,以备下次用
}
else
{
for(i=0;i<count;i++)
load_image(p_temp->lock_image[flag[i]],"../image/error.png",80,80);
timer=g_timeout_add(1500,(GSourceFunc)deal_time,data);
}
return TRUE;
}
/*******************************************************************
* 函数功能:曝光事件用于画线
* 参数类型:widget:控件变量
event:鼠标信号
data:WINDOW变量的地址
* 返回类型:无
********************************************************************/
gboolean on_expose_event(GtkWidget * widget, GdkEventExpose *event, gpointer data)
{
WINDOW *p_temp = (WINDOW *)data;
int i=0;
cairo_t *cr = gdk_cairo_create(widget->window); // 创建cairo环境
cairo_set_line_width(cr, 25); // 线宽设置
cairo_set_source_rgb(cr, 0, 1, 0); // 设置环境的前景色,暗红色
if(flag[0]>0&&flag[1]<0)
{
cairo_move_to(cr, xy[flag[0]][0], xy[flag[0]][1]); // 起点
cairo_line_to(cr, p_temp->x, p_temp->y); // 终点
cairo_stroke(cr); // 绘制cairo环境的路径
}
else if(flag[1]>-1)
{
for(i=0;i<count-1;i++)
{
cairo_move_to(cr, xy[flag[i]][0], xy[flag[i]][1]); // 起点
cairo_line_to(cr, xy[flag[i+1]][0], xy[flag[i+1]][1]); // 终点
cairo_stroke(cr); // 绘制cairo环境的路径
}
}
gtk_widget_queue_draw(p_temp->main_window); // 更新刷图区域
cairo_destroy(cr); // 回收所有Cairo环境所占用的内存资源
return FALSE;
}
/*******************************************************************
* 函数功能:定时器回调函数,用于把锁图恢复到开始状态
* 参数类型: data:WINDOW变量的地址
* 返回类型:TRUE:定时器继续工作,FALSE:定时器停止工作
********************************************************************/
gboolean deal_time(gpointer data)
{
WINDOW *p_temp = (WINDOW *)data;
int i=0;
for(i=0;i<count;i++)
{
load_image(p_temp->lock_image[flag[i]],"../image/main.png",80,80);
flag[i]=-1;//flag数组赋成-1,以备下次用
}
count=0;//赋成0,以备下次用
g_source_remove(timer);
return TRUE;
}
gtk_window.h
#ifndef _GTK_WINDOW_H_
#define _GTK_WINDOW_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <cairo.h> // 绘图所需要的头文件
#define TOTAL_DOT 20
typedef struct _window
{
GtkWidget *main_window;//主窗口
GtkWidget *main_table;//表格布局
GtkWidget *lock_image[9];//锁的图片
int x;//获取到的触摸坐标
int y;
}WINDOW;
/*******************************************************************
* 函数功能:窗口控件的创建、设置、布局、信号连接
* 参数类型:data:WINDOW变量的地址
* 返回类型:无
********************************************************************/
void window_demo(gpointer data);
/*******************************************************************
* 函数功能:鼠标处理回调函数
* 参数类型:widget:控件变量
event:鼠标信号
data:WINDOW变量的地址
* 返回类型:无
********************************************************************/
gboolean mouse_callback(GtkWidget *widget, GdkEventButton *event, gpointer data);
/*******************************************************************
* 函数功能:锁控制回调函数
* 参数类型:widget:控件变量
event:鼠标信号
data:WINDOW变量的地址
* 返回类型:无
********************************************************************/
gboolean lock_callback(GtkWidget *widget, GdkEventButton *event, gpointer data);
/*******************************************************************
* 函数功能:曝光事件用于画线
* 参数类型:widget:控件变量
event:鼠标信号
data:WINDOW变量的地址
* 返回类型:无
********************************************************************/
gboolean on_expose_event (GtkWidget * widget, GdkEventExpose * event, gpointer data);
/*******************************************************************
* 函数功能:定时器回调函数,用于把锁图恢复到开始状态
* 参数类型: data:WINDOW变量的地址
* 返回类型:TRUE:定时器继续工作,FALSE:定时器停止工作
********************************************************************/
gboolean deal_time(gpointer data);
#endif
gtk_function.c
#include "gtk_function.h"
/*******************************************************************
* 函数功能:设置背景图
* 参数类型:widget: 主窗口
w, h: 图片的大小
path: 图片路径
* 返回类型:无
********************************************************************/
void chang_background(GtkWidget *widget, int w, int h, const gchar *path)
{
gtk_widget_set_app_paintable(widget, TRUE); //允许窗口可以绘图
gtk_widget_realize(widget);
/* 更改背景图时,图片会重叠
* 这时要手动调用下面的函数,让窗口绘图区域失效,产生窗口重绘制事件(即 expose 事件)。
*/
gtk_widget_queue_draw(widget);
GdkPixbuf *src_pixbuf = gdk_pixbuf_new_from_file(path, NULL); // 创建图片资源对象
// w, h是指定图片的宽度和高度
GdkPixbuf *dst_pixbuf = gdk_pixbuf_scale_simple(src_pixbuf, w, h, GDK_INTERP_BILINEAR);
GdkPixmap *pixmap = NULL;
/* 创建pixmap图像;
* NULL:不需要蒙版;
* 123: 0~255,透明到不透明
*/
gdk_pixbuf_render_pixmap_and_mask(dst_pixbuf, &pixmap, NULL, 128);
// 通过pixmap给widget设置一张背景图,最后一个参数必须为: FASLE
gdk_window_set_back_pixmap(widget->window, pixmap, FALSE);
// 释放资源
g_object_unref(src_pixbuf);
g_object_unref(dst_pixbuf);
g_object_unref(pixmap);
}
/*******************************************************************
* 函数功能:创建一张图片
* 参数类型:image_path:图片路径
w, h: 图片的大小
* 返回类型:图片控件
********************************************************************/
GtkWidget *image_new_from_file(const char *image_path, int w, int h)
{
GtkWidget *image = NULL;
GdkPixbuf *src_pixbuf = NULL;
GdkPixbuf *dst_pixbuf = NULL;
src_pixbuf = gdk_pixbuf_new_from_file(image_path, NULL);//创建图片资源对象
dst_pixbuf = gdk_pixbuf_scale_simple(src_pixbuf, w, h, GDK_INTERP_BILINEAR);//设置图片大小
image = gtk_image_new_from_pixbuf(dst_pixbuf);//通过图片资源对象创建图片控件
g_object_unref(dst_pixbuf);//释放图片资源
if(NULL == image)
{
return NULL;
}
else
{
return image;
}
}
/*******************************************************************
* 函数功能:给创建好的image重新设计一张图片
* 参数类型:image: 图片控件
w, h: 图片的大小
file_path: 图片路径
* 返回类型:无
********************************************************************/
void load_image(GtkWidget *image, const char *file_path, const int w, const int h )
{
gtk_image_clear( GTK_IMAGE(image) ); // 清除图像
GdkPixbuf *src_pixbuf = gdk_pixbuf_new_from_file(file_path, NULL); // 创建图片资源
GdkPixbuf *dest_pixbuf = gdk_pixbuf_scale_simple(src_pixbuf, w, h, GDK_INTERP_BILINEAR); // 指定大小
gtk_image_set_from_pixbuf(GTK_IMAGE(image), dest_pixbuf); // 图片控件重新设置一张图片(pixbuf)
g_object_unref(src_pixbuf); // 释放资源
g_object_unref(dest_pixbuf); // 释放资源
}
gtk_function.h
#ifndef _GTK_FUNCTION_H_
#define _GTK_FUNCTION_H_
#include <gtk/gtk.h>
/*******************************************************************
* 函数功能:设置背景图
* 参数类型:widget: 主窗口
w, h: 图片的大小
path: 图片路径
* 返回类型:无
********************************************************************/
void chang_background(GtkWidget *widget, int w, int h, const gchar *path);
/*******************************************************************
* 函数功能:创建一张图片
* 参数类型:image_path:图片路径
w, h: 图片的大小
* 返回类型:图片控件
********************************************************************/
GtkWidget *image_new_from_file(const char *image_path, int w, int h);
/*******************************************************************
* 函数功能:给创建好的image重新设计一张图片
* 参数类型:image: 图片控件
w, h: 图片的大小
file_path: 图片路径
* 返回类型:无
********************************************************************/
void load_image(GtkWidget *image, const char *file_path, const int w, const int h );
#endif
Makefile
SRC := #
SRC += main.c
SRC += gtk_function.c
SRC += gtk_window.c
#OBJ := $(subst .c,.o,$(SRC))
OBJ = $(SRC:%.c=%.o)
CC = gcc
FLAG = -Wall `pkg-config --cflags --libs gtk+-2.0`
EXEC_NAME = ../execute/demo
EXEC_PATH = .
.PHONY:clean call
call:$(OBJ)
@echo make ...
$(CC) $^ -o $(EXEC_PATH)/$(EXEC_NAME) $(FLAG)
@echo make over
@echo Execute target is $(EXEC_PATH)/$(EXEC_NAME)
$(OBJ):%.o:%.c
$(CC) -c -o $@ $< $(FLAG)
clean:
@echo clean ...
rm $(EXEC_PATH)/$(EXEC_NAME) *.o -rf
@echo clean over
2、在image文件夹里放如下图片及对应名称:
background.jpg main.png right.png error.png
3、在code目录下执行make命令,便在execute目录下生成demo的可执行程序。
4、运行程序后用鼠标滑动密码出现效果图如下:
输入正确的密码 (密码正确终端会输出*****hello******) 输入错误的密码
附:配置gtk编译环境
1、安装
sudo apt-get install libgtk2.0*
#gtk+2.0所需的所有文件统通下载安装完毕。
2、测试
运行:
pkg-config --cflags --libs gtk+-2.0
现象:
-pthread -I/usr/local/include/gio-unix-2.0/ -I/usr/local/include/atk-1.0 -I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include -I/usr/include/gtk-2.0
-I/usr/include/pango-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/freetype2 -I/usr/include/pixman-1 -I/usr/include/libpng12
说明成功