3

I am unable to get gtk's cell renderer combo box to display any options. I need to use a different model for each row in my tree, which should be possible with cellComboTextModel. My result is the combo box renderer is completely empty.

Here is a simplified example:

{-# OPTIONS_GHC -Wall #-}

module Main ( main ) where

import Graphics.UI.Gtk ( AttrOp( (:=) ) )
import qualified Graphics.UI.Gtk as Gtk
import System.Glib.Signals ( on )

-- the element in the list store
data ListElement =
  ListElement
  { leName :: String
  , leListStore :: Gtk.ListStore String
  }

makeMyTreeview :: IO Gtk.TreeView
makeMyTreeview = do
  -- make a list store with two elements

  -- the storage for each combo box cell renderer
  comboListStore0 <- Gtk.listStoreNew ["hi", "there"]
  comboListStore1 <- Gtk.listStoreNew ["A", "B", "C"]
  let elements =
        [ ListElement "joe" comboListStore0
        , ListElement "bob" comboListStore1
        ]

  listStore <- Gtk.listStoreNew elements :: IO (Gtk.ListStore ListElement)
  treeview <- Gtk.treeViewNewWithModel listStore :: IO Gtk.TreeView

  Gtk.treeViewSetHeadersVisible treeview True

  -- add some columns
  nameCol <- Gtk.treeViewColumnNew
  comboCol <- Gtk.treeViewColumnNew

  Gtk.treeViewColumnSetTitle nameCol "name"
  Gtk.treeViewColumnSetTitle comboCol "combo"

  -- add cell renderers
  nameRenderer <- Gtk.cellRendererTextNew
  comboRenderer <- Gtk.cellRendererComboNew

  Gtk.cellLayoutPackStart nameCol nameRenderer True
  Gtk.cellLayoutPackStart comboCol comboRenderer True

  _ <- Gtk.treeViewAppendColumn treeview nameCol
  _ <- Gtk.treeViewAppendColumn treeview comboCol

  -- this sets the name column strings
  Gtk.cellLayoutSetAttributes nameCol nameRenderer listStore $
    \x -> [Gtk.cellText := leName x ++ "!"]

  -- combo box
  Gtk.cellLayoutSetAttributes comboCol comboRenderer listStore $ \x ->
    [ Gtk.cellComboTextModel := ( leListStore x, Gtk.makeColumnIdString 0 :: Gtk.ColumnId String String
                                )
    , Gtk.cellMode := Gtk.CellRendererModeActivatable
    , Gtk.cellComboHasEntry := True
    ]

  -- an action when the combo box is edited
  _ <- on comboRenderer Gtk.edited $ \_treePath newVal -> do
    putStrLn "combo box is being edited (this never happens)"
    putStrLn $ "new value: " ++ newVal

  return treeview


main :: IO ()
main = do
  _ <- Gtk.initGUI
  win <- Gtk.windowNew
  _ <- Gtk.set win [ Gtk.containerBorderWidth := 8
                   , Gtk.windowTitle := "help"
                   ]
  treeview <- makeMyTreeview
  _ <- Gtk.set win [ Gtk.containerChild := treeview ]
  Gtk.widgetShowAll win
  Gtk.mainGUI

Any insight would be greatly appreciated.

EDIT: I figured out what I was missing:

Gtk.treeModelSetColumn comboListStore0 (Gtk.makeColumnIdString 0) id
Gtk.treeModelSetColumn comboListStore1 (Gtk.makeColumnIdString 0) id

This sets the ListStore column ID so that the later line

Gtk.cellComboTextModel := (leListStore x, Gtk.makeColumnIdString 0 :: Gtk.ColumnId String String)

is referencing the text correctly. This does not seem to work in GTK3 however

Cactus
  • 27,075
  • 9
  • 69
  • 149
ghorn
  • 614
  • 3
  • 11

1 Answers1

1

I figured it out for GTK3. (See my edit above for the GTK2 solution.) For GTK3 you have to use the editingStarted signal to edit the combo box's liststore manually. Unfortunately this causes a segfault for GTK2.

Here is the complete working code for GTK3

{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE PackageImports #-}

module Main ( main ) where

import qualified Data.Text as T
import "gtk3" Graphics.UI.Gtk ( AttrOp( (:=) ) )
import qualified "gtk3" Graphics.UI.Gtk as Gtk
import System.Glib.Signals ( on )

-- the element in the list store
data ListElement =
  ListElement
  { leName :: String
  , leListStore :: Gtk.ListStore String
  , leOptions :: [String]
  }

makeMyTreeview :: IO Gtk.TreeView
makeMyTreeview = do
  -- the storage for each combo box cell renderer
  comboListStore0 <- Gtk.listStoreNew []
  comboListStore1 <- Gtk.listStoreNew []
  Gtk.treeModelSetColumn comboListStore0 (Gtk.makeColumnIdString 0) id
  Gtk.treeModelSetColumn comboListStore1 (Gtk.makeColumnIdString 0) id
  let elements =
        [ ListElement "joe" comboListStore0 ["hi", "there"]
        , ListElement "bob" comboListStore1 ["A", "B", "C"]
        ]

  listStore <- Gtk.listStoreNew elements :: IO (Gtk.ListStore ListElement)
  treeview <- Gtk.treeViewNewWithModel listStore :: IO Gtk.TreeView

  Gtk.treeViewSetHeadersVisible treeview True

  -- add some columns
  nameCol <- Gtk.treeViewColumnNew
  comboCol <- Gtk.treeViewColumnNew

  Gtk.treeViewColumnSetTitle nameCol "name"
  Gtk.treeViewColumnSetTitle comboCol "combo"

  -- add cell renderers
  nameRenderer <- Gtk.cellRendererTextNew
  comboRenderer <- Gtk.cellRendererComboNew

  Gtk.cellLayoutPackStart nameCol nameRenderer True
  Gtk.cellLayoutPackStart comboCol comboRenderer True

  _ <- Gtk.treeViewAppendColumn treeview nameCol
  _ <- Gtk.treeViewAppendColumn treeview comboCol

  -- this sets the name column
  Gtk.cellLayoutSetAttributes nameCol nameRenderer listStore $
    \x -> [Gtk.cellText := leName x ++ "!"]

  Gtk.cellLayoutSetAttributes comboCol comboRenderer listStore $ \x ->
    [ Gtk.cellTextEditable := True
    , Gtk.cellComboTextModel := (leListStore x, Gtk.makeColumnIdString 0 :: Gtk.ColumnId String String)
    , Gtk.cellComboHasEntry := False
    ]

  -- here is where we will set the combo options!!!!
  _ <- on comboRenderer Gtk.editingStarted $ \widget treepath -> do
    case treepath of
      [k] -> do
        listElement <- Gtk.listStoreGetValue listStore k
        comboListStore <- Gtk.comboBoxSetModelText (Gtk.castToComboBox widget)
        mapM_ (Gtk.listStoreAppend comboListStore . T.pack) (leOptions listElement)
      ks -> error $ "bad treepath for liststore: " ++ show ks

  -- an action when the combo box is edited
  _ <- on comboRenderer Gtk.edited $ \_treePath newVal -> do
    putStrLn $ "combo box edited, new value: " ++ newVal

  return treeview


main :: IO ()
main = do
  _ <- Gtk.initGUI
  win <- Gtk.windowNew
  _ <- Gtk.set win [ Gtk.containerBorderWidth := 8
                   , Gtk.windowTitle := "help"
                   ]
  treeview <- makeMyTreeview
  _ <- Gtk.set win [ Gtk.containerChild := treeview ]
  Gtk.widgetShowAll win
  Gtk.mainGUI
ghorn
  • 614
  • 3
  • 11
  • I'm not going to accept this answer, even this it works around my problem, because I never really got to the bottom of the issue. – ghorn Feb 07 '16 at 20:07