由于gtk+是采用C语言写的,个人认为做界面还是用C++比较方便,可能是因为我用MFC用的多的原因吧。那么如果用GTK+开发的话,我们做一个位图按钮,怎么做呢?大家都知道在MFC下,需要自己重写一个继承自CButton得按钮类,在DrawItem虚函数中进行按钮的绘制。网上有很多人用C语言的方式实现了位图按钮,如果一个界面上按钮很多的话,代码量可想而知。好在C++的类在代码重用方面比较好。
废话少说,进入正题
/* author: Allen Wang * data: 2009/10/27 */ #ifndef __MY_BUTTON__ #define __MY_BUTTON__ #include "stdafx.h" typedef void (*callback_t)(GtkWidget *,gpointer); //define the reference of a button struct ButtonRef { GtkWidget *button; //normal button GtkWidget *image; //image object GdkPixmap *pixmap; //pixmap of bg GdkPixbuf *pixbuf; //pixbuf of bg GdkFont *font; //font of label char label[100]; //label of button int width; //width of button int height; //height of button int font_width; //width of label int font_height; //height of label int font_x; //x coridation of label int font_y; //y coridation of label callback_t func_clicked; //call back func of button callback_t func_entered; //call back func of button callback_t func_leaved; //call back func of button callback_t func_pressed; //call back func of button callback_t func_released; //call back func of button callback_t func_actived; //call back func of button void * data_clicked; //call back data of button void * data_entered; //call back data of button void * data_leaved; //call back data of button void * data_pressed; //call back data of button void * data_released; //call back data of button void * data_actived; //call back data of button }; // a own button class class CMyButton { public: CMyButton(GtkWidget *button,char *image, callback_t func_clicked = NULL, void * data_clicked = NULL, callback_t func_entered = NULL, void * data_entered = NULL, callback_t func_leaved = NULL, void * data_leaved = NULL, callback_t func_released = NULL, void * data_released = NULL, callback_t func_pressed = NULL, void * data_pressed = NULL, callback_t func_actived = NULL, void * data_actived = NULL); public: ~CMyButton(); public: void SetLabel(char *label); char* GetLabel(); private: void ConnectSignals(); void Init(GtkWidget *button,char *image); private: static void Draw(GtkWidget *widget,GdkEventButton *event,gpointer data,int state); static void ButtonEntered(GtkWidget *widget,GdkEventButton *event,gpointer data); static void ButtonLeaved(GtkWidget *widget,GdkEventButton *event,gpointer data); static void ButtonPressed(GtkWidget *widget,GdkEventButton *event,gpointer data); static void ButtonReleased(GtkWidget *widget,GdkEventButton *event,gpointer data); public: GtkWidget *m_EventBox; private: enum{ IMAGE_NORMAL, IMAGE_PRESSED, IMAGE_ENTERED, IMAGE_DISABLE }; ButtonRef m_ButtonRef; }; #endif //__MY_BUTTON__
#include "stdafx.h" #include <string.h> #include "MyButton.h" CMyButton::CMyButton(GtkWidget *button,char *image, callback_t func_clicked, void * data_clicked, callback_t func_entered, void * data_entered, callback_t func_leaved , void * data_leaved, callback_t func_released, void * data_released, callback_t func_pressed, void * data_pressed, callback_t func_actived, void * data_actived) { if(image) { m_ButtonRef.func_clicked = func_clicked; m_ButtonRef.func_entered = func_entered; m_ButtonRef.func_leaved = func_leaved; m_ButtonRef.func_pressed = func_pressed; m_ButtonRef.func_released = func_released; m_ButtonRef.func_actived = func_actived; m_ButtonRef.data_clicked = data_clicked; m_ButtonRef.data_entered = data_entered; m_ButtonRef.data_leaved = data_leaved; m_ButtonRef.data_pressed = data_pressed; m_ButtonRef.data_released = data_released; m_ButtonRef.data_actived = data_actived; //hide the button gtk_widget_hide(button); //initialization Init(button,image); //draw normal Draw(m_EventBox,NULL,&m_ButtonRef,IMAGE_NORMAL); //connect signals ConnectSignals(); } } CMyButton::~CMyButton() { if (m_ButtonRef.pixmap) gdk_pixmap_unref(m_ButtonRef.pixmap); if(m_ButtonRef.pixbuf) gdk_pixbuf_unref(m_ButtonRef.pixbuf); } void CMyButton::ConnectSignals() { g_signal_connect(G_OBJECT(m_EventBox),"enter_notify_event",G_CALLBACK(ButtonEntered),&m_ButtonRef); g_signal_connect(G_OBJECT(m_EventBox),"leave_notify_event",G_CALLBACK(ButtonLeaved),&m_ButtonRef); g_signal_connect(G_OBJECT(m_EventBox),"button_press_event",G_CALLBACK(ButtonPressed),&m_ButtonRef); g_signal_connect(G_OBJECT(m_EventBox),"button_release_event",G_CALLBACK(ButtonReleased),&m_ButtonRef); } void CMyButton::ButtonEntered(GtkWidget *widget,GdkEventButton *event,gpointer data) { Draw(widget,event,data,IMAGE_ENTERED); //respond the clicked signal if((((ButtonRef*)data)->func_entered)) (((ButtonRef*)data)->func_entered)(((ButtonRef*)data)->button,((ButtonRef*)data)->data_entered); } void CMyButton::ButtonLeaved(GtkWidget *widget,GdkEventButton *event,gpointer data) { Draw(widget,event,data,IMAGE_NORMAL); //respond the clicked signal if((((ButtonRef*)data)->func_leaved)) (((ButtonRef*)data)->func_leaved)(((ButtonRef*)data)->button,((ButtonRef*)data)->data_leaved); } void CMyButton::ButtonPressed(GtkWidget *widget,GdkEventButton *event,gpointer data) { Draw(widget,event,data,IMAGE_PRESSED); //respond the clicked signal if((((ButtonRef*)data)->func_clicked)) (((ButtonRef*)data)->func_clicked)(((ButtonRef*)data)->button,((ButtonRef*)data)->data_clicked); } void CMyButton::ButtonReleased(GtkWidget *widget,GdkEventButton *event,gpointer data) { Draw(widget,event,data,IMAGE_NORMAL); //respond the clicked signal if((((ButtonRef*)data)->func_released)) (((ButtonRef*)data)->func_released)(((ButtonRef*)data)->button,((ButtonRef*)data)->data_released); } void CMyButton::Draw(GtkWidget *widget,GdkEventButton *event,gpointer data,int state) { //remove the image from the eventbox gtk_container_remove(GTK_CONTAINER(widget), ((ButtonRef*)data)->image); //cut pixels from the pixbuf to pixmap gdk_pixbuf_render_to_drawable(((ButtonRef*)data)->pixbuf, ((ButtonRef*)data)->pixmap, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], state * ((ButtonRef*)data)->width,0,0,0, ((ButtonRef*)data)->width, ((ButtonRef*)data)->height, GDK_RGB_DITHER_NORMAL,0,0); // draw button's label if(((ButtonRef*)data)->label) { gdk_draw_string(((ButtonRef*)data)->pixmap, ((ButtonRef*)data)->font, widget->style->black_gc, ((ButtonRef*)data)->font_x, ((ButtonRef*)data)->font_y, ((ButtonRef*)data)->label); } //create new pixbuf GdkPixbuf * pixbuf = NULL; pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, ((ButtonRef*)data)->width, ((ButtonRef*)data)->height); pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, ((ButtonRef*)data)->pixmap, gdk_colormap_get_system(), 0,0,0,0, ((ButtonRef*)data)->width,((ButtonRef*)data)->height); //create new image object GdkBitmap *bitmap; ((ButtonRef*)data)->image = gtk_image_new_from_pixbuf(pixbuf); gtk_widget_set_usize(((ButtonRef*)data)->image,((ButtonRef*)data)->width,((ButtonRef*)data)->height); gdk_pixbuf_render_pixmap_and_mask(pixbuf, NULL, &bitmap,128); gtk_widget_shape_combine_mask(widget,bitmap,0,0); //add and show gtk_container_add(GTK_CONTAINER(widget),((ButtonRef*)data)->image); gtk_widget_show(((ButtonRef*)data)->image); gtk_widget_show(widget); } void CMyButton::Init(GtkWidget *button,char *image) { //get button's parent GtkWidget* fixed = gtk_widget_get_parent(button); m_EventBox = NULL; m_ButtonRef.pixmap = NULL; m_ButtonRef.pixbuf = NULL; m_ButtonRef.pixmap = gdk_pixmap_new(button->window, button->allocation.width, button->allocation.height, -1); m_ButtonRef.pixbuf = gdk_pixbuf_new_from_file(image, NULL); m_ButtonRef.width = gdk_pixbuf_get_width(m_ButtonRef.pixbuf) / 4; m_ButtonRef.height = gdk_pixbuf_get_height(m_ButtonRef.pixbuf); // create and set the event box m_EventBox = gtk_event_box_new(); gtk_widget_set_events(m_EventBox, GDK_MOTION_NOTIFY | GDK_BUTTON_PRESS | GDK_BUTTON_RELEASE | GDK_ENTER_NOTIFY | GDK_LEAVE_NOTIFY); gtk_widget_set_uposition(m_EventBox, button->allocation.x, button->allocation.y); gtk_widget_set_usize(m_EventBox, m_ButtonRef.width,m_ButtonRef.height); // save the button's label const char *label = gtk_button_get_label(GTK_BUTTON(button)); if(label) { memset(m_ButtonRef.label,0,100); strcpy(m_ButtonRef.label,label); } gtk_fixed_put(GTK_FIXED(fixed),m_EventBox,10,10); //create the image m_ButtonRef.image = gtk_image_new(); gtk_container_add(GTK_CONTAINER(m_EventBox),m_ButtonRef.image); //create font PangoFontDescription *font_desc = pango_font_description_from_string("simsun 12"); pango_font_description_set_size (font_desc, PANGO_SCALE * 9); m_ButtonRef.font = gdk_font_from_description(font_desc); m_ButtonRef.font_width = gdk_string_width(m_ButtonRef.font,m_ButtonRef.label); m_ButtonRef.font_height = 9; m_ButtonRef.font_x = (m_ButtonRef.width - m_ButtonRef.font_width) / 2; m_ButtonRef.font_y = (m_ButtonRef.height + m_ButtonRef.font_height) / 2; } void CMyButton::SetLabel(char *label) { memset(m_ButtonRef.label,0,100); strcpy(m_ButtonRef.label,label); } char *CMyButton::GetLabel() { return m_ButtonRef.label; }