Отправляет email-рассылки с помощью сервиса Sendsay

Практические советы по GTK+

  Все выпуски  

Практические советы по GTK+ (Форматированный текст. часть 2)


 Форматированный текст. часть 2

Теперь все выпуски, включая этот, Вы можно найти в одном файле gtk_book.chm.

Это продолжение статьи о применениии форматированного текста в GTK. Если Вы решите написать свой текстовый редактор с поддержкой форматированием текста или что-то в этом роде, эта статья, которая содержит готовые решения для некоторых операций, поможет сэкономить немного времени.

 

Напомню, что вывод текста производится в виджет типа GtkTextView.

Все примеры будут работать с текстовым виджетом text_view и текстовым буфером buffer, которые определены следующими образом:

GtkWidget *text_view = gtk_text_view_new();

GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));

 

Примеры разделены по группам:

Установка и определение положений в буфере

Поиск тегов

 

 

Установка и определение положений в буфере:

 

Смещение в буфере на N символов вперёд/назад:

// [in/out] iter - текущая позиция(поменяется)

// [in] n - число символов для смещения (если <0, то идём назад)

gboolean move_iter(GtkTextIter *iter, int n)

{

       // двигаемся на x символов вперёд

       gtk_text_iter_forward_chars(iter,n);

       // или так:

       // gtk_text_iter_backward_chars(iter,-n);

}

 

 

Установить курсор в заданную позицию:

// [in] iter - задаёт текущую позицию

void set_cursor_place(GtkTextIter *iter)

{

       gtk_text_buffer_place_cursor(buffer,iter);

}

 

Поиск текущего местоположения курсора:

// [out] iter - сюда запишется текущая позиция курсора в текстовом поле

void get_cursor_place(GtkTextIter *iter)

{

       // начало выделения, даже если ничего не выделено, всё равно эта метка есть

       GtkTextMark *mark = gtk_text_buffer_get_mark(buffer,"insert");

       // можно искать через конец выделения - тот же результат, ведь при отсутствии выделения эти метки совпадают, а при наличии выделения курсор отсутствует на экране.

       //GtkTextMark *mark = gtk_text_buffer_get_mark(buffer,"selection_bound");

       

       // ищем положение метки

       gtk_text_buffer_get_iter_at_mark(buffer,iter,mark);

// ещё можно пробегать по тексту с узнавать здесь ли курсор:gboolean gtk_text_iter_is_cursor_position(GtkTextIter *iter); - но так дольше

}

 

 

Выделение области:

// [in] iter1, iter2 - начальная и конечная позиции области для выделения

void set_selection(GtkTextIter *iter1,GtkTextIter *iter2)

{

       gtk_text_buffer_select_range(buffer,iter1,iter2);

}

 

Поиск выделенной области:

// [out] iter1, iter2 - сюда запишется начальная и конечная позиции выделенной области

void get_selection(GtkTextIter *iter1,GtkTextIter *iter2)

{

       gtk_text_buffer_get_selection_bounds(buffer,iter1,iter2);

}

 

 

Определение положения в тексте x,y по iter:

// [in] iter - текущая позиция

// [out] x - номер символа в строке, у - номер строки в тексте (счёт идёт от 0)

void get_xy_pos(GtkTextIter *iter, int *x, int *y)

{

       *x = gtk_text_iter_get_line_offset(iter);

       *y = gtk_text_iter_get_line(iter);

}

 

Определение положения в тексте iter по x,y:

// [out] iter - текущая позиция

// [in] x - номер символа в строке, у - номер строки в тексте (счёт идёт от 0)

void get_iter_pos(int *x, int *y, GtkTextIter *iter)

{

       // встаём в начало строки

       gtk_text_buffer_get_iter_at_line_index(buffer,iter,y,0);

       // двигаемся на x символов вперёд

       gtk_text_iter_forward_chars(iter,x);

}

В последнем параметре gtk_text_buffer_get_iter_at_line_index() можно было бы сразу указать смещение по x в байтах, и не надо было бы использовать вторую функцию, но у нас известен номер символа в строке, а не номер байта (в кодировке UTF8 символ может занимать больше одного байта).

 

Отслеживание перемещения текстового курсора пользователем

Если Вы хотите обрабатывать изменение положения текстового курсора, то в качестве одного из вариантов, Вам надо будет подключить обработчики двух событий:

// подключение обработчика нажатия кнопкой мыши

g_signal_connect(G_OBJECT(text_view),"button_press_event",G_CALLBACK (button_press_event), NULL);

// подключение обработчика перемещения текстового курсора клавишами клавиатуры

g_signal_connect_after(G_OBJECT(text_view),"move_cursor",G_CALLBACK (move_cursor_event), NULL);

Обратите внимание, что второй обработчик подключается через g_signal_connect_after(), поскольку используемый в нём метод поиска текущего положения в тексте требует установки метки "insert" во встроенном обработчике.

 

// обработчик нажатия кнопкой мыши

static gboolean button_press_event(GtkWidget *text_editor, GdkEventButton *event, gpointer data)

{

       if (event->button == 1)// левая кнопка мыши

       {

               GtkTextIter iter;

               // определяем текущее положение курсора

               gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(text_editor),&iter,event->x,event->y);

               // теперь в iter находится тек. положение в текстовом буфере

               // ...

       }

       return FALSE;

}

 

// обработчик перемещения текстового курсора клавишами клавиатуры

void move_cursor_event(GtkTextView *text_editor, GtkMovementStep step, gint count, gboolean extend_selection, gpointer user_data)

{

       GtkTextIter iter;

       GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_editor));

       GtkTextMark *mark = gtk_text_buffer_get_mark(text_buffer,"insert");// начало выделения, даже если ничего не выделено, всё равно эта метка есть

       gtk_text_buffer_get_iter_at_mark(text_buffer,&iter,mark);

       // теперь в iter находится тек. положение в текстовом буфере

       // ...

}

 

 

Поиск тегов:

 

Узнать сколько всего тегов в буфере:

GtkTextTagTable *tag_table =  gtk_text_buffer_get_tag_table(buffer);// получить таблицу тегов

int tag_max = gtk_text_tag_table_get_size(tag_table);

 

 

Перечисление всех тегов в буфере:

GtkTextTagTable *tag_table =  gtk_text_buffer_get_tag_table(buffer);// получить таблицу тегов

GHashTable *hash_table = tag_table->hash;

GHashTableIter iter_hash;

gpointer tag_name, tag;

// поиск всех тегов

g_hash_table_iter_init (&iter_hash, hash_table);

while (g_hash_table_iter_next (&iter_hash,&tag_name,&tag))// пока есть теги в таблице

{

      ;// теперь в tag_name - имя очередного тега, а в tag - указатель на сам тег, т.е. на структуру GtkTextTag;

};

 

 

Получить список с примененными в конкретном месте текста(iter) тегами:

GSList *list_start;

GSList *list = gtk_text_iter_get_tags(iter);

list_start = list;

// перечисление всех тегов в списке

while(list)

{

       GtkTextTag *tag = list->data;

       // для примера напечаем имя тега

       printf("%s;",tag->name);

       // переходим на следующий тег в списке

       list = list->next;

};

if(list_start)

       g_slist_free(list_start);

 


В избранное