[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13. Miscellaneous Widgets


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.1 Arrows

figures/arrow-buttons

Figure 13.1: Arrows

The arrow widget draws an arrowhead, facing in a number of possible directions and having a number of possible styles. It can be very useful when placed on a button. Like the label widget, the arrow widget emits no signals. There are only two functions for manipulating an arrow widget gtk-arrow-new and gtk-arrow-set. The first function creates a new arrow widget with the indicated type and appearance. The second function allows these values to be altered retrospectively. The type of an arrow can be one of of the values of the enumeration type gtk-arrow-type. Possible values are :up, :down, :left and :right. These values obviously indicate the direction in which the arrow will point.

The shadow type argument is of the enumeration type gtk-shadow-type and may take one of the the values :none, :in, :etched-in and :etched-out.

The amount of space used by the arrow is controlled by the style property arrow-scaling. The style property arrow-scaling takes values of type double in a range of [0,1]. The default value is 0.7.

example-arrows shows a brief example to illustrate the use of arrows in buttons. In addition, this example introduces the function gtk-widget-tooltip-text, which attaches a tooltip to the button widget. The tooltip pops up, when the mouse is over the button.

Example 13.1: Buttons with Arrows

(defun create-arrow-button (arrow-type shadow-type)
  (let (;; Create a button
        (button (make-instance 'gtk-button
                               ;; Add a small margin around the button
                               :margin 3
                               ;; Make big buttons of size 75 x 75
                               :width-request 75
                               :height-request 75)))
    ;; Add an arrow to the button
    (gtk-container-add button
                       (make-instance 'gtk-arrow
                                      :arrow-type arrow-type
                                      :shadow-type shadow-type))
    ;; Add a tooltip to the button
    (setf (gtk-widget-tooltip-text button)
          (format nil "Arrow of type ~A" (symbol-name arrow-type)))
    button))

(defun example-arrows ()
  (within-main-loop
    (let ((;; Create the main window
           window (make-instance 'gtk-window
                                 :type :toplevel
                                 :title "Example Arrow Buttons"
                                 :default-width 275
                                 :default-height 125
                                 :border-width 12))
          ;; Create a grid for the buttons
          (grid (make-instance 'gtk-grid
                               :orientation :horizontal
                               :column-homogeneous t)))
      ;; Connect a signal handler to the window
      (g-signal-connect window "destroy"
                        (lambda (widget)
                          (declare (ignore widget))
                          (leave-gtk-main)))
      ;; Create buttons with an arrow and add the buttons to the grid
      (gtk-container-add grid (create-arrow-button :up :in))
      (gtk-container-add grid (create-arrow-button :down :out))
      (gtk-container-add grid (create-arrow-button :left :etched-in))
      (gtk-container-add grid (create-arrow-button :right :etched-out))
      ;; Add the grid to the window
      (gtk-container-add window grid)
      ;; Show the window
      (gtk-widget-show-all window))))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.2 Calendar

figures/calendar

Figure 13.2: Calendar

The gtk-calendar widget displays a Gregorian calendar, one month at a time. It can be created with the function gtk-calendar-new.

The month and year currently displayed can be altered with the function gtk-calendar-select-month. The exact day can be selected from the displayed month using the function gtk-calendar-select-day.

To place a visual marker on a particular day, use the function gtk-calendar-mark-day and to remove the marker the function gtk-calendar-unmark-day. Alternative, all marks can be cleared with the function gtk-calendar-clear-marks.

The way in which the calendar itself is displayed can be altered using the function gtk-calendar-set-display-options.

The selected date can be retrieved from a gtk-calendar using the function gtk-calendar-get-date.

Users should be aware that, although the Gregorian calendar is the legal calendar in most countries, it was adopted progressively between 1582 and 1929. Display before these dates is likely to be historically incorrect.

example-calendar shows a brief example of the calendar widget. It is possible to set a special function with the function gtk-calendar-set-detail-func. The example uses this to show a tooltip whenever the 12th day of a month is selected.

Example 13.2: Example Calendar

(defun example-calendar ()
  (within-main-loop
    (let ((window (make-instance 'gtk-window
                                 :title "Example Calendar"
                                 :type :toplevel
                                 :border-width 24
                                 :default-width 250
                                 :default-height 100))
          (frame (make-instance 'gtk-frame))
          (calendar (make-instance 'gtk-calendar
                                   :show-details nil)))
      ;; Connect a signal handler to the window
      (g-signal-connect window "destroy"
                        (lambda (widget)
                          (declare (ignore widget))
                          (leave-gtk-main)))
      ;; Connect a signal handler to print the selected day
      (g-signal-connect calendar "day-selected"
                        (lambda (widget)
                          (declare (ignore widget))
                          (format t "selected: year ~A month ~A day ~A~%"
                                  (gtk-calendar-year calendar)
                                  (gtk-calendar-month calendar)
                                  (gtk-calendar-day calendar))))
      ;; Install a calendar detail function
      (gtk-calendar-set-detail-func calendar
                                    (lambda (calendar year month day)
                                      (declare (ignore calendar year month))
                                      (when (= day 12)
                                        "This day has a tooltip.")))
      ;; Mark a day
      (gtk-calendar-mark-day calendar 6)
      ;; Put the calendar into the frame and the frame into the window.
      (gtk-container-add frame calendar)
      (gtk-container-add window frame)
      (gtk-widget-show-all window))))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.3 Event Box

figures/event-box

Figure 13.3: Event Box

Some GTK+ widgets do not have associated X windows, so these widgets just draw on their parents. Because of this, they cannot receive events and if they are incorrectly sized, they do not clip so you can get messy overwriting. If you require more from these widgets, the GtkEventBox widget is for you.

At first glance, the GtkEventBox widget might appear to be totally useless. It draws nothing on the screen and responds to no events. However, it does serve a function - it provides an X window for its child widget. This is important as many GTK+ widgets do not have an associated X window. Not having an X window saves memory and improves performance, but also has some drawbacks. A widget without an X window cannot receive events, and does not perform any clipping on its contents. Although the name GtkEventBox emphasizes the event-handling function, the widget can also be used for clipping.

To create a new GtkEventBox widget, use the call (make-instance 'gtk-event-box) or the function gtk-event-box-new. A child widget can then be added to this GtkEventBox with the function gtk-container-add. With the function gtk-widget-events the events are set for the event box which can be connected to a signal handler. To create the resources associated with an event box, the function gtk-widget-realize has to be called explicitly for the GtkEventBox widget.

example-event-box demonstrates both uses of a GtkEventBox widget - a label is created that is clipped to a small box, and set up so that a mouse-click on the label causes the program to exit. Resizing the window reveals varying amounts of the label.

In addition, example-event-box shows how to change the mouse pointer over a window. Every widget has an associated window of type GdkWindow, which can be get with the function gtk-widget-window. The function gdk-window-set-cursor sets a mouse pointer for this GdkWindow. A new mouse pointer is created with the function gdk-cursor-new. The functions takes one argument, which is a keyword of the enumeration type GdkCursorType for a predefined mouse pointer. GTK+ has about 150 predefined mouse pointers. Look at the implementation of GdkCursorType in the file gdk.cursor.lisp to see all possible keywords. In example-event-box the mouse pointer :hand1 is chosen. This mouse pointer is than associated to the GdkWindow with the function gdk-window-set-cursor.

Example 13.3: Event Box

(defun example-event-box ()
  (within-main-loop
    (let ((window (make-instance 'gtk-window
                                 :type :toplevel
                                 :title "Example Event Box"
                                 :border-width 12))
          (eventbox (make-instance 'gtk-event-box))
          (label (make-instance 'gtk-label
                                :label
                                "Click here to quit, and more text, more")))
      (g-signal-connect window "destroy"
                        (lambda (widget)
                          (declare (ignore widget))
                          (leave-gtk-main)))
      ;; Set the events for the event box
      (setf (gtk-widget-events eventbox) :button-press-mask)
      ;; Connect a signal to the eventbox
      (g-signal-connect eventbox "button-press-event"
                        (lambda (widget event)
                          (declare (ignore widget event))
                          (gtk-widget-destroy window)))
      ;; Add the label to the event box and the event box to the window
      (gtk-container-add eventbox label)
      (gtk-container-add window eventbox)
      ;; Realize the event box
      (gtk-widget-realize eventbox)
      ;; Set a new cursor for the event box
      (gdk-window-set-cursor (gtk-widget-window eventbox)
                             (gdk-cursor-new :hand1))
      ;; Show the window
      (gtk-widget-show-all window))))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.4 Text Entries

figures/text-entry256x106

Figure 13.4: Text Entry

The entry widget allows text to be typed and displayed in a single line text box. The text may be set with function calls that allow new text to replace, prepend or append the current contents of the Entry widget.

Create a new Entry widget with the function gtk-entry-new. The generic function gtk-entry-text alters the text which is currently within the entry widget. The function gtk-entry-text sets the contents of the entry widget, replacing the current contents. Note that the class entry implements the editable interface which contains some more functions for manipulating the contents.

The contents of the entry can be retrieved by using a call to the function gtk-entry-text. This is useful in the callback functions described below.

If we do not want the contents of the entry to be changed by someone typing into it, we can change its editable state with the function gtk-editable-set-editable. This function allows us to toggle the editable state of the entry widget by passing in a T or NIL value for the editable argument.

If we are using the entry where we do not want the text entered to be visible, for example when a password is being entered, we can use the function gtk-entry-visibility, which also takes a boolean flag.

A region of the text may be set as selected by using the function gtk-editable-select-region. This would most often be used after setting some default text in an Entry, making it easy for the user to remove it.

If we want to catch when the user has entered text, we can connect to the activate or changed signal. Activate is raised when the user hits the enter key within the entry widget. Changed is raised when the text changes at all, e.g., for every character entered or removed.

example-text-entry is an example of using an entry widget.

Example 13.4: Text Entry

(defun example-text-entry ()
  (within-main-loop
    (let* ((window (make-instance 'gtk-window
                                  :type :toplevel
                                  :title "Example Text Entry"
                                  :default-width 250))
           (vbox (make-instance 'gtk-vbox))
           (hbox (make-instance 'gtk-hbox))
           (entry (make-instance 'gtk-entry
                                 :text "Hello"
                                 :max-length 50))
           (pos (gtk-entry-text-length entry)))
      (g-signal-connect window "destroy"
                        (lambda (widget)
                          (declare (ignore widget))
                          (leave-gtk-main)))
      (g-signal-connect entry "activate"
                        (lambda (widget)
                          (declare (ignore widget))
                          (format t "Entry contents: ~A"
                                  (gtk-entry-text entry))))
      (gtk-editable-insert-text entry " world" pos)
      (gtk-editable-select-region entry 0 (gtk-entry-text-length entry))
      (gtk-box-pack-start vbox entry :expand t :fill t :padding 0)
      (let ((check (gtk-check-button-new-with-label "Editable")))
        (g-signal-connect check "toggled"
           (lambda (widget)
             (declare (ignore widget))
             (gtk-editable-set-editable
                                      entry
                                      (gtk-toggle-button-active check))))
        (gtk-box-pack-start hbox check))
      (let ((check (gtk-check-button-new-with-label "Visible")))
        (setf (gtk-toggle-button-active check) t)
        (g-signal-connect check "toggled"
           (lambda (widget)
             (declare (ignore widget))
             (setf (gtk-entry-visibility entry)
                   (gtk-toggle-button-active check))))
        (gtk-box-pack-start hbox check))
      (gtk-box-pack-start vbox hbox)
      (let ((button (gtk-button-new-from-stock "gtk-close")))
        (g-signal-connect button "clicked"
                          (lambda (widget)
                            (declare (ignore widget))
                            (gtk-widget-destroy window)))
        (gtk-box-pack-start vbox button))
      (gtk-container-add window vbox)
      (gtk-widget-show window))))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.5 Spin Buttons

figures/spin-button306x347

Figure 13.5: Spin Button

The spin button widget is generally used to allow the user to select a value from a range of numeric values. It consists of a text entry box with up and down arrow buttons attached to the side. Selecting one of the buttons causes the value to "spin" up and down the range of possible values. The entry box may also be edited directly to enter a specific value.

The spin button allows the value to have zero or a number of decimal places and to be incremented or decremented in configurable steps. The action of holding down one of the buttons optionally results in an acceleration of change in the value according to how long it is depressed.

The spin button uses an adjustment object to hold information about the range of values that the spin button can take. This makes for a powerful spin button widget.

Recall that an adjustment object is created with the function gtk-adjustment-new, which has the arguments value, lower, step-increment, page-increment, and page-size. These properties of an adjustment are used by the spin button in the following way:

value

initial value for the Spin Button

lower

lower range value

upper

upper range value

step-increment

value to increment/decrement when pressing mouse button 1 on a button

page_increment

value to increment/decrement when pressing mouse button 2 on a button

page_size

unused

Additionally, mouse button 3 can be used to jump directly to the upper or lower values when used to select one of the buttons. A spin button is created with the function gtk-spin-button-new, which as the arguments adjustment, climb-rate, and digits.

The climb-rate argument take a value between 0.0 and 1.0 and indicates the amount of acceleration that the spin button has. The digits argument specifies the number of decimal places to which the value will be displayed.

A spin button can be reconfigured after creation using the function gtk-spin-button-configure. The first argument specifies the spin button that is to be reconfigured. The other arguments are as specified for the function gtk-spin-button-new.

The adjustment can be set and retrieved independently using the two functions gtk-spin-button-set-adjustment and gtk-spin-button-get-adjustment.

The number of decimal places can also be altered using the function gtk-spin-button-set-digits and the value that a spin button is currently displaying can be changed using the function gtk-spin-button-set-value.

The current value of a spin button can be retrieved as either a floating point or integer value with the functions gtk-spin-button-value and gtk-spin-button-get-value-as-int.

If you want to alter the value of a spin button relative to its current value, then the function gtk-spin-button-spin can be used, which has the three arguments spin-button, direction, and increment. The argument direction is of the enumeration type GtkSpinType, which can take one of the values shown in table-gtk-spin-type.

Table 13.1: The values of the GtkSpinType enumeration are used to specify the change to make in gtk-spin-button-spin

:step-forward

Increment by the adjustments step increment.

:backward

Decrement by the adjustments step increment.

:forward

Increment by the adjustments page increment.

:page-backward

Decrement by the adjustments page increment.

:home

Go to the adjustments lower bound.

:end

Go to the adjustments upper bound.

:user-defined

Change by a specified amount.

:step-forward and :step-backward change the value of the spin button by the amount specified by increment, unless increment is equal to 0, in which case the value is changed by the value of step-increment in the adjustment.

:page-forward and :page-backward simply alter the value of the spin button by increment.

:home sets the value of the spin button to the bottom of the adjustments range and :end sets the value of the spin button to the top of the adjustments range.

:user-defined simply alters the value of the spin button by the specified amount.

We move away from functions for setting and retrieving the range attributes of the spin button now, and move onto functions that affect the appearance and behavior of the spin button widget itself.

The first of these functions is gtk-spin-button-set-numeric, which is used to constrain the text box of the spin button such that it may only contain a numeric value. This prevents a user from typing anything other than numeric values into the text box of a spin button.

You can set whether a Spin Button will wrap around between the upper and lower range values with the function gtk-spin-button-set-wrap. You can set a spin button to round the value to the nearest step-increment, which is set within the adjustment object used with the spin button. This is accomplished with the function gtk-spin-button-set-snap-to-ticks.

The update policy of a spin button can be changed with the function gtk-spin-button-set-update-policy. The possible values of policy are either :always or :if-valid. These policies affect the behavior of a Spin Button when parsing inserted text and syncing its value with the values of the adjustment.

In the case of :if-valid the spin button value only gets changed if the text input is a numeric value that is within the range specified by the adjustment. Otherwise the text is reset to the current value. In case of :always we ignore errors while converting text into a numeric value.

Finally, you can explicitly request that a spin button update itself with the function gtk-spin-button-update.

Example 13.5: Spin Button

(defun example-spin-button ()
  (within-main-loop
    (let ((window (make-instance 'gtk-window
                                 :type :toplevel
                                 :title "Example Spin Button"
                                 :default-width 300))
          (vbox (make-instance 'gtk-vbox
                               :homogeneous nil
                               :spacing 6
                               :border-width 12))
          (vbox1 (make-instance 'gtk-vbox
                                :homogeneous nil
                                :spacing 0
                                :border-width 6))
          (vbox2 (make-instance 'gtk-vbox
                                :homogeneous nil
                                :spacing 0
                                :boder-width 6))
          (hbox (make-instance 'gtk-hbox))
          (frame1 (make-instance 'gtk-frame
                                 :label "Not accelerated"))
          (frame2 (make-instance 'gtk-frame
                                 :label "Accelerated"))
          (label (make-instance 'gtk-label
                                :label "0")))
      (g-signal-connect window "destroy"
                        (lambda (widget)
                          (declare (ignore widget))
                          (leave-gtk-main)))
      (let ((vbox (make-instance 'gtk-vbox))
            (spinner (make-instance 'gtk-spin-button
                                    :adjustment
                                    (make-instance 'gtk-adjustment
                                                   :value 1.0
                                                   :lower 1.0
                                                   :upper 31.0
                                                   :step-increment 1.0
                                                   :page-increment 5.0
                                                   :page-size 0.0)
                                    :climb-rate 0
                                    :digits 0
                                    :wrap t)))
        (gtk-box-pack-start vbox
                            (make-instance 'gtk-label
                                           :label "Day :"
                                           :xalign 0
                                           :yalign 0.5)
                            :expand nil)
        (gtk-box-pack-start vbox spinner :expand nil)
        (gtk-box-pack-start hbox vbox :padding 6))
      (let ((vbox (make-instance 'gtk-vbox))
            (spinner (make-instance 'gtk-spin-button
                                    :adjustment
                                    (make-instance 'gtk-adjustment
                                                   :value 1.0
                                                   :lower 1.0
                                                   :upper 12.0
                                                   :step-increment 1.0
                                                   :page-increment 5.0
                                                   :page-size 0.0)
                                    :climb-rate 0
                                    :digits 0
                                    :wrap t)))
        (gtk-box-pack-start vbox
                            (make-instance 'gtk-label
                                           :label "Month :"
                                           :xalign 0
                                           :yalign 0.5)
                            :expand nil)
        (gtk-box-pack-start vbox spinner :expand nil)
        (gtk-box-pack-start hbox vbox :padding 6))
      (let ((vbox (make-instance 'gtk-vbox))
            (spinner (make-instance 'gtk-spin-button
                                    :adjustment
                                    (make-instance 'gtk-adjustment
                                                   :value 1.0
                                                   :lower 1998.0
                                                   :upper 2100.0
                                                   :step-increment 1.0
                                                   :page-increment 100.0
                                                   :page-size 0.0)
                                    :climb-rate 0
                                    :digits 0
                                    :wrap t)))
        (gtk-box-pack-start vbox
                            (make-instance 'gtk-label
                                           :label "Year :"
                                           :xalign 0
                                           :yalign 0.5)
                            :expand nil)
        (gtk-box-pack-start vbox spinner :expand nil :fill t)
        (gtk-box-pack-start hbox vbox :padding 6))
      (gtk-box-pack-start vbox1 hbox :padding 6)
      (gtk-container-add frame1 vbox1)
      (gtk-box-pack-start vbox frame1)
      (setq hbox (make-instance 'gtk-hbox))
      (let ((vbox (make-instance 'gtk-vbox))
            (spinner1 (make-instance 'gtk-spin-button
                                     :adjustment
                                     (make-instance 'gtk-adjustment
                                                    :value 1.0
                                                    :lower -10000.0
                                                    :upper  10000.0
                                                    :step-increment 0.5
                                                    :page-increment 100.0
                                                    :page-size 0.0)
                                     :climb-rate 1.0
                                     :digits 2
                                     :wrap t))
            (spinner2 (make-instance 'gtk-spin-button
                                     :adjustment
                                     (make-instance 'gtk-adjustment
                                                    :value 2
                                                    :lower 1
                                                    :upper 5
                                                    :step-increment 1
                                                    :page-increment 1
                                                    :page-size 0)
                                     :climb-rate 0.0
                                     :digits 0
                                     :wrap t)))
        (gtk-box-pack-start vbox
                            (make-instance 'gtk-label
                                           :label "Value :"
                                           :xalign 0
                                           :yalign 0.5)
                            :fill t)
        (gtk-box-pack-start vbox spinner1 :expand nil)
        (gtk-box-pack-start hbox vbox :padding 6)
        (g-signal-connect spinner2 "value-changed"
           (lambda (widget)
             (declare (ignore widget))
             (gtk-spin-button-set-digits
                               spinner1
                               (gtk-spin-button-get-value-as-int spinner2))))
        (setq vbox (make-instance 'gtk-vbox))
        (gtk-box-pack-start vbox
                            (make-instance 'gtk-label
                                           :label "Digits :"
                                           :xalign 0
                                           :yalign 0.5)
                            :expand nil)
        (gtk-box-pack-start vbox spinner2 :expand nil)
        (gtk-box-pack-start hbox vbox :padding 6)
        (gtk-box-pack-start vbox2 hbox :padding 6)
        (let ((check (make-instance 'gtk-check-button
                                    :label "Snap to 0.5-ticks"
                                    :active t)))
          (g-signal-connect check "clicked"
             (lambda (widget)
               (gtk-spin-button-set-snap-to-ticks
                                     spinner1
                                     (gtk-toggle-button-active widget))))
          (gtk-box-pack-start vbox2 check))
        (let ((check (make-instance 'gtk-check-button
                                    :label "Numeric only input mode"
                                    :active t)))
          (g-signal-connect check "clicked"
             (lambda (widget)
               (gtk-spin-button-set-numeric
                                     spinner1
                                     (gtk-toggle-button-active widget))))
          (gtk-box-pack-start vbox2 check))
        (gtk-container-add frame2 vbox2)
        (setq hbox (make-instance 'gtk-hbox))
        (let ((button (gtk-button-new-with-label "Value as Int")))
          (g-signal-connect button "clicked"
             (lambda (widget)
               (declare (ignore widget))
               (gtk-label-set-text
                      label
                      (format nil "~A"
                              (gtk-spin-button-get-value-as-int spinner1)))))
            (gtk-box-pack-start hbox button))
        (let ((button (gtk-button-new-with-label "Value as Float")))
          (g-signal-connect button "clicked"
             (lambda (widget)
               (declare (ignore widget))
               (gtk-label-set-text
                             label
                             (format nil "~A"
                                     (gtk-spin-button-value spinner1)))))
          (gtk-box-pack-start hbox button))
        (gtk-box-pack-start vbox2 hbox)
        (gtk-box-pack-start vbox2 label))
      (gtk-box-pack-start vbox frame2)
      (let ((button (make-instance 'gtk-button
                                   :label "Close")))
        (g-signal-connect button "clicked"
                          (lambda (widget)
                            (declare (ignore widget))
                            (gtk-widget-destroy window)))
        (gtk-box-pack-start vbox button))
      (gtk-container-add window vbox)
      (gtk-widget-show window))))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.6 Combo Box


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.6.1 General Combo Box

figures/combo-box386x131

Figure 13.6: Combo Box

A gtk-combo-box is a widget that allows the user to choose from a list of valid choices. The gtk-combo-box displays the selected choice. When activated, the gtk-combo-box displays a popup which allows the user to make a new choice. The style in which the selected value is displayed, and the style of the popup is determined by the current theme. It may be similar to a Windows-style combo box.

The gtk-combo-box uses the model-view pattern; the list of valid choices is specified in the form of a tree model, and the display of the choices can be adapted to the data in the model by using cell renderers, as you would in a tree view. This is possible since gtk-combo-box implements the gtk-cell-layout interface. The tree model holding the valid choices is not restricted to a flat list, it can be a real tree, and the popup will reflect the tree structure.

To allow the user to enter values not in the model, the has-entry property allows the gtk-combo-box to contain a gtk-entry. This entry can be accessed by calling gtk-bin-get-child on the combo box.

For a simple list of textual choices, the model-view API of gtk-combo-box can be a bit overwhelming. In this case, gtk-combo-box-text offers a simple alternative. Both gtk-combo-box and gtk-combo-box-text can contain an entry.

Example 13.6: Combo Box

(defun example-combo-box ()
  (within-main-loop
    (let* ((window (make-instance 'gtk-window
                                  :type :toplevel
                                  :border-width 12
                                  :title "Example Combo Box"))
           (model (make-instance 'gtk-list-store
                                 :column-types '("gchararray" "gint")))
           (combo-box (make-instance 'gtk-combo-box :model model))
           (title-label (make-instance 'gtk-label :label "Title:"))
           (value-label (make-instance 'gtk-label :label "Value:"))
           (title-entry (make-instance 'gtk-entry))
           (value-entry (make-instance 'gtk-entry))
           (button (make-instance 'gtk-button :label "Add"))
           (table (make-instance 'gtk-table
                                 :n-rows 3
                                 :n-columns 3)))
      ;; Fill in data into the columns
      (gtk-list-store-set model (gtk-list-store-append model) "Monday" 1)
      (gtk-list-store-set model (gtk-list-store-append model) "Tuesday" 2)
      (gtk-list-store-set model (gtk-list-store-append model) "Wednesday" 3)
      (gtk-list-store-set model (gtk-list-store-append model) "Thursday" 4)
      (gtk-list-store-set model (gtk-list-store-append model) "Friday" 5)
      (gtk-list-store-set model (gtk-list-store-append model) "Saturday" 6)
      (gtk-list-store-set model (gtk-list-store-append model) "Sunday" 7)
      ;; Set the first entry to active
      (gtk-combo-box-set-active combo-box 0)
      ;; Define the signal handlers
      (g-signal-connect window "destroy"
                        (lambda (w)
                          (declare (ignore w))
                          (leave-gtk-main)))
      (g-signal-connect button "clicked"
         (lambda (widget)
           (declare (ignore widget))
           (gtk-list-store-set model
                               (gtk-list-store-append model)
                               (gtk-entry-text title-entry)
                               (or (parse-integer
                                     (gtk-entry-text value-entry)
                                     :junk-allowed t)
                                   0))))
      (g-signal-connect combo-box "changed"
         (lambda (widget)
           (declare (ignore widget))
           (let ((dialog (gtk-message-dialog-new
                             window
                             '(:destroy-with-parent)
                             :info
                             :close
                             "You selected row ~A"
                             (gtk-combo-box-get-active combo-box))))
             (gtk-dialog-run dialog)
             (gtk-widget-destroy dialog))))
      ;; Create renderers for the cells
      (let ((renderer (make-instance 'gtk-cell-renderer-text
                                     :text "A text")))
        (gtk-cell-layout-pack-start combo-box renderer :expand t)
        (gtk-cell-layout-add-attribute combo-box renderer "text" 0))
      (let ((renderer (make-instance 'gtk-cell-renderer-text
                                     :text "A number")))
        (gtk-cell-layout-pack-start combo-box renderer :expand nil)
        (gtk-cell-layout-add-attribute combo-box renderer "text" 1))
      ;; Align the labels
      (gtk-misc-set-alignment title-label 0.0 0.0)
      (gtk-misc-set-alignment value-label 0.0 0.0)
      ;; Put the widgets into the table
      (gtk-table-attach table title-label 0 1 0 1)
      (gtk-table-attach table value-label 1 2 0 1)
      (gtk-table-attach table title-entry 0 1 1 2)
      (gtk-table-attach table value-entry 1 2 1 2)
      (gtk-table-attach table button      2 3 1 2)
      (gtk-table-attach table combo-box   0 3 2 3)
      ;; Put the table into the window
      (gtk-container-add window table)
      ;; Show the window
      (gtk-widget-show-all window))))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.6.2 Combo Box Text

figures/combo-box-text151x85

Figure 13.7: Combo Box Text

A gtk-combo-box-text is a simple variant of gtk-combo-box that hides the model-view complexity for simple text-only use cases.

To create a gtk-combo-box-text, use the functions gtk-combo-box-text-new or gtk-combo-box-text-new-with-entry.

You can add items to a gtk-combo-box-text with the functions gtk-combo-box-text-append-text, gtk-combo-box-text-insert-text or gtk-combo-box-text-prepend-text and remove options with the function gtk-combo-box-text-remove.

If the gtk-combo-box-text contains an entry via the has-entry property, its contents can be retrieved using gtk-combo-box-text-get-active-text. The entry itself can be accessed by calling gtk-bin-get-child on the combo box.

Example 13.7: Combo Box Text

(defun example-combo-box-text ()
  (within-main-loop
    (let ((window (make-instance 'gtk-window
                                 :border-width 12
                                 :title "Example Combo Box Text"))
          (combo (make-instance 'gtk-combo-box-text)))
      (gtk-combo-box-text-append-text combo "First entry")
      (gtk-combo-box-text-append-text combo "Second entry")
      (gtk-combo-box-text-append-text combo "Third entry")
      (gtk-combo-box-set-active combo 0)
      (gtk-container-add window combo)
      (gtk-widget-show window))))

[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Crategus on January, 10 2016 using texi2html 1.76.