Код:
#include <gtk/gtk.h>
// Структурный тип для создания рабочего пространства
typedef struct
{
GtkWidget *parent;
GtkWidget *frame;
gint mode;
}SWorkspace;
SWorkspace *workspace;
// Функция формирующая рабочее пространство
void get_workspace_frame( SWorkspace *workspace);
// Функция формирующая содержимое рабочего пространства
GtkWidget* new_frame();
// Функция удаления дочернего виджета из панельного виджета
// (эта функция присутствует в GTK+ версии 2.10.13, но отсутсвует в более ранних версиях библиотеки)
void gtk_paned_remove (GtkContainer *container,
GtkWidget *widget)
{
GtkPaned *paned;
gboolean was_visible;
paned = GTK_PANED (container);
was_visible = GTK_WIDGET_VISIBLE (widget);
if (paned->child1 == widget)
{
gtk_widget_unparent (widget);
paned->child1 = NULL;
if (was_visible && GTK_WIDGET_VISIBLE (container))
gtk_widget_queue_resize (GTK_WIDGET (container));
}
else if (paned->child2 == widget)
{
gtk_widget_unparent (widget);
paned->child2 = NULL;
if (was_visible && GTK_WIDGET_VISIBLE (container))
gtk_widget_queue_resize (GTK_WIDGET (container));
}
}
// Функция переключения переменных рабочего пространства
void set_frame_workspace( GtkWidget *frame)
{
workspace->frame = frame;
workspace->parent = frame->parent;
}
// Рекурсивная функция удаления рабочего пространства
// если родительский панельный виджет удаляемого фрейма оказывается пустым
// функция вызывается повторно с родительским виджетом в качестве
// параметра указывающего виджет для удаления
void widget_destroy( GtkWidget *widget)
{
GtkPaned *paned;
if( GTK_IS_PANED( widget->parent))
{
paned = GTK_PANED( widget->parent);
gtk_paned_remove( GTK_CONTAINER( widget->parent), widget);
if(GTK_IS_WIDGET( widget))
{
gtk_widget_destroy( widget);
}
if( paned->child1 == NULL && paned->child2 == NULL)
{
widget_destroy( (GtkWidget*)paned);
}
}
}
// Функция удаления содержимого рабочего пространства
void widget_clear( GtkWidget *widget)
{
if(GTK_IS_WIDGET( widget))
{
gtk_widget_destroy( widget);
}
}
// Функция устанавливающая режим деления по вертикали
void set_workspace_mode1( SWorkspace *workspace)
{
workspace->mode = 1;
get_workspace_frame( workspace);
}
// Функция устанавливающая режим деления по горизонтали
void set_workspace_mode2( SWorkspace *workspace)
{
workspace->mode = 2;
get_workspace_frame( workspace);
}
int main(int argc, char* argv[])
{
gtk_init(&argc, &argv);
GtkWidget *window;
// Выделяем память для переменных рабочего пространства
workspace = g_malloc( sizeof(SWorkspace));
// создаем основное окно программы
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
// устанавливаем начальный размер основного окна
gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
// устанавливаем позицию окна при запуске программы
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
// определяем заголовок основного окна
gtk_window_set_title(GTK_WINDOW(window), "GtkPaned example");
// подключаем сигнал выхода из программы при нажатии кнопки закрытия окна
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
// Определяем начальные переменные рабочего пространства
workspace->parent = window;
workspace->mode = 0;
get_workspace_frame( workspace);
// Отображаем всё содержимое окна
gtk_widget_show_all( window);
gtk_main();
return 0;
}
GtkWidget* new_frame()
{
// Ярлык имитирующий содержимое рабочего пространства
GtkWidget *label = gtk_label_new("FRAME");
// Основная рамка рабочего пространства
GtkWidget *frame = gtk_frame_new( NULL);
gtk_frame_set_shadow_type( GTK_FRAME( frame), GTK_SHADOW_IN);
// Изображение для кнопки закрыть
GtkWidget *image_close = gtk_image_new_from_stock( GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
// Кнопка закрыть
GtkWidget *button_close = gtk_button_new();
gtk_button_set_relief( (GtkButton*)button_close, GTK_RELIEF_NONE);
gtk_button_set_image( (GtkButton*)button_close, image_close);
// Подключаем функцию рекурсивного удаления рабочего пространства
g_signal_connect_swapped( G_OBJECT( button_close), "clicked",
G_CALLBACK( widget_destroy), frame);
// Изображение для кнопки очиcтки рабочего пространства
GtkWidget *image_clear = gtk_image_new_from_stock( GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU);
// Кнопка очистки рабочего пространства
GtkWidget *button_clear = gtk_button_new();
gtk_button_set_relief( (GtkButton*)button_clear, GTK_RELIEF_NONE);
gtk_button_set_image( (GtkButton*)button_clear, image_clear);
// Подключаем функцию очистки рабочего пространства
g_signal_connect_swapped( G_OBJECT( button_clear), "clicked",
G_CALLBACK( widget_clear), label);
// Изображение для кнопки вставки рабочего пространства в лево
GtkWidget *image_left = gtk_image_new_from_stock( GTK_STOCK_GOTO_LAST, GTK_ICON_SIZE_MENU);
// Кнопка добавляющая деление в левую часть существующего виджета
GtkWidget *button_left = gtk_button_new();
gtk_button_set_relief( (GtkButton*)button_left, GTK_RELIEF_NONE);
gtk_button_set_image( (GtkButton*)button_left, image_left);
// Подключаем функции переключения переменных рабочего пространства
g_signal_connect_swapped( G_OBJECT( button_left), "enter",
G_CALLBACK( set_frame_workspace), frame);
g_signal_connect_swapped( G_OBJECT( button_left), "button-press-event",
G_CALLBACK( set_workspace_mode2), workspace);
// Изображение для кнопки вставки рабочего пространства снизу
GtkWidget *image_bottom = gtk_image_new_from_stock( GTK_STOCK_GOTO_BOTTOM, GTK_ICON_SIZE_MENU);
// Кнопка добавляющая деление снизу
GtkWidget *button_bottom = gtk_button_new();
gtk_button_set_relief( (GtkButton*)button_bottom, GTK_RELIEF_NONE);
gtk_button_set_image( (GtkButton*)button_bottom, image_bottom);
// Подключаем функции переключения переменных рабочего пространства
g_signal_connect_swapped( G_OBJECT( button_bottom), "enter",
G_CALLBACK( set_frame_workspace), frame);
g_signal_connect_swapped( G_OBJECT( button_bottom), "button-press-event",
G_CALLBACK( set_workspace_mode1), workspace);
// Контейнер для кнопок
GtkWidget *buttonbox = gtk_hbox_new( FALSE, 0);
gtk_box_pack_end( (GtkBox*)buttonbox, button_close, FALSE, FALSE, 0);
gtk_box_pack_end( (GtkBox*)buttonbox, button_clear, FALSE, FALSE, 0);
gtk_box_pack_start( (GtkBox*)buttonbox, button_bottom, FALSE, FALSE, 0);
gtk_box_pack_start( (GtkBox*)buttonbox, button_left, FALSE, FALSE, 0);
// Вертикальный контейнер
GtkWidget *vbox = gtk_vbox_new( FALSE, 0);
gtk_box_pack_start( (GtkBox*)vbox, buttonbox, FALSE, FALSE, 0);
gtk_box_pack_start( (GtkBox*)vbox, label, TRUE, FALSE, 0);
gtk_container_add( GTK_CONTAINER( frame), vbox);
return frame;
}
void get_workspace_frame( SWorkspace *workspace)
{
// Вертикальная панель деления
GtkWidget *vpaned = gtk_vpaned_new();
// Горизонтальная панель деления
GtkWidget *hpaned = gtk_hpaned_new();
// Создаём содержимое фрейма
GtkWidget *frame = new_frame();
if( workspace->mode > 0)
{
if( workspace->mode == 1)
{
// Вертикальное деление
// Создаём ссылку на фрейм для удаления из родительского контейнера
gtk_widget_ref( workspace->frame);
// Если родитель - панельный виджет
if( workspace->frame->parent == vpaned)
{
// Удаляем фрейм из родителя для последующей перепаковки
gtk_paned_remove( GTK_CONTAINER( workspace->frame->parent), workspace->frame);
// Упаковываем в родительский виджет новый вертикальный панельный виджет
gtk_paned_pack1( GTK_PANED( workspace->parent), vpaned, FALSE, FALSE);
}
else
{
// Иначе удаляем фрейм из родительского контейнера
gtk_container_remove( GTK_CONTAINER( workspace->frame->parent), workspace->frame);
// Добавляем в родительский контейнер панельный виджет вертикального деления
gtk_container_add( GTK_CONTAINER( workspace->parent), vpaned);
}
// Упаковываем во вновь созданный панельный виджет предыдущий frame и новый
gtk_paned_pack1( GTK_PANED( vpaned), workspace->frame, FALSE, FALSE);
gtk_paned_pack2( GTK_PANED( vpaned), frame, FALSE, FALSE);
// Определяем нового родителя для фрейма
workspace->parent = frame->parent;
}
else if( workspace->mode == 2)
{
// Горизонтальное деление
// Создаём ссылку на фрейм для удаления из родительского контейнера
gtk_widget_ref( workspace->frame);
// Если родитель - панельный виджет
if( workspace->frame->parent == hpaned)
{
// Удаляем фрейм из родителя для последующей перепаковки
gtk_paned_remove( GTK_CONTAINER( workspace->frame->parent), workspace->frame);
// Упаковываем в родительский виджет новый горизонтальный панельный виджет
gtk_paned_pack1( GTK_PANED( workspace->parent), hpaned, FALSE, FALSE);
}
else
{
// Иначе удаляем фрейм из родительского контейнера
gtk_container_remove( GTK_CONTAINER( workspace->frame->parent), workspace->frame);
// Добавляем в родительский контейнер панельный виджет горизоньального деления
gtk_container_add( GTK_CONTAINER( workspace->parent), hpaned);
}
// Упаковываем во вновь созданный панельный виджет предыдущий и новый фреймы
gtk_paned_pack1( GTK_PANED( hpaned), workspace->frame, FALSE, FALSE);
gtk_paned_pack2( GTK_PANED( hpaned), frame, FALSE, FALSE);
// Определяем нового родителя для фрейма
workspace->parent = frame->parent;
}
}
else
{
// Если режим равен 0 - занчит рабочее пространство не имеет деления
// просто добавляем фрейм в родительский контейнер
gtk_container_add( GTK_CONTAINER( workspace->parent), frame);
// Определяем нового родителя для фрейма
workspace->frame = frame;
}
gtk_widget_show_all( workspace->parent);
}
Код можно скомпилировать командой
gcc `pkg-config --cflags --libs gtk+-2.0` panedexample.c -o panedexample
при условии что в вашей системе установлено всё необходимое, а код находится в файле panedexample.c
Подробности тут:
http://linfoline.homedns.org/gtk-2.10-refe.../GtkHPaned.html
http://linfoline.homedns.org/gtk-2.10-refe.../GtkVPaned.html
http://linfoline.homedns.org/gtk-2.10-refe...u/GtkPaned.html
P/S Данный пример содержит несколько ошибок, правильный вариант можно будет увидеть в программе TFX