以下是一个基于 GTK3.0 的自定义标题栏 Demo,支持窗口拖动、最大化/最小化功能。代码通过移除默认标题栏并模拟自定义控件实现。
完整代码示例
#include <gtk/gtk.h>
// 全局变量记录鼠标按下时的坐标
static gboolean is_dragging = FALSE;
static gint start_x, start_y;
// 处理鼠标按下事件(开始拖动)
static gboolean on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
if (event->button == GDK_BUTTON_PRIMARY && event->y < 50) { // 仅在上部区域触发拖动
is_dragging = TRUE;
start_x = event->x_root;
start_y = event->y_root;
}
return TRUE;
}
// 处理鼠标移动事件(执行拖动)
static gboolean on_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) {
if (is_dragging) {
GtkWindow *window = GTK_WINDOW(user_data);
gint x, y;
gtk_window_get_position(window, &x, &y);
gtk_window_move(window, x + (event->x_root - start_x), y + (event->y_root - start_y));
start_x = event->x_root;
start_y = event->y_root;
}
return TRUE;
}
// 处理鼠标释放事件(停止拖动)
static gboolean on_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
if (event->button == GDK_BUTTON_PRIMARY) {
is_dragging = FALSE;
}
return TRUE;
}
// 按钮回调:关闭窗口
static void on_close_clicked(GtkButton *button, gpointer user_data) {
gtk_main_quit();
}
// 按钮回调:最大化/还原窗口
static void on_maximize_clicked(GtkButton *button, gpointer user_data) {
GtkWindow *window = GTK_WINDOW(user_data);
if (gtk_window_is_maximized(window)) {
gtk_window_unmaximize(window);
} else {
gtk_window_maximize(window);
}
}
// 按钮回调:最小化窗口
static void on_minimize_clicked(GtkButton *button, gpointer user_data) {
GtkWindow *window = GTK_WINDOW(user_data);
gtk_window_iconify(window);
}
int main(int argc, char **argv) {
// 初始化 GTK
gtk_init(&argc, &argv);
// 创建主窗口并移除默认标题栏
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Custom Titlebar Demo");
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
/*关键步骤:移除默认标题栏*/
gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
/*允许窗口接收鼠标移动事件*/
gtk_widget_add_events(window,
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK);
/*绑定鼠标事件*/
g_signal_connect(window,"button-press-event",
G_CALLBACK(on_button_press),
NULL);
g_signal_connect(window,"motion-notify-event",
G_CALLBACK(on_motion_notify),
window);
g_signal_connect(window,"button-release-event",
G_CALLBACK(on_button_release),
NULL);
/*创建自定义标题栏容器*/
GtkWidget* titlebar=gtk_box_new(GTK_ORIENTATION_HORIZONTAL ,5);
GdkRGBA color;
gdk_rgba_parse(&color,"#333333"); /*设置深色背景*/
GdkDisplay* display=gdk_display_get_default();
cairo_pattern_t* pattern=cairo_pattern_create_linear(0 ,0 ,0 ,50);
cairo_pattern_add_color_stop_rgb(pattern ,0 ,0.2 ,0.2 ,0.2);
cairo_pattern_add_color_stop_rgb(pattern ,1 ,0.1 ,0.1 ,0.1);
/*添加标题文本*/
GLabel* label=glabel_new("Custom Title");
glabel_set_xalign(label ,0 );
glabel_set_size_request(label ,-1 ,40 );
/*添加控制按钮(最小化/最大化/关闭)*/
ButtonBox* button_box=create_button_box();
pack_start(titlebar ,label ,TRUE ,TRUE );
pack_end(titlebar ,button_box );
set_valign(titlebar ,GTK ALIGN START );
set_size_request(titlebar ,-1 ,50 );
add_overlay(main overlay ,titlebar );
return app run(argc argv );
}
关键实现说明
- 移除默认标题栏
”`c //关键步骤: //必须调用这个函数才能禁用系统原生边框和标题栏。 //注意:某些桌面环境可能忽略此设置(比如Gnome Shell)。 //如果无效可以尝试: //set_type_hint(GDK WINDOW TYPE HINT UTILITY) set_decorated(FALSE)
2.**模拟拖动逻辑**:
```c++
/*核心原理是跟踪三个事件:
- button-press-event:记录初始坐标。
- motion-notify-event:计算位移差并移动窗口。
- button-release-event:结束拖动状态。*/
/*注意事项:
1.GDK会限制窗口不能移出屏幕边界。
2.多显示器环境下需要额外处理坐标转换。*/
3.控制按钮实现:
closeBtn.connect("clicked",[](){app quit();});
maximizeBtn.connect("clicked",[this](){
if(isMaximized()) unmaximize();
else maximize();
});
minimizeBtn.connect("clicked",[this](){
iconify();
});
4.样式优化建议:
/*推荐使用CSS provider为自定义标题栏添加现代视觉效果*/
#custom-titlebar{
background: linear-gradient(to bottom,#222,#111);
border-radius:5px5px00;
box-shadow:02px5pxrgba(0,,,.3)
}
编译运行
保存为 custom_titlebar.c
,然后编译:
gcc custom_titlebar.c -o demo `pkg-config --cflags --libsgtk+-3.`
./demo
效果说明
-顶部50像素区域可拖动窗口
-右侧三个标准功能按钮
-完全去除了系统原生边框
如果需要更复杂的效果(如阴影、动画),建议结合Clutter或直接使用CSD(CilentSideDecorations)。
内容由零声教学AI助手提供,问题来源于学员提问