Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need support for model interface to set on views #9

Open
eivindro opened this issue Oct 1, 2013 · 12 comments
Open

Need support for model interface to set on views #9

eivindro opened this issue Oct 1, 2013 · 12 comments

Comments

@eivindro
Copy link
Contributor

eivindro commented Oct 1, 2013

model-view objects like TableView has a model property which needs to be set. Now to feed the view from a proper dynamic model this should probably be a go interface that mimics the virtual functions in C++ class QAbstractItemModel.

Since all other model classes inherits from this C++ class, that's all that needs to be implemented. Convenience interfaces for specialized view like listview and tableview may be implemented purely in Go to make life it easier for the Go user.

For an introduction to the C++ model classes have a look here: http://qt-project.org/doc/qt-5.1/qtquick/qtquick-modelviewsdata-cppmodels.html

Now, the implementation of this is essential to be able to support GUIs with larger amounts of non static data. And it also gives a very clean cut between data and gui as the same data model could be visualized in many different ways without having to make any changes to the data model itself.

@niemeyer
Copy link
Contributor

niemeyer commented Oct 2, 2013

For the record, working with model views is already possible and convenient today via the indexed mechanism.

Here is a good example:

Let's keep this bug open, though, as there might be advantages in supporting an implementation of QAbstractItemModel.

@michael-k
Copy link

Regarding TableViews, I had the problem, that role did not work. (At least I could not find out how to get it to work. So I use this workaround:

TableView {
    model: contactList.len

    TableViewColumn {
        title: qsTr("Name")
        delegate: Item {
            Text {
                anchors.verticalCenter: parent.verticalCenter
                color: styleData.textColor
                elide: styleData.elideMode
                text: contactList.name(styleData.row)
            }
        }
    }
}

@quarnster
Copy link
Contributor

Is there an efficient way to remove/add a single item out of 1000 with the index model?

Just setting model = array.length will re-create all 999/1001 elements rather than just tweak the single one that was changed.

@quarnster
Copy link
Contributor

To answer myself; yes there is. For example:

    ListModel {
        id: myModel
    }
...
    myModel.append({"itemId":rs.item(i).id});

itemId will then exist as a variable in the delagate component that is created as a result. myModel can be located from go so that its functions can be called from there if one wants to.

@NSkelsey
Copy link

@quarnster I am trying to figure out what you did here. Is there any chance you could elaborate?

@quarnster
Copy link
Contributor

Sure, here's a quick freestanding example:

package main

import (
    "gopkg.in/qml.v1"
    "log"
)

var qmlFile = `
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.0

ApplicationWindow {
    id: main
    width: 800
    height: 600

    function validate() {
        for (var i = 0; i < gomodel.len(); i++) {
            var godata = gomodel.get(i);
            var qmldata = lmodel.get(i).goitem;
            // Note that "godata" and "qmldata" are not
            // pointing to the same address though...
            if (godata.text != qmldata.text) {
                console.log(godata.text, qmldata.text);
            }
        }
    }
    function insert(i, data) {
        lmodel.insert(i, {"goitem": data});
        validate();
    }
    function removed(i) {
        lmodel.remove(i);
        validate();
    }
    ListModel {
        id: lmodel
    }
    ColumnLayout {
        Button {
            text: "add"
            onClicked: {
                console.log("adding!!");
                gomodel.add("Item " + Math.floor(Math.random()*1024));
            }
        }
        Button {
            text: "remove"
            onClicked: {
                console.log("removing!!");
                gomodel.remove(lv.currentIndex);
            }
        }

        ScrollView {
            Layout.fillHeight: true
            ListView {
                id: lv
                model: lmodel
                height: contentHeight
                delegate: Rectangle {
                    id: item
                    color: lv.currentIndex == index ? Qt.rgba(0.9,0.9,0.9,1.0) : "white"
                    width: Math.max(t.width, parent.width)
                    height: t.height
                    clip: true
                    Text {
                        id: t
                        text: goitem.text
                    }
                    MouseArea {
                        anchors.fill: parent
                        onClicked: lv.currentIndex = index
                    }
                }
            }
        }
    }
}
`

var window *qml.Window

type (
    Item struct {
        Text string
    }
    Model struct {
        items []*Item
    }
)

func (m *Model) Add(text string) {
    i := len(m.items)
    m.items = append(m.items, &Item{text})
    window.Call("insert", i, m.items[i])
}

func (m *Model) Remove(i int) {
    copy(m.items[i:], m.items[i+1:])
    m.items = m.items[:len(m.items)-1]
    window.Call("removed", i)
}

func (m *Model) Len() int {
    return len(m.items)
}

func (m *Model) Get(i int) *Item {
    return m.items[i]
}

func main() {
    model := &Model{}
    log.Println(qml.Run(func() error {
        engine := qml.NewEngine()
        defer engine.Destroy()
        engine.Context().SetVar("gomodel", model)
        component, err := engine.LoadString("main.qml", qmlFile)
        if err != nil {
            return err
        }
        window = component.CreateWindow(nil)
        window.Show()
        window.Wait()
        return nil
    }))
}

@NSkelsey
Copy link

@quarnster Thanks for the response. That window.Call in Add is very clever! I would not have thought of that.

This should be added to the delegate dir of the examples.

@pjoe
Copy link

pjoe commented Jan 26, 2015

Though putting things through a QML ListModel is workable, in my experience that won't perform anything near the QAbstractItemModel, that can efficiently signal changes in the model directly to the QML ListView, see e.g. beginInsertRows/endInsertRows. This is especially true if you are doing insertion/removal of mutliple items at once. So having a way to implement this QAbstractItemlModel interface in go would be really cool :D

@pjoe
Copy link

pjoe commented Jan 27, 2015

Ohh I just saw that there is already a list-model branch with some work in progress for this, anything we can do to help?

@niemeyer
Copy link
Contributor

niemeyer commented Feb 9, 2015

I'm not sure. The main blocker is researching in depth how to implement these interfaces in a sane way, and the reason it's taking so long is because the interface seems extensive and non-trivial on the C++ side. Whatever we do needs to be straightforward and sensible, and I haven't managed to work on it enough to get to that point.

@filcuc
Copy link

filcuc commented Feb 12, 2015

Niemeyer we should get in contact. I'm the author of the DOtherSide project that bring Qml bindings for Nim and D. I worked on this topic maybe i can share my implementation and see if it works for you too.

@pjoe
Copy link

pjoe commented Feb 12, 2015

Also lemme know if there is anything i can do to help. I have been using QAbstractItemList for interfacing C++ and QML for several years by now (since sometime from Qt 4.7beta). I'm on IRC freenode (as pjoe or pjoe_dj) during daytime CET

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants