Safe Haskell | None |
---|---|
Language | Haskell2010 |
Haskell side
Any data type with a single constructor and marshallable fields can be used in a QML data model. For example:
data Row = Row {foo :: Int, bar :: String, baz :: Double} deriving Generic
To use the data type in a model, first you need to declare the necessary instances.
All the necessary classes have default implementations using Generic
.
To further automate the process, there's a Template Haskell macro that declares them all:
dataModelInstances Row
If you don't want to use TH, you can declare them manually:
instance QtTable Row instance Mock Row instance CountFields Row instance SetupColumns Row
Finally, in your main
function, register the data model as a QML type, set up the delegate and its callbacks, and provide a way for QML to access it.
setTVarCallbacks :: QtTable a => DataModel a -> TVar [a] -> IO () setTVarCallbacks model tv = do setRowCountCallback model $ length $ readTVarIO mtv setDataCallback model $ i -> (!!i) $ readTVarIO mtv main = do registerHaskellModel storage <- newTVarIO [Row 1 "a" 3.0, Row 2 "b" 4.2] model <- setupDataModel setTVarCallbacks model storage toplevel'class <- newClass [ defPropertyConst' "haskellModelDelegate" . return $ delegate model ] toplevel'obj <- newObject toplevel'class () runEngineLoop defaultEngineConfig { initialDocument = "path/toyour/main.qml" , contextObject = Just $ anyObjRef toplevel'obj }
QML side
Using the model in QML is simple as that:
HaskellModel { id: haskellModel; delegate: haskellModelDelegate; } TableView { id: hsView; model: haskellModel; TableViewColumn { title: "A"; role: "baz"; } TableViewColumn { title: "B"; role: "foo"; } }
Record fields become roles, and you can use them in any order any with any names you like. Views other than TableView can be used too, of course.