gtk user control自绘控件

ubuntu下gtk库是默认已安装的,开发部署很方便,以下是我写的自绘控件例子:

EuhatChildWnd.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma once
 
struct _cairo_surface;
struct _GtkWidget;
 
class EuhatChildWnd
{
public:
	EuhatChildWnd(int width, int height);
	~EuhatChildWnd();
 
	void clear();
	void drawBrush(struct _GtkWidget *widget, double x, double y);
 
	struct _GtkWidget *drawingArea_;
	struct _cairo_surface *surface_;
 
	double xFrom_;
	double yFrom_;
};


EuhatChildWnd.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "EuhatChildWnd.h"
#include <gtk/gtk.h>
 
static gboolean configureEventCb(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
{
	EuhatChildWnd *pThis = (EuhatChildWnd *)data;
 
	if (NULL != pThis->surface_)
		cairo_surface_destroy(pThis->surface_);
 
	pThis->surface_ = gdk_window_create_similar_surface(gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR, gtk_widget_get_allocated_width(widget), gtk_widget_get_allocated_height(widget));
 
	pThis->clear();
 
	return TRUE;
}
 
static gboolean drawCb(GtkWidget *widget, cairo_t *cr, gpointer data)
{
	EuhatChildWnd *pThis = (EuhatChildWnd *)data;
 
	cairo_set_source_surface(cr, pThis->surface_, 0, 0);
	cairo_paint(cr);
 
	return FALSE;
}
 
static gboolean buttonPressEventCb(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
	EuhatChildWnd *pThis = (EuhatChildWnd *)data;
	if (NULL == pThis->surface_)
		return FALSE;
 
	if (event->button == GDK_BUTTON_PRIMARY)
	{
		pThis->xFrom_ = event->x;
		pThis->yFrom_ = event->y;
		pThis->drawBrush(widget, event->x, event->y);
	}
	else if (event->button == GDK_BUTTON_SECONDARY)
	{
		pThis->clear();
		gtk_widget_queue_draw(widget);
	}
 
	return TRUE;
}
 
static gboolean motionNotifyEventCb(GtkWidget *widget, GdkEventMotion *event, gpointer data)
{
	EuhatChildWnd *pThis = (EuhatChildWnd *)data;
	if (NULL == pThis->surface_)
		return FALSE;
 
	if (event->state & GDK_BUTTON1_MASK)
		pThis->drawBrush(widget, event->x, event->y);
 
	return TRUE;
}
 
EuhatChildWnd::EuhatChildWnd(int width, int height)
{
	surface_ = NULL;
	xFrom_ = 0;
	yFrom_ = 0;
 
	drawingArea_ = gtk_drawing_area_new();
 
	gtk_widget_set_size_request(drawingArea_, width, height);
 
	g_signal_connect(drawingArea_, "configure-event", G_CALLBACK(configureEventCb), this);
	g_signal_connect(drawingArea_, "draw", G_CALLBACK(drawCb), this);
 
	g_signal_connect(drawingArea_, "button-press-event", G_CALLBACK(buttonPressEventCb), this);
	g_signal_connect(drawingArea_, "motion-notify-event", G_CALLBACK(motionNotifyEventCb), this);
 
	gtk_widget_set_events(drawingArea_, gtk_widget_get_events(drawingArea_) | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
}
 
EuhatChildWnd::~EuhatChildWnd()
{
	if (NULL != surface_)
		cairo_surface_destroy(surface_);
}
 
void EuhatChildWnd::clear()
{
	cairo_t *cr;
 
	cr = cairo_create(surface_);
 
	cairo_set_source_rgb(cr, 1, 1, 1);
	cairo_paint(cr);
 
	cairo_destroy(cr);
}
 
void EuhatChildWnd::drawBrush(GtkWidget *widget, gdouble x, gdouble y)
{
	cairo_t *cr;
 
	cr = cairo_create(surface_);
 
//	cairo_rectangle(cr, x - 3, y - 3, 6, 6);
//	cairo_fill(cr);
//	cairo_draw_line(cr, xFrom_, yFrom_, x, y);
	cairo_set_source_rgb(cr, 1, 1, 1);
	cairo_paint(cr);
 
	cairo_set_source_rgb(cr, 0, 0, 0);
	cairo_set_line_width(cr, 1);
	cairo_move_to(cr, xFrom_, yFrom_);
	cairo_line_to(cr, x, yFrom_);
	cairo_line_to(cr, x, y);
	cairo_line_to(cr, xFrom_, y);
	cairo_line_to(cr, xFrom_, yFrom_);
	cairo_stroke(cr);
 
	cairo_destroy(cr);
 
//	gtk_widget_queue_draw_area(widget, x - 3, y - 3, 6, 6);
	gtk_widget_queue_draw(widget);
}

EuhatWindow.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#pragma once
 
struct _GtkWidget;
 
class EuhatApp;
class EuhatChildWnd;
 
class EuhatWindow
{
public:
	EuhatWindow(EuhatApp *app);
	~EuhatWindow();
 
	void setTitle(const char *title);
	void addChildWnd(EuhatChildWnd *childWnd);
	void showAll();
 
	struct _GtkWidget *window_;
//	struct _GtkWidget *frame_;
	struct _GtkWidget *box_;
};

EuhatWindow.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include "EuhatWindow.h"
#include "EuhatApp.h"
#include "EuhatChildWnd.h"
#include <gtk/gtk.h>
 
static void closeWindow(gpointer data)
{
}
 
EuhatWindow::EuhatWindow(EuhatApp *app)
{
	window_ = gtk_application_window_new(app->app_);
 
	g_signal_connect(window_, "destroy", G_CALLBACK(closeWindow), this);
 
	gtk_container_set_border_width(GTK_CONTAINER(window_), 8);
 
/*	frame_ = gtk_frame_new(NULL);
	gtk_frame_set_shadow_type(GTK_FRAME(frame_), GTK_SHADOW_IN);
	gtk_container_add(GTK_CONTAINER(window_), frame_);
*/
	box_ = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
	gtk_container_add(GTK_CONTAINER(window_), box_);
}
 
EuhatWindow::~EuhatWindow()
{
}
 
void EuhatWindow::setTitle(const char *title)
{
	gtk_window_set_title(GTK_WINDOW(window_), title);
}
 
void EuhatWindow::addChildWnd(EuhatChildWnd *childWnd)
{
//	gtk_container_add(GTK_CONTAINER(frame_), childWnd->drawingArea_);
	gtk_container_add(GTK_CONTAINER(box_), childWnd->drawingArea_);
}
 
void EuhatWindow::showAll()
{
	gtk_widget_show_all(window_);
}

EuhatApp.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma once
 
struct _GtkApplication;
 
class EuhatApp
{
public:
	EuhatApp();
	~EuhatApp();
 
	virtual void onActivate();
	int run(int argc, char **argv);
 
	struct _GtkApplication *app_;
};

EuhatApp.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "EuhatApp.h"
#include <gtk/gtk.h>
 
static void activate(GtkApplication *app, gpointer data)
{
	EuhatApp *pThis = (EuhatApp *)data;
 
	pThis->onActivate();
}
 
EuhatApp::EuhatApp()
{
	app_ = gtk_application_new("com.euhat.expert", G_APPLICATION_FLAGS_NONE);
	g_signal_connect(app_, "activate", G_CALLBACK(activate), this);
}
 
EuhatApp::~EuhatApp()
{
	g_object_unref(app_);
}
 
void EuhatApp::onActivate()
{
}
 
int EuhatApp::run(int argc, char **argv)
{
	int status;
	status = g_application_run(G_APPLICATION(app_), argc, argv);
	return 1;
}

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <EuhatApp.h>
#include <EuhatWindow.h>
#include <EuhatChildWnd.h>
#include <list>
#include <vector>
#include <string>
#include <memory>
 
using namespace std;
 
class TstApp : public EuhatApp
{
public:
	void onActivate();
 
	unique_ptr<EuhatWindow> mainWin_;
	unique_ptr<EuhatChildWnd> childWnd_;
	unique_ptr<EuhatChildWnd> childWnd2_;
};
 
void TstApp::onActivate()
{
	mainWin_.reset(new EuhatWindow(this));
	childWnd_.reset(new EuhatChildWnd(400, 400));
	childWnd2_.reset(new EuhatChildWnd(400, 400));
	mainWin_->addChildWnd(childWnd_.get());
	mainWin_->addChildWnd(childWnd2_.get());
	mainWin_->showAll();
}
 
int main(int argc, char **argv)
{
	TstApp app;
	return app.run(argc, argv);
}

Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CPLUSPLUS=g++
CFLAGS=-g -I. -Wl,-Map=test.map -no-pie -rdynamic `pkg-config --cflags gtk+-3.0`
LDFLAGS=`pkg-config --libs gtk+-3.0`
 
SOURCES=$(wildcard *.cpp)
 
OBJS=$(SOURCES:%.cpp=release/%.o)
 
TARGET=release/test
 
all: before $(TARGET)
 
before:
	@test -d release || mkdir -p release
 
$(OBJS): release/%.o: %.cpp
	$(CPLUSPLUS) -c $(CFLAGS) $< -o $@
 
$(TARGET): $(OBJS)
	$(CPLUSPLUS) -o $@ $^ $(LDFLAGS)
 
clean:
	rm -Rf release