Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QML ListView and QSqlTableModel



  • Post 1/2 (exceeds the 6000 character limit)

    Hello,

    I am still new to QML and I have a problem trying to use a QSqlDatabase and QML ListView. I've searched the forum but can't find a solution.

    The application uses QML for most of the work, but it needs to get data from an MS Access database and show it inside QML elements containing a ListView. To do this, I have made a C++ BaseModel class which inherits from QSqlTableModel. I've made a few test programs and managed to connect the database with the ListView to show the data.

    Here's the problem, though. The QML part of the application uses a Loader in the main file to load different pages. These are loaded when I click certain buttons and they hold most of the content. One of these pages needs to contain ComboBoxes which pull data from the database. To make the ComboBox I have first created a ListBox which contains a ListView and a custom-made ListItem which is the delegate. The model for the ListView comes from the C++ BaseModel class. The problem is that I don't know how to de-couple the ListBox/ComboBox from the model to be able to show different data in each ComboBox I make. Currently, it will work if I specify the name of the column directly in the delegate, but because each ComboBox uses a different column (and a different table), I need to be able to do this outside the ComboBox definition, i.e. something like:

    @
    ComboBox {
    id: topicComboBox
    //...
    model: topicModel
    delegate: Topic //this is the column name
    }

    ComboBox {
    id: keyWordComboBox
    //...
    model: keywordModel
    delegate: KeyWord //this is the column name
    }
    @

    I've tried doing this, but I get the following error:

    bq. ReferenceError: KljucnaRijec is not defined

    Do I even need different models for setting each ComboBox?

    I'll provide as much code as possible.

    ListBox.qml

    @import QtQuick 2.0

    Rectangle {
    id: listBox
    width: 400
    height: 500
    color: "#1a4381"
    border.color: "#ffffff"

    property int selectedIndex: testView.currentIndex
    property string selectedText: ""
    property variant listModel
    property string tableField
    
    signal indexChanged()
    
    Component {
        id: delegateItem
    
        ListItem {
            text: listBox.tableField ? listBox.tableField : ""
            width: parent.width
            anchors.left: parent.left
            anchors.leftMargin: 2
            onListItemClick: {
                listBox.selectedText = text;
                testView.currentIndex = index;
            }
        }
    }
    
    ListView {
        id: testView
        clip: true
        anchors.centerIn: parent
        width: parent.width - 2
        height: parent.height - 2
        model: listBox.listModel
        delegate: delegateItem
    
        currentIndex: -1
        onContentHeightChanged: {
            if (listBox.height < testView.contentHeight)
                vScrollBar.visible = true;
            else
                vScrollBar.visible = false;
        }
    
        onCurrentIndexChanged: indexChanged()
    
        ScrollBar {
            id: vScrollBar
            anchors.right: parent.right
            height: parent.height
            position: testView.visibleArea.yPosition
            pageSize: testView.visibleArea.heightRatio
    
            visible: (testView.height < testView.contentHeight) ? true : false
        }
    }
    

    }
    @

    ComboBox.qml

    @import QtQuick 2.0

    Item {
    id: comboBox
    width: 400
    height: selectedItemRect.height

    property alias imageSource: arrowImage.source
    property color itemColor: "#1a4381"
    property color borderColor: "#ffffff"
    property alias text: selectedItemText.text
    property alias listBoxHeight: comboListBox.height
    property variant model
    property string field
    
    Rectangle {
        id: selectedItemRect
        anchors.left: parent.left
        anchors.top: parent.top
        width: parent.width
        height: 20
        color: comboBox.itemColor
        border.color: comboBox.borderColor
    
        Text {
            id: selectedItemText
            color: "#ffffff"
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.left: parent.left
            anchors.leftMargin: 2
            text: ""
            font.pixelSize: 16
            font.family: "Arial"
    
        }
    
        Rectangle {
            id: arrowImageRect
            color:comboBox.itemColor
            border.color: comboBox.borderColor
            height: parent.height
            width: height //width is the same as height
            anchors.right: parent.right
            anchors.verticalCenter: parent.verticalCenter
    
            Image {
                id: arrowImage
                source: ""
                anchors.centerIn: parent
            }
        }
    
        MouseArea {
            id: comboMouseArea
            anchors.fill: parent
    
            cursorShape: Qt.PointingHandCursor
    
            onClicked: {
                if (comboListBox.visible)
                    comboListBox.visible = false;
                else
                    comboListBox.visible = true;
            }
        }
    }
    
    ListBox {
        id: comboListBox
        anchors.top: selectedItemRect.bottom
        anchors.left: selectedItemRect.left
        width: selectedItemRect.width
        height: 500
        visible: false
        listModel: comboBox.model
        tableField: comboBox.field
    
        onIndexChanged: {
            comboBox.text = selectedText;
            visible = false;
        }
    }
    

    }
    @



  • Post 2/2

    ContentsPage.qml

    @
    import QtQuick 2.0

    Item {
    id: mainContents

    Text {
        id: keywordText
        color: "#ffffff"
        anchors.verticalCenter: keywordComboBox.verticalCenter
        anchors.right: authorsIndexText.right
        wrapMode: Text.WordWrap
        text: "<b>Keyword</b>"
        font.pixelSize: 16
        font.family: "Arial"
    }
    
    ComboBox {
            id: keywordComboBox
            width: 300
            height: 20
            listBoxHeight: 570
            itemColor: "#1a4381"
            borderColor: "#ffffff"
            anchors.top: indexRect.bottom
            anchors.topMargin: 10
            anchors.left: indexRect.left
            text: "Choose a keyword --&gt;"
            imageSource: "images/DownArrow.png"
            model: keywordModel
            field: KljucnaRijec //this is the name of the column
            z: 1
    }
    

    }
    @

    The line "field: KljucnaRijec" is the one that causes the error

    bq. ReferenceError: KljucnaRijec is not defined

    main.qml

    @
    import QtQuick 2.0

    Item {
    id: mainItem
    width: 1024

    FontLoader {
        id: avantGardeBookBT
        source: "qrc:/fonts/fonts/AvantGardeBookBT.ttf"
    }
    
    Rectangle {
        id: headerRectangle
        //width: parent.width
        width: 1024
        height: 80
        color: "#1a4381"
        anchors.horizontalCenter: parent.horizontalCenter
    
        ImageTextButton {
            id: exitButton
            imageSource: "images/X.png"
            anchors.right: parent.right
            anchors.top: parent.top
            anchors.topMargin: 5
            onImageTextButtonClick: exitDialog.visible = true;
            text: "EXIT"
        }
    }
    
    Rectangle {
        id: mainRectangle
        //width: parent.width
        width: 1024
        height: mainItem.height - headerRectangle.height - 1
        color: "#1a4381"
        anchors.bottom: parent.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        Component.onCompleted: pageLoader.setSource("HomePage.qml")
    
        signal loadPage(string pageName)
    
        YesNoDialog {
            id: exitDialog
            anchors.centerIn: parent
            visible: false
            z: 1
    
            titleText: "Question"
            messageText: "Are you sure you want to quit?"
            iconSource: "images/Warning.png"
            xButtonImageSource: "images/X.png"
    
            onYesClick: Qt.quit();
            onNoClick: exitDialog.visible = false;
            onExitClick: exitDialog.visible = false;
        }
    
        Image {
            id: mainBgImage
            source: "images/Background1.png"
            anchors.fill: parent
        }
    
        Loader {
            id: pageLoader
    
            anchors.fill: parent
            //source: "HomePage.qml"
        }
    
        Connections {
            id: pageConnections
            ignoreUnknownSignals: true
            target: pageLoader.item
    
            onLoadPage: {
                if (pageName == "ContentsPage.qml")
                    keywordModel.setModel("KljucneRijeci"); //this will set data from the table specified in quotes to the model
                pageLoader.source = pageName;
    
            }
        }
    }
    

    }
    @

    I hope this is clear enough.

    Cheers,
    Lucijan

    P.S. I have a side question: if I try to use this application on Linux or Mac, will I need to install a database driver for MS Access databases or will the program call one of Qt's library files? I need to make the program work without any installation. If not, will it work if I convert the database to SQLite or some other database?



  • OK, maybe I should start with easier questions. What kind of QML type is the name of the column that I'm sending to the delegate - variant or string? Also, where is the variable visible - only in the delegate, in the file that contains the delegate and ListView or elsewhere as well? I can't make other files see it and I don't know why. This prevents me from making my ListBox a generalized component. As it stands, I would have to make three different ListBox "classes" with the only difference being the data they pull from the database. There has to be a better way to do this, but how? Could I do it from C++ and how would I go about doing that?

    Any pointers in the right direction would be really welcome.

    Cheers,
    Lucijan


Log in to reply