3
votes

this is how I currently initialize the Tree view from the glade file (Removed the uninteresting parts)

tree_view <- xmlGetWidget xml castToTreeView "tree_view"

To make it easy, how could I add a new entry to the tree_view using the text from an already filled text field?

text <- get text_field entryText

May someone help me?

Thanks

3

3 Answers

8
votes

From your description, I assume that you have a tree view, but haven't set it up properly. A GTK tree view is worth nothing if you don't connect it to several other widgets.

  • A tree model, which holds the data to be displayed in the tree view. The tree model can either be a list store, which stores data as a list, or a tree store, which stores the data as a tree, with nodes containing children. In your case, you'd probably need to create a ListStore:

    store <- listStoreNew String
    

    Tree models can store data of any type, including complex custom data types.

  • A tree view column for each piece of data to be shown. In this case, we just need one column because we want to display one string per row:

    column <- treeViewColumnNew
    
  • The tree view column must know what data to show and how to display it (as text, as a tick box, as a picture...) So we need a cell renderer. The cell renderer will get a piece of data from each row in the tree model and show it in the given column. For displaying text, a CellRendererText is needed. There are other types of cell renderers for showing data in other forms (for instance CellRendererToggle for True/False values).

    -- Create a cell renderer for displaying text
    cell <- cellRendererTextNew
    -- Add the cell renderer to the column. A column may display one or more
    -- pieces of data; just pack the cell renderers into the column
    cellLayoutPackStart column cell True
    -- Let the cell renderer know where it has to get the data from
    -- (in this case, the only element of each row). Note that we
    -- want to display some text
    cellLayoutSetAttributes column cell store $ \row -> [ cellText := row ]
    

Next, insert the column into the tree view. If you don't do this, the column won't be shown!

    -- Insert the column into the tree view
    _ <- treeViewAppendColumn tree_view column
    -- Optional: Give a header/title to the column
    treeViewColumnSetTitle column "My data"

And last but not least: connect the tree view to the tree model:

    treeViewSetModel tree_view store

Now you should see an empty column in your tree view. See the documentation of the gtk package at http://hackage.haskell.org/package/gtk to learn how to insert, remove and get data to/from a tree model (listStoreAppend, listStoreRemove, listStoreGetValue etc.)

Note that every tree model has a type and can only work with data of that type (but you can use any data type, even your own, so you can indeed store and show rows of complex data provided you set up every tree view column correctly). Otherwise you will get a type error when compiling the program.

1
votes

A TreeView is a

"Widget that displays any object that implements the TreeModel interface."

So you need the treeViewGetModel, treeViewSetModel to get the TreeModel.

I expect that the TreeModel interface you need is the TreeStore:

Two generic models are provided that implement the TreeModel interface: the TreeStore and the ListStore. To use these, the developer simply inserts data into these models as necessary.

The TreeStore has treeStoreInsert.

0
votes

If you initialize your tree store like that (just passing an empty list), Haskell won't know its exact type and will say that the type of the store is "TreeStore (GHC.Prim.Any *)", which isn't what you want.

TreeStores are more complicated than ListStores because they must not only contain the data, but also its hierarchy (parent and children nodes).

See the definition of treeStoreNew:

    treeStoreNew :: Forest a -> IO (TreeStore a)

TreeStores hold a "Forest" of type "a" (Integers, Strings, etc.). The Forest type is defined in the module Data.Tree, so you'll have to import this module:

    import Data.Tree

A Forest is just a list of "Tree a", that means a data type "Tree" holding values of type "a". That said, in order to set up your tree store properly, you must do the following if you want to store strings:

    let id :: [Tree String]
        id = []
    store <- treeStoreNew id

If you look at your store's type (at the GHCi prompt), you'll see it's correct:

    :t store
    store :: TreeStore String

To insert a row at "[]" (the top level, without a parent), appending it to the end if there are already some rows at the top level (that's the meaning of (-1)), for example the string "John":

    treeStoreInsert store [] (-1) "John"

The row will be inserted at path [0]. Check it at GHCi with:

    treeStoreGetTree store [0] >>= print

Which will give "Node {rootLabel = "John", subForest = []}".

To insert a child of "John", for example "Smith":

    treeStoreInsert store [0] (-1) "Smith"

The tree will now contain a parent item and a child (check with GHCi):

    treeStoreGetTree store [0] >>= print

Will output now "Node {rootLabel = "John", subForest = [Node {rootLabel = "Smith", subForest = []}]}".

Finally,

    treeStoreGetTree store [0,0] >>= print

Will show the child only: Node {rootLabel = "Smith", subForest = []}

See the documentation to learn more about the topic.