go-qml / qml

QML support for the Go language
Other
1.96k stars 187 forks source link

Support JavaScript-specific methods in qml objects #90

Open jackman0 opened 10 years ago

jackman0 commented 10 years ago

Please refer to the following URL as the pertinent QML reference: http://qt-project.org/doc/qt-5/qml-qtqml-models-listmodel.html

My intent is to manipulate a QML TableView. The data model for the TableView is a ListModel. When attempting to do a simple fetch of a model row, I get a panic. Here is the relevant code:

The Go file:

package main

import (
        "fmt"
        "gopkg.in/qml.v1"
        "log"
        "math/rand"
        "os"
        "time"
)

var engine *qml.Engine

func main() {
        if err := qml.Run(run); err != nil {
                fmt.Fprintf(os.Stderr, "error: %v\n", err)
                os.Exit(1)
        }
}

func run() error {
        engine = qml.NewEngine()
        component, err := engine.LoadFile("bug.qml")
        if err != nil {
                return err
        }

        ctrl := Control{}

        context := engine.Context()
        context.SetVar("ctrl", &ctrl)

        window := component.CreateWindow(nil)

        ctrl.Root = window.Root()

        rand.Seed(time.Now().Unix())

        window.Show()
        window.Wait()

        return nil
}

type Control struct {
        Root qml.Object
}

func (ctrl *Control) Debug(obj qml.Object) {
        log.Println(obj.Int("count"))
        x := 1
        log.Println(obj.Call("get", x))
}

The QML file:

import QtQuick 2.0
import QtQuick.Controls 1.2
import QtQml.Models 2.1

Rectangle {
    id: root

    width: 640
    height: 480

    gradient: Gradient {
        GradientStop { position: 0.0; color: "#3a2c32"; }
        GradientStop { position: 0.8; color: "#875864"; }
        GradientStop { position: 1.0; color: "#9b616c"; }
    }

    TableView {
        id: tableROList
        TableViewColumn{ role: "title"  ; title: "Title" ; width: 100 }
        TableViewColumn{ role: "author" ; title: "Author" ; width: 200 }
        model: modelROList
        width: root.width
    }

    ListModel {
        id: modelROList
        ListElement{ title: "A Masterpiece" ; author: "Gabriel" }
        ListElement{ title: "Brilliance"    ; author: "Jens" }
        ListElement{ title: "Outstanding"   ; author: "Frederik" }
    }

    Rectangle{
        width:20
        height: 20
        color:"blue"
        x: 620
        y: 460
        MouseArea {
            id: mouseArea
            anchors.fill: parent
            drag.target: parent
            onReleased: ctrl.debug(modelROList)
        }
    }
}

Output:

jackman@debian:~/code/qmlbug$ cd ~/code/qmlbug/ && go run ./src/main.go
OpenGL Warning: Failed to connect to host. Make sure 3D acceleration is enabled for this VM.
2014/08/25 12:33:04 3
panic: invalid parameters to method "get"

goroutine 16 [running]:
runtime.panic(0x55c360, 0xc2080004b0)
        /home/jackman/code/go/src/pkg/runtime/panic.c:279 +0xf5
gopkg.in/qml%2ev1.cmust(0x7f7e50728160)
        /home/jackman/code/gopath/src/gopkg.in/qml.v1/qml.go:808 +0x90
gopkg.in/qml%2ev1.(*Common).Call(0xc2080003b0, 0x5a7210, 0x3, 0xc208000460, 0x1, 0x1, 0x0, 0x0)
        /home/jackman/code/gopath/src/gopkg.in/qml.v1/qml.go:663 +0x1d5
main.(*Control).Debug(0xc2080002c0, 0x7f7e61c9b490, 0xc2080003b0)
        /home/jackman/code/qmlbug/src/main.go:52 +0x163
reflect.Value.call(0x5806e0, 0xc2080002c0, 0x0, 0x138, 0x5a2d10, 0x4, 0xc20803a140, 0x1, 0xa, 0x0, ...)
        /home/jackman/code/go/src/pkg/reflect/value.go:563 +0x1210
reflect.Value.Call(0x5806e0, 0xc2080002c0, 0x0, 0x138, 0xc20803a140, 0x1, 0xa, 0x0, 0x0, 0x0)
        /home/jackman/code/go/src/pkg/reflect/value.go:411 +0xd7
gopkg.in/qml%2ev1.hookGoValueCallMethod(0x7f7e5016b980, 0xc208004180, 0x7fff00000000, 0x7fffb94068f0)
        /home/jackman/code/gopath/src/gopkg.in/qml.v1/bridge.go:507 +0x4a8
gopkg.in/qml%2ev1._Cfunc_applicationExec(0x589680)
        gopkg.in/qml.v1/_obj/_cgo_defun.c:60 +0x31
gopkg.in/qml%2ev1.Run(0x5df9c0, 0x0, 0x0)
        /home/jackman/code/gopath/src/gopkg.in/qml.v1/bridge.go:61 +0x1ac
main.main()
        /home/jackman/code/qmlbug/src/main.go:15 +0x2f

goroutine 19 [finalizer wait]:
runtime.park(0x4a5bb0, 0x87e398, 0x86e789)
        /home/jackman/code/go/src/pkg/runtime/proc.c:1369 +0x89
runtime.parkunlock(0x87e398, 0x86e789)
        /home/jackman/code/go/src/pkg/runtime/proc.c:1385 +0x3b
runfinq()
        /home/jackman/code/go/src/pkg/runtime/mgc0.c:2644 +0xcf
runtime.goexit()
        /home/jackman/code/go/src/pkg/runtime/proc.c:1445

goroutine 17 [syscall]:
runtime.goexit()
        /home/jackman/code/go/src/pkg/runtime/proc.c:1445

goroutine 20 [semacquire]:
sync.runtime_Semacquire(0xc2080003a4)
        /home/jackman/code/go/src/pkg/runtime/sema.goc:199 +0x30
sync.(*Mutex).Lock(0xc2080003a0)
        /home/jackman/code/go/src/pkg/sync/mutex.go:66 +0xd6
gopkg.in/qml%2ev1.(*Window).Wait(0xc208000370)
        /home/jackman/code/gopath/src/gopkg.in/qml.v1/qml.go:868 +0x9b
main.run(0x0, 0x0)
        /home/jackman/code/qmlbug/src/main.go:40 +0x1ec
gopkg.in/qml%2ev1.func·002()
        /home/jackman/code/gopath/src/gopkg.in/qml.v1/bridge.go:58 +0x46
created by gopkg.in/qml%2ev1.Run
        /home/jackman/code/gopath/src/gopkg.in/qml.v1/bridge.go:60 +0x1a5
exit status 2
jackman@debian:~/code/qmlbug$

I am using QML 5.3.1 as the TableView is not available in 5.0.3 (the recommended version on GitHub).

I tried looking for a model use of the Call() method in the repostory with parameters, but I just didn't find one.

jackman0 commented 10 years ago

I ran the same code against Qt 5.1.1, and I get the same result. I also tried explicitly declaring the type of 'x' as an int, int16, int32, and int64. With the exception of int16 (not yet implemented), the output among all of these was similar.

niemeyer commented 10 years ago

Per the mailing list response:

Sorry for not providing a more timely response to your ticket, Andrew.

I'll have to spend some time looking at why the default Qt introspection capabilities are failing with that function, but my guess is that it is related to how there's some JavaScript-specific magic in its definition.

Meanwhile, there's an easy way to workaround the issue: define a function like this in your modelROList type:

function myget(i) { return modelROList.get(i) }

and call that from Go instead. This will be a standard function, and won't suffer from these anomalies.

niemeyer commented 10 years ago

As a reference, these are the method declarations in QQmlListModel:

Q_INVOKABLE void clear();
Q_INVOKABLE void remove(QQmlV4Function *args);
Q_INVOKABLE void append(QQmlV4Function *args);
Q_INVOKABLE void insert(QQmlV4Function *args);
Q_INVOKABLE QQmlV4Handle get(int index) const;
Q_INVOKABLE void set(int index, const QQmlV4Handle &);
Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
Q_INVOKABLE void move(int from, int to, int count);
Q_INVOKABLE void sync();
geraldstanje commented 10 years ago

Hello Gustavo, whats the right way to call append to add new elements to the list model, im running into the same issue!? http://qt-project.org/doc/qt-5/qml-qtqml-models-listmodel.html#append-method

edit: current solution pasted to https://groups.google.com/forum/#!topic/go-qml/WCj373DO6qM

niemeyer commented 10 years ago

Yes, this is the same issue, and will be addressed once the general support for this is added.

geraldstanje commented 10 years ago

Ok

jackman0 commented 9 years ago

I accidentally closed this, but I think it was pretty much in a closed (duplicate) status, anyway.

niemeyer commented 9 years ago

Duplicate of what?