therecipe / qt

Qt binding for Go (Golang) with support for Windows / macOS / Linux / FreeBSD / Android / iOS / Sailfish OS / Raspberry Pi / AsteroidOS / Ubuntu Touch / JavaScript / WebAssembly
GNU Lesser General Public License v3.0
10.46k stars 747 forks source link

Passing a context property to QML #1019

Open amlwwalker opened 4 years ago

amlwwalker commented 4 years ago

I am passing an object that is supposed to be the users settings within my app to the front end so that I can set some check boxes based on the saved settings:

                  CheckBox { id: statisticsCheck; checked: systemSettings.sendStatistics}
                  CheckBox { id: screenshotCheck; checked: systemSettings.saveScreenshots}
                  CheckBox { id: newFileReadySystemNotifyCheck; checked: systemSettings.systemNewFileNotification}
                  CheckBox { id: patchSystemNotifyCheck; checked: systemSettings.systemNewPatchNotification}
                  CheckBox { id: overrideExistingCheck; checked: systemSettings.overrideMasterFile}

In main I have

engine := qml.NewQQmlApplicationEngine(nil)
engine.RootContext().SetContextProperty("systemSettings", controller.Instance().UserSettings)

Where UserSettings are:

type SystemSettings struct {
    core.QObject

    _ bool `property:"sendStatistics"`
    _ bool `property:"saveScreenshots"`
    _ bool `property:"systemNewFileNotification"`
    _ bool `property:"systemNewPatchNotification"`
    _ bool `property:"overrideMasterFile"`
}

type Controller struct {
    core.QObject
    UserSettings  *SystemSettings
...
}

func (c *Controller) init() {
    c.UserSettings = NewSystemSettings(nil)

    c.UserSettings.SetSendStatistics(true)
    c.UserSettings.ConnectSendStatisticsChanged(func(setting bool) {
        fmt.Printf("settings 1%+v\r\n", c.UserSettings)
        // fmt.Printf("settings 2%+v\r\n", c.UserSettings.SendStatistics())
    })

    c.UserSettings.SetSaveScreenshots(true)
    c.UserSettings.SetSystemNewFileNotification(false)
    c.UserSettings.SetSystemNewPatchNotification(false)
    c.UserSettings.SetOverrideMasterFile(true)

...
}

Strangely I get an error of

file:///Users/alex/go/src/github.com/amlwwalker/.../Settings/Settings.qml:50: ReferenceError: systemSettings is not defined
file:///Users/alex/go/src/github.com/amlwwalker/.../Settings/Settings.qml:51: ReferenceError: systemSettings is not defined
file:///Users/alex/go/src/github.com/amlwwalker/.../Settings/Settings.qml:52: ReferenceError: systemSettings is not defined
file:///Users/alex/go/src/github.com/amlwwalker/.../Settings/Settings.qml:53: ReferenceError: systemSettings is not defined
file:///Users/alex/go/src/github.com/amlwwalker/.../Settings/Settings.qml:54: ReferenceError: systemSettings is not defined

Even though the checkboxes are correctly set based on the boolean values from above. Any idea why that might be? Secondly, the ConnectSendStatisticsChanged doesn't detect the change at all, and I'm wondering whether its because Controller sits between qml and the System settings possibly?

And lastly, I am possibly going to have alot of settings, is there a tidier way I can do a ConnectXChanged on the whole SystemSettings object (and then save all the fields to my database) in one go, as I think i am going to have to save each one individiually which is quite large and messy when at the end of the day they are just boolean values?

I added it as an example here https://github.com/amlwwalker/qml-settings-example

Thanks

therecipe commented 4 years ago

Hey

To get rid of the ReferenceError: systemSettings is not defined issue, you will just need set the contextproperty before loading the qml file.

And to make the ConnectSendStatisticsChanged signal work you can listen on the onClicked signal of the checkbox.

And about some way to catch the ConnectXChanged on the whole SystemSettings object. For that I would just create a new signal and manually call that every time one of the settings changed.

This should work:

diff --git a/controller.go b/controller.go
index 1ec1a84..6c83331 100644
--- a/controller.go
+++ b/controller.go
@@ -21,6 +21,8 @@ type SystemSettings struct {
    _ bool `property:"systemNewFileNotification"`
    _ bool `property:"systemNewPatchNotification"`
    _ bool `property:"overrideMasterFile"`
+
+   _ func() `signal:"someSettingChanged"`
 }
 type Controller struct {
    core.QObject
@@ -37,9 +39,19 @@ func ControllerInstance() *Controller {
 func (c *Controller) InitWith() {
    c.UserSettings = NewSystemSettings(nil)

+   c.UserSettings.ConnectSomeSettingChanged(func() {
+       fmt.Println("ConnectSomeSettingChanged",
+           c.UserSettings.IsSendStatistics(),
+           c.UserSettings.IsSaveScreenshots(),
+           c.UserSettings.IsSystemNewFileNotification(),
+           c.UserSettings.IsSystemNewPatchNotification(),
+           c.UserSettings.IsOverrideMasterFile(),
+       )
+   })
+
    c.UserSettings.SetSendStatistics(true)
    c.UserSettings.ConnectSendStatisticsChanged(func(setting bool) {
-       fmt.Printf("settings 1%+v\r\n", c.UserSettings)
+       fmt.Println("settings 1", setting)
        //now i want to send the properties/settings and store them in a database (boltdb.)
    })

diff --git a/main.go b/main.go
index e7bf72b..6e2f61a 100644
--- a/main.go
+++ b/main.go
@@ -6,7 +6,6 @@ import (
    "path/filepath"

    "github.com/therecipe/qt/core"
-   "github.com/therecipe/qt/gui"
    "github.com/therecipe/qt/qml"
    "github.com/therecipe/qt/widgets"
 )
@@ -15,8 +14,8 @@ func main() {

    // configure UI
    var path string
-   if false {
-       path = "qrc:/qml/view.qml"
+   if true {
+       path = "qrc:/qml/main.qml"
    } else {
        path = filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "amlwwalker", "example-qml", "settings-example", "qml", "main.qml")
    }
@@ -28,16 +27,14 @@ func main() {
    ControllerInstance().InitWith()

    engine.AddImportPath("qrc:/qml/")
+   fmt.Printf("userSettings %+v\r\n", ControllerInstance().UserSettings)
+   engine.RootContext().SetContextProperty("systemSettings", ControllerInstance().UserSettings)
+
    if true {
        engine.Load(core.NewQUrl3(path, 0))
    } else {
        engine.Load(core.NewQUrl3("qrc:/qml/main.qml", 0))
    }

-   view := gui.NewQWindowFromPointer(engine.RootObjects()[0].Pointer()) //get a handle on the view as a OS object
-   fmt.Printf("userSettings %+v\r\n", ControllerInstance().UserSettings)
-   engine.RootContext().SetContextProperty("systemSettings", ControllerInstance().UserSettings)
-
-   view.Show()
    widgets.QApplication_Exec()
 }
diff --git a/qml/main.qml b/qml/main.qml
index 5633e24..61bb99d 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -29,7 +29,7 @@ ApplicationWindow {
               Label { text: "Notify when a patch is created"; Layout.fillWidth: true  }
               Label { text: "Override existing files (or save patches next to them"; Layout.fillWidth: true  }

-              CheckBox { id: statisticsCheck; checked: systemSettings.sendStatistics}
+              CheckBox { id: statisticsCheck; checked: systemSettings.sendStatistics; onClicked: { systemSettings.sendStatistics = statisticsCheck.checked; systemSettings.someSettingChanged()}}
               CheckBox { id: screenshotCheck; checked: systemSettings.saveScreenshots}
               CheckBox { id: newFileReadySystemNotifyCheck; checked: systemSettings.systemNewFileNotification}
               CheckBox { id: patchSystemNotifyCheck; checked: systemSettings.systemNewPatchNotification}