Create  Edit  FrontPage  Index  Search  Changes  History  RSS  Back  Login

tut-gtk2-txtw-textview - History

  • Added words are showed as here.
  • Removed words are showed as here.
= The Text View Widget
{{link "tut-gtk2-txtw-scrolledwin", "tut-gtk2-txtw", "tut-gtk", "tut-gtk2-txtw-itrsmrks"}}

= Sorry still under construction

== Text Views


The Gtk::TextView widget is used to display multiple lines of a text document. It provides many ways to customize the text within the widget. You can even insert Gdk::Pixbuf objects and other child widgets into a document. Gtk::TextView is the first  reasonably involved widget we've encountered so far and in this session we will explore most of its interesting features. It is a versatile widget that you will exploit in many GTK+ applications.

As just hinted, this widget is not only used to display simple text, it can also be used to display many types of rich text, and interactive documents used by a variety of different applications. This is what we will learn here and in the following pages.

Let us start with the simple minimal example of Gtk::TextView widget, that we borrowed in the introduction to scrolling on the previous page. The first thing to remember is that text view has a built in scrolling support and that it has to be added to the Gtk::ScrolledWindow widget. The "textview.rb" listing illustrates the simplest text view example that you could create:


#!/usr/bin/env ruby
require 'gtk2'

window ="Text Views")
window.resizable = true
window.border_width = 10
window.signal_connect('destroy') { Gtk.main_quit }
window.set_size_request(250, 150)

textview =
textview.buffer.text = "Your 1st Gtk::TextView widget!"

scrolled_win =
scrolled_win.border_width = 5
scrolled_win.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)


=== Text Buffers

Each text view is used to display the contents of a class called Gtk::TextBuffer. Text buffers are used to store the current state of the container within the text view. You can guess this from the following line in our example program above.

textview.buffer.text = "Your 1st Gtk::TextView widget!"

Here the buffer component is the Gtk::TextBuffer. Text buffers hold text, images, child widgets, text tags and other information necessary for rendering the documents. A Gtk::TextBuffer buffer is an independent object and can be displayed by many text view widgets. However any text view has  only a single text buffer associated with it. Most programmers do not take advantage of this feature, but it will become important  latter when you learn how to embed child widgets into a text buffer.

:A Short D-tour:

    If you understand the relationship between the two Gtk classes, namely between Gtk::TextView and Gtk::TextBuffer, you will not miss anything by ignoring this D-tour. But if you are not exactly sure what was just said in the above paragraph, then following short demonstration simulating how Gtk::TextView and Gtk::TextBuffer are implemented, may help you understand this relationship and show you how to exploit this design to create some text views that share the same Gtk::TextBuffer and some that do not.
    In tv-N-tb-example.rb sample program pay attention to three different ((*tview_instance_#*)) TextView instances. The first one, designated with number zero (0) has its own (not shared) TextBuffer, however, the other two (#1 and #2) share the TextBuffer instance:

     #!/usr/bin/env ruby
     class TextView
       attr_accessor :buffer
       def initialize(buffer=nil); @buffer = (buffer) ? buffer : "Auto-Initialzed"; end
     class TextBuffer
       attr_accessor :text
       def initialize(text); @text = text; end
       def to_s; "Class TextBuffer: text=#@text"; end
     def show_text_views_buffer(id, tv_inst)
       puts "Buffer ID=#{id} - #{tv_inst.class}: #{tv_inst.buffer.to_s}"
     tview_instance_0 =    # (nil)
     show_text_views_buffer(0, tview_instance_0)"Some initial text")
     tview_instance_1 =
     tview_instance_2 =
     show_text_views_buffer(1, tview_instance_1)
     tview_instance_2.buffer.text = "Override the initial text with new text."
     puts "----- after overriding text buffer -------"
     show_text_views_buffer(0, tview_instance_0)
     show_text_views_buffer(1, tview_instance_1)
     show_text_views_buffer(2, tview_instance_2)  

    I suggest you run this program and experiment with it, until the design similarity with Gtk::TextView and Gtk::TextBuffer becomes apparent.

Most new text views are created with the When using this method with the default nil argument an empty Gtk::TextBuffer is created for you. This empty text buffer can be replaced or retrieved by "Gtk::TextView#buffer=(buff)", or "Gtk::TextView#set_buffer(buff)", and "buff = Gtk::TextView#buffer" respectively. With the former two methods the contents of the buffer gets completely replaced. However, as we will see on the following page in paragraphs entitled((*Text Iterators and Marks,*))one can also make changes only to small segments of a text buffer, i.e. change text buffer partially.

Recall that we have pointed out that a few widgets provide native scrolling support. Well, Gtk::TextView is one of them. This means you should use Gtk::Container#add method, rather than Gtk::ScrolledWindow#add_with_viewport(child), to add Gtk::TextView to the scrolled windows.



When handling text buffers, you will be dealing with terms such as((*ofset*))and((*index.*))As with all text widgets in GTK+, text is stored in UTF-8 strings, hence individual characters may be more than one byte long. This may effect the overall meaning or value that offset and index will represent. You can tell what is the size in bytes for an UTF-8 character by looking at the initial bit(s) of the character. Consult the table on the left for details.

The Gtk::TextView widget is used word((*index*))refers to display multiple lines of an individual byte, you need to be careful when stepping through a text document. it provides many ways to customize the text within the widget. You can even insert Gdk::Pixbuf objects and other child widgets into a document. Gtk::TextView is the first  reasonably involved widget we've encountered so far and buffer in this session we will explore most of its interesting features. It is a versatile widget that way. In particular you will exploit in many GTK+ applications.can not refer to an index pointing to the position between two characters.

At the first glance you may think that this widget may only be used  to display simple text, however that is not the case. It can also be used to display many types of rich text, and interactive documents used by a variety of different applications. This is what we will learn here in the following few articles.

Let us start with a simple example of Gtk::TextView widget inside a Gtk::ScrolledWindow widget:=== Text View Properties


Gtk::TextView widget was created to be very versatile. Because of this, many properties are provided for the widget. In the next example program we will look only at the properties that apply changes to the whole buffer. We will look at the possibility to affect only part of the text buffer shortly when discussing((*tags.*))

Let's have a look at the following example program demonstrating how properties can be used to customize the text:



#!/usr/bin/env ruby
require 'gtk2'

def destroy; Gtk.main_quit; end

window =
window.resizable = true
window.title = "Text Views"View Properties"
window.border_width = 10
window.signal_connect('delete_event') { destroy }
window.set_size_request(250, 150)

textview =
font ="Monospace Bold 10")
textview.wrap_mode = Gtk::TextTag::WRAP_WORD
textview.justification = Gtk::JUSTIFY_RIGHT
textview.editable =  true
textview.cursor_visible =  true
textview.pixels_above_lines = 5
textview.pixels_below_lines = 5
textview.pixels_inside_wrap = 5
textview.left_margin = 10
textview.right_margin = 10
textview.buffer.text = "This is some text!\nChange me!\nPlease!"

scrolled_win =
scrolled_win.border_width = 5
scrolled_win.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)


The following two properties need the reference to GTK+ constants:

textview.wrap_mode = Gtk::TextTag::WRAP_WORD

For your convenience I list all the relevant GTK constants also here:

    * Gtk::TextTag::WRAP_NONE - do not wrap lines; just make the text area wider.
    * Gtk::TextTag::WRAP_CHAR - wrap text, breaking lines anywhere the cursor can appear (between characters, usually - if you want to be technical, between graphemes, see Pango.get_log_attrs).
    * Gtk::TextTag::WRAP_WORD - wrap text, breaking lines in between words.
    * Gtk::TextTag::WRAP_WORD_CHAR - wrap the same as Gtk::TextTag::WRAP_WORD, but if the whole word takes up more than the whole visible width of the text view, wrap it by the character.

You can find the constants for the above line at: ((<Gtk::TextTag#GtkWrapMode>))

textview.justification = Gtk::JUSTIFY_RIGHT

For your convenience:

    * Gtk::JUSTIFY_LEFT - The text is placed at the left edge of the label.
    * Gtk::JUSTIFY_RIGHT - The text is placed at the right edge of the label.
    * Gtk::JUSTIFY_CENTER - The text is placed in the center of the label.
    * Gtk::JUSTIFY_FILL - The text is placed is distributed across the label.

And again, you can find these constants for the above code segment at: ((<Gtk#GtkJustification>))

:Gtk::TextView#editable? and Gtk::Widget#sensitive?:

    Sometimes you may want to prevent users from editing the document. You accomplish this with the Gtk::TextView#editable= method to set the editable property. Though this property is used to set this behaviour for the entire text buffer, with ((*text tags*)) you can override this to affect only a part of the text. Compare this with Gtk::Widget#sensitive= which is even more restrictive than Gtk::TextView#editable=. With sensitive you can also disallow a text to be selected and perform cut-and-paste operations, which are still allowed if you set the text only not to be editable.

=== You will often want to change font

Changing font is easy. You first need to obtain a valid font name, sometimes also called description, since it describes font properties such as "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]". In API we find the following for Pango::FontDescription: = nil):  
    Creates a new font description from a string representation in the form "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]", where FAMILY-LIST is a comma separated list of families optionally terminated by a comma, STYLE_OPTIONS is a whitespace separated list of words where each WORD describes one of style, variant, weight, or stretch, and SIZE is an decimal number (size in points). Any one of the options may be absent. If FAMILY-LIST is absent, then the family_name field of the resulting font description will be initialized to nil. If STYLE-OPTIONS is missing, then all style options will be set to the default values. If SIZE is missing, the size in the resulting font description will be set to 0. If str is nil, constructor creates a new font description structure with all fields unset.

In our example we set the font with the following code:

font ="Monospace Bold 10")

Sometimes you may want to give user the control over which font style and size they would like to set the font to. In that event you would most likely employ((*Font Selection Dialog*))and then initialiye the font in a way reminiscent of the code we have just seen. Let's run our imagination and pretend we needed something like the following:

font = dialog.font_name
desc =

For a few more explanations and examples check the ((<Font Manipulation Methods|tut-gtk2-fichoo-fontbtt#Font Manipulation Methods>)) in this tutorial.

=== Pango Tab Arrays

You' ve seen Pango a few times already in our tutorials. Lets first see, how it is defined on Wiki pages:

:What is Pango:
    Pango is an LGPL licensed free software computing library used by software developers for laying out and rendering text in high quality, emphasising support for multilingual text. Different font backends can be used, allowing cross-platform support, so that Pango-rendered text will appear similar under different operating systems, such as Linux, Apple's Mac OS, and Microsoft Windows.


Here we are discussing((*Pango Tab Arrays*))in relation to editing a text buffer.((*TABs*))are a special kind of character that can seem to behave a little bit differently, depending on which font is currently active. The most consistent behavior produce((*monospaced*))fonts. This is because all characters for such a font take up the same amount of space on a graphical display. On the image depicting our next program example, here on the right, you can see that cursor is at the position fifteen spaces to the right from the left margin. Incidentally this is also the TAB size. You can run the program and see for yourself, that this indeed is where the TAB key would position the cursor if you pressed it after you started the sample program.

Tabs added to a text view are set to a default width, but there are times when this is not what you want. GTK+ provides Pango::TabArray object, which can help you define a new tab size. In order to change the tab size you must first calculate the number of horizontal pixels the tab will take up based on the current font. Let us expand our first simple example (textview.rb) by adding a tab size altering function called ((*make_tab_array.*)) In this program the tab size is arbitrarily restricted be less than 20 characters.


#!/usr/bin/env ruby
require 'gtk2'

def make_tab_array(textview, tab_size, font_desc)
   raise "Tab size can't be more than 20" if tab_size > 20
   tab_string = " " * tab_size
   layout = textview.create_pango_layout(tab_string)
   layout.font_description = font_desc
   width, height = layout.pixel_size
   tab_array =, true)
   tab_array.set_tab(0, Pango::TAB_LEFT, width)

window =
window.resizable = true
window.title = "TABs in Text Views"
window.border_width = 10

window.signal_connect('delete_event') { Gtk.main_quit }
window.set_size_request(250, 150)

textview =
textview.buffer.text = "Your 1st Gtk::TextView widget!""Tab is now set to 15!\n" +
                        "You can hit the TAB key\n" +
                        "and see for yourself:\n" +

# For font styles "Italic", "Bold", "Bold Italic" and
# "Regular" currently, all except "Regular" work fine.
# However, this is really not a Ruby but general version
# "C" GTK+ problem!
font ="Monospace Italic 8")
make_tab_array(textview, 15, font)

scrolled_win =
scrolled_win.border_width = 5
scrolled_win.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)


The Pango::Layout object is used to represent a whole paragraph of text. Normally, Pango uses it internally for laying out text within a widget. However, it can be employed as in our example in the ((*make_tab_array*)) function to calculate the width of the tab string. Note that using tab, let alone changing it makes sense only when you have a mono-spaced text as well when you use the same font through out the text.

In ((*make_tab_array*))method we use Pango::Layout object and a set of other Pango devices to set up our ((*TAB.*))We start up with Gtk::Widget#create_pango_layout(text=nil). In general Pango::Layout object is created by, which creates a new Pango::Layout object with attributes initialized to default values for a particular Pango::Context. However, in our sample program we are employing Gtk::Widget#create_pango_layout, with a string parameter containing as many spaces as we would like our TAB to expand. instead. API documentation tells us that Gtk::Widget#create_pango_layout(text=nil) creates a new Pango::Layout with the appropriate colormap, font description, and base direction for drawing text for this widget.

Next we need to tell our Pango::Layout object what is the font we are using in the text buffer, for which we wish to calculate TAB size. At this point we can request the pixel size, which returns an array of width and height elements. As TAB is concerned with the horizontal layout only, we are interested in width only. We will need to convey the size to Pango::TabArray, which we create next. We will accomplish this with  Pango::TabArray#set_tab to which just obtained pixel width is passed as the third argument. Finally we set the tabs for our text buffer and pass it our tab array object as the argument.

Between the following are the descriptions of the methods we used in order to implement our tab size altering functionality:

--- Gtk::Widget#create_pango_layout(text=nil)

    Creates a new Pango::Layout with the appropriate colormap, font description, and base direction for drawing text for this widget.
    If you keep a Pango::Layout created in this way around, in order notify the layout of changes to the base direction or font of this widget, you must call Pango::Layout#context_changed in response to the ::style_set and ::direction_set signals for the widget.
    * text: text to set on the layout (can be nil)
    * Returns: the new Pango::Layout

--- Pango::Layout#font_description

    Gets the font description for the layout, if any.
    * Returns: the layout's font description(Pango::FontDescription), or nil if the font description from the layout's context is inherited.

--- Pango::Layout#font_description=(desc)

    Sets the default font description for the layout. If no font description is set on the layout, the font description from the layout's context is used.
    * desc: the new Pango::FontDescription, or nil to unset the current font description.
    * Returns: desc

--- Pango::Layout#pixel_size

    Determines the logical width and height of a Pango::Layout in device units. (Pango::Layout#size returns the width and height in thousandths of a device unit.) This is simply a convenience method around Pango::Layout#extents.
    * Returns: [width, height]
       * width: the logical width
       * height: the logical height

--- Pango::TabArray#set_tab(0, Pango::TAB_LEFT, width)

    Before applying the tab array, you need to add the width.
    * 0: refers to the first element in the Pango::TabArray, the only one that should ever exist.
    * Pango::TAB_LEFT - must always be specified; it is the only constant in ((<Pango#TabAlign>))
    * width: the width of the tab in pixels
    * Returns: self: ((*FIXME ??? *))

--- Gtk::TextView#tabs

    Gets the default tabs for text_view. Tags in the buffer may override the defaults. The returned array will be nil if "standard" (8-space) tabs are used.
    * Returns: copy of default tab array, or nil if "standard" tabs are used

--- Gtk::TextView#tabstabs=(tabs)

    Sets the default tab stops for paragraphs in the Gtk::TextView. Tags in the buffer may override the default.
    * tabs: tabs as a Pango::TabArray
    * Returns: tabs

--- Gtk::TextView#tabsset_tabs(tabs)

    Same as Gtk::TextView#tabs=.
    * tabs: tabs as a Pango::TabArray
    * Returns: self

Last modified:2021/11/30 10:11:18