I'm trying to populate my main GUI with qml objects received via various communication channels: os.StdIn or RPC service. But to achieve that task, I would need to access a qml.Object or Context from outside the main func/qml.Run(func(){}) in the go program.
My attempts so far always end up in a panic :run time panic: runtime error: invalid memory address or nil pointer dereference.
Here below is a tangible example of what I'm trying to acheive. This is a program called mainUI that's being called by another called skeleton. The two communicate via RPC, and they both serve various procedures to whoever wants to connect to them. Here, "mainUI" offers the function AddMenuItem which expect a path to a qml file in order to create an object from it (that's the goal). But everytime I try to access a qml object or context from outside the "run" function, the program panics with the message quoted above.
So, why are qml types (object, engine, context) dereferenced outside of the "run" function? and is there a way to access them anyway?
package main
import (
"fmt"
"gopkg.in/qml.v1"
"log"
"os"
"path/filepath"
"skeleton/API/skeleton"
"skeleton/plugin"
)
var (
plug *plugin.Plugin
skel *skeleton.Skeleton
ctxt *qml.Context
)
func main() {
defer func() {
if x := recover(); x != nil {
fmt.Println(skel.LogPrefix(), "run time panic: ", x)
}
}()
// Initialise Skeleton connection
skel = &skeleton.Skeleton{PluginName: "mainUI"}
if err := skel.InitRPC(); err != nil {
fmt.Println(skel.LogPrefix(), err)
return
}
// Initialise mainUI RPC through the plugin object
plug = &plugin.Plugin{}
mui := new(MainUI)
plug.Init(skel, Parse, mui)
defer func() {
skel.Close()
plug.Stop()
}()
qml.Run(run)
}
func run() error {
pwd, _ := filepath.Abs(filepath.Dir(os.Args[0]))
qmlDir := pwd + string(os.PathSeparator) + "qml"
fmt.Println(skel.LogPrefix(), "qmlDir="+qmlDir)
engine := qml.NewEngine()
defer engine.Destroy()
ctxt = engine.Context()
defer ctxt.Destroy()
component, err := engine.LoadFile(qmlDir + string(os.PathSeparator) + "skeletonApp.qml")
if err != nil {
skel.Quit()
panic(err)
}
window := component.CreateWindow(nil)
defer window.Destroy()
window.On("closing", func() { skel.Quit() })
window.Show()
window.Wait()
return nil
}
type MainUI int
type MenuArgs struct {
MenuPath []string
ObjPath string
}
func (m *MainUI) AddMenuItem(args *MenuArgs, err *string) error {
defer func() {
if x := recover(); x != nil {
fmt.Println(skel.LogPrefix(), "run time panic: ", x)
}
}()
ob :=ctxt.ObjectByName("rootApp")
ob.Set("title", "Any Title would please me")
return nil
}