Gtk中的文本視圖(GtkTexViewWidget)

Gtk中的文本視圖(GtkTexViewWidget)

Gtk中的文本視圖(GtkTexView Widget)

在本章的Gtk+程序設計教程中,我們將重點介紹 GtkTexView 構件。

GtkTexView w構件被常常用來顯示和編輯多行的文本。正如我們一再提到的, GtkTexBuffer 構件也是給予MVC的設計。GtkTextView 就是顯示(view)元素而 GtkTexBuffer 則代表了model 元素。 GtkTexBuffer 常常被用來處理文本數據。GtkTextTag則是一種被用於文本的屬性。 GtkTextIter則是代表了兩個字符之間的空隙。那麼很好理解,文本的排版操作多用iterators。

簡單的例子(Simple example)

在我們的第一個例子中,我們將向大家展示GtkTexView 的一些功能。我們還將教大家怎麼樣去應用各種各樣的文本標記( tags )。

#include <gtk/gtk.h>


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *view;
  GtkWidget *vbox;
  
  GtkTextBuffer *buffer;
  GtkTextIter start, end;
  GtkTextIter iter;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "TextView");
  gtk_container_set_border_width(GTK_CONTAINER(window), 5);
  GTK_WINDOW(window)->allow_shrink = TRUE;

  vbox = gtk_vbox_new(FALSE, 0);
  view = gtk_text_view_new();
  gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0);

  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));

  gtk_text_buffer_create_tag(buffer, "gap",
        "pixels_above_lines", 30, NULL);

  gtk_text_buffer_create_tag(buffer, "lmarg", 
      "left_margin", 5, NULL);
  gtk_text_buffer_create_tag(buffer, "blue_fg", 
      "foreground", "blue", NULL); 
  gtk_text_buffer_create_tag(buffer, "gray_bg", 
      "background", "gray", NULL); 
  gtk_text_buffer_create_tag(buffer, "italic", 
      "style", PANGO_STYLE_ITALIC, NULL);
  gtk_text_buffer_create_tag(buffer, "bold", 
      "weight", PANGO_WEIGHT_BOLD, NULL);

  gtk_text_buffer_get_iter_at_offset(buffer, &iter, 0);

  gtk_text_buffer_insert(buffer, &iter, "Plain text\n", -1);
  gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, 
        "Colored Text\n", -1, "blue_fg", "lmarg",  NULL);
  gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, 
        "Text with colored background\n", -1, "lmarg", "gray_bg", NULL);

  gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, 
        "Text in italics\n", -1, "italic", "lmarg",  NULL);

  gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, 
        "Bold text\n", -1, "bold", "lmarg",  NULL);

  gtk_container_add(GTK_CONTAINER(window), vbox);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), G_OBJECT(window));

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}

這個例子展示瞭如何利用各種各樣的文本標記( GtkTextTags)來顯示文本。

view = gtk_text_view_new();

生成一個GtkTextView

gtk_text_buffer_create_tag(buffer, "blue_fg", 
    "foreground", "blue", NULL); 

這就是一個運用 GtkTextTag的例子,這個標記改變了文本的顏色。

gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, 
      "Colored Text\n", -1, "blue_fg", "lmarg",  NULL);

這個代碼插入了一些文本,並運用了一個特殊的文本標記blue_fg


Simple TextView
Figure: Simple TextView

行和欄(Lines and Columns)

在接下來的示例中將要顯示文本編輯光標目前處於的行數和列數。

#include <gtk/gtk.h>

update_statusbar(GtkTextBuffer *buffer,
    GtkStatusbar  *statusbar)
{
  gchar *msg;
  gint row, col;
  GtkTextIter iter;

  gtk_statusbar_pop(statusbar, 0); 

  gtk_text_buffer_get_iter_at_mark(buffer,
      &iter, gtk_text_buffer_get_insert(buffer));

  row = gtk_text_iter_get_line(&iter);
  col = gtk_text_iter_get_line_offset(&iter);

  msg = g_strdup_printf("Col %d Ln %d", col+1, row+1);

  gtk_statusbar_push(statusbar, 0, msg);

  g_free(msg);
}

static void
mark_set_callback(GtkTextBuffer *buffer,
    const GtkTextIter *new_location, GtkTextMark *mark,
    gpointer data)
{
  update_statusbar(buffer, GTK_STATUSBAR(data));
}


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *vbox;

  GtkWidget *toolbar;
  GtkWidget *view;
  GtkWidget *statusbar;
  GtkToolItem *exit;
  GtkTextBuffer *buffer;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "lines & cols");

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);

  toolbar = gtk_toolbar_new();
  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);

  exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exit, -1);

  gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5);

  view = gtk_text_view_new();
  gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0);
  gtk_widget_grab_focus(view);

  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));

  statusbar = gtk_statusbar_new();
  gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);

  g_signal_connect(G_OBJECT(exit), "clicked", 
        G_CALLBACK(gtk_main_quit), NULL);

  g_signal_connect(buffer, "changed",
        G_CALLBACK(update_statusbar), statusbar);

  g_signal_connect_object(buffer, "mark_set", 
        G_CALLBACK(mark_set_callback), statusbar, 0);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), NULL);

  gtk_widget_show_all(window);

  update_statusbar(buffer, GTK_STATUSBAR (statusbar));

  gtk_main();

  return 0;
}

在上面的代碼示例中,我們完成了在狀態欄中顯示當前文本編輯光標所處於的行和列數。

view = gtk_text_view_new();

生成一了 GtkTextView構件。

g_signal_connect(buffer, "changed",
      G_CALLBACK(update_statusbar), statusbar);

如果我們要更改文本,我們只需要調用回調函數 update_statusbar() 就可以了。

g_signal_connect_object(buffer, "mark_set", 
      G_CALLBACK(mark_set_callback), statusbar, 0);

當光標在移動的時候, mark_set 信號就被髮射出去了。

gtk_statusbar_pop(statusbar, 0); 

這段代碼功能是清除了先前的任何一些狀態欄中的信息。

gtk_text_buffer_get_iter_at_mark(buffer,
    &iter, gtk_text_buffer_get_insert(buffer));

row = gtk_text_iter_get_line(&iter);
col = gtk_text_iter_get_line_offset(&iter);

顯然上面的代碼是在獲取當前所處於的行號與列號。

msg = g_strdup_printf("Col %d Ln %d", col+1, row+1);

上面的代碼準備好,狀態欄中顯示出來的行號與列號的內容。

gtk_statusbar_push(statusbar, 0, msg);

然後,我們就在狀態欄上顯示文本。


Lines & Columns
Figure: Lines & Columns

監測& 突顯(Search & Highlight)

在接下來的例子中,我們將要在 GtkTextBuffer中做一些監測的工作。我們還將把一些文本的內容進行“突顯”處理。

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>


gboolean key_pressed(GtkWidget * window,
    GdkEventKey* event, GtkTextBuffer *buffer) {

  GtkTextIter start_sel, end_sel;
  GtkTextIter start_find, end_find;
  GtkTextIter start_match, end_match;
  gboolean selected;	
  gchar *text;		  
  


  if ((event->type == GDK_KEY_PRESS) && 
     (event->state & GDK_CONTROL_MASK)) {

    switch (event->keyval)
    {
      case GDK_m :
        selected = gtk_text_buffer_get_selection_bounds(buffer, 
            &start_sel, &end_sel);
      if (selected) {
        gtk_text_buffer_get_start_iter(buffer, &start_find);
        gtk_text_buffer_get_end_iter(buffer, &end_find);

        gtk_text_buffer_remove_tag_by_name(buffer, "gray_bg", 
            &start_find, &end_find);  
        text = (char *) gtk_text_buffer_get_text(buffer, &start_sel,
            &end_sel, FALSE);

        while ( gtk_text_iter_forward_search(&start_find, text, 
                GTK_TEXT_SEARCH_TEXT_ONLY | 
                GTK_TEXT_SEARCH_VISIBLE_ONLY, 
                &start_match, &end_match, NULL) ) {

          gtk_text_buffer_apply_tag_by_name(buffer, "gray_bg", 
              &start_match, &end_match);
          int offset = gtk_text_iter_get_offset(&end_match);
          gtk_text_buffer_get_iter_at_offset(buffer, 
              &start_find, offset);
        }

        g_free(text);
      }

      break;

      case GDK_r:
        gtk_text_buffer_get_start_iter(buffer, &start_find);
        gtk_text_buffer_get_end_iter(buffer, &end_find);
      
        gtk_text_buffer_remove_tag_by_name(buffer, "gray_bg", 
            &start_find, &end_find);  
      break;
    }
  }

  return FALSE;
}


int main( int argc, char *argv[])
{

  GtkWidget *window;
  GtkWidget *view;
  GtkWidget *vbox;
  
  GtkTextBuffer *buffer;
  GtkTextIter start, end;
  GtkTextIter iter;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
  gtk_window_set_title(GTK_WINDOW(window), "Search & Highlight");
  gtk_container_set_border_width(GTK_CONTAINER(window), 5);
  GTK_WINDOW(window)->allow_shrink = TRUE;

  vbox = gtk_vbox_new(FALSE, 0);
  view = gtk_text_view_new();
  gtk_widget_add_events(view, GDK_BUTTON_PRESS_MASK);
  gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0);

  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
  gtk_text_buffer_create_tag(buffer, "gray_bg", 
      "background", "gray", NULL); 
  gtk_container_add(GTK_CONTAINER(window), vbox);

  g_signal_connect_swapped(G_OBJECT(window), "destroy",
        G_CALLBACK(gtk_main_quit), G_OBJECT(window));

  g_signal_connect(G_OBJECT(window), "key-press-event",
        G_CALLBACK(key_pressed), buffer);

  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}

在我們的示例中,我們用到了鍵盤的快捷鍵。Ctrl + M 是用來突顯我們當前所選取的文本內容。Ctrl + R 則是用來取消上面的操作。

gtk_text_buffer_create_tag(buffer, "gray_bg", 
    "background", "gray", NULL); 

我們在例子中會再次用到 GtkTextTag 。這個標記可以使文本的背景反白。

selected = gtk_text_buffer_get_selection_bounds(buffer, 
    &start_sel, &end_sel);

這裏我們得到我們選中的文本所具有的起始和終點位置。

gtk_text_buffer_get_start_iter(buffer, &start_find);
gtk_text_buffer_get_end_iter(buffer, &end_find);

我們得到了文本緩衝區(text buffer)的起始和終點位置。

gtk_text_buffer_remove_tag_by_name(buffer, "gray_bg", 
    &start_find, &end_find);  

上面就是,把先前的標記去處。

text = (char *) gtk_text_buffer_get_text(buffer, &start_sel,
    &end_sel, FALSE);

接着我們得到了所選擇的文本內容,我們將要進行監測。

while ( gtk_text_iter_forward_search(&start_find, text, 
        GTK_TEXT_SEARCH_TEXT_ONLY | 
        GTK_TEXT_SEARCH_VISIBLE_ONLY, 
        &start_match, &end_match, NULL) ) {

  gtk_text_buffer_apply_tag_by_name(buffer, "gray_bg", 
      &start_match, &end_match);
  int offset = gtk_text_iter_get_offset(&end_match);
  gtk_text_buffer_get_iter_at_offset(buffer, 
      &start_find, offset);
}

這段代碼將檢測所有我們所選擇的文本後的所發生的事件,一旦發現與我們定義的內容有匹配就應用我們設定好的標記。在匹配工作完成之後,單詞的尾端將將被成下次監視操作的首端。


Search & Highlight
Figure: Search & Highlight
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章