Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QML dynamic ComboBox Entrys

i'm trying to implement a ComboBox in QML and C++, in which i can dynamically change the content of my ComboBox. I'm providing a QStringList as ComboBox-Model and want to insert/remove an entry from the ComboBox with two buttons.

I can display the QStringList in my ComboBox, but when i click on the Add-Button for example, my QStringList gets updated in my class, but somehow the View does not update the ComboBox entrys. What should i do, to tell the View that my ComboBox-Model has updated?

This is my code:

comboboxmodel.h

#ifndef COMBOBOXMODEL_H
#define COMBOBOXMODEL_H

#include <QObject>
#include <QStringList>

class ComboBoxModel : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QStringList comboList READ comboList WRITE setComboList NOTIFY comboListChanged)
    Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged)

public:
    ComboBoxModel(QObject *parent = 0);
    ComboBoxModel(const QStringList &list,int count, QObject *parent = 0);

    const QStringList comboList();
    void setComboList(const QStringList &comboList);

    int count();
    void setCount(int cnt);

    Q_INVOKABLE void addElement(const QString &element);
    Q_INVOKABLE void removeElement(int index);

signals:

    void comboListChanged();
    void countChanged();

public slots:


private:

    QStringList m_comboList;
    int         m_count;
};

#endif // COMBOBOXMODEL_H

comboboxmodel.cpp

#include "comboboxmodel.h"
#include "qdebug.h"

ComboBoxModel::ComboBoxModel(QObject *parent) :
    QObject(parent)
{
}

ComboBoxModel::ComboBoxModel(const QStringList &list, int count, QObject *parent) :
    QObject(parent), m_comboList(list), m_count(count)
{

}

const QStringList ComboBoxModel::comboList()
{
    return m_comboList;
}

void ComboBoxModel::setComboList(const QStringList &comboList)
{

    if (m_comboList != comboList)
    {
        m_comboList = comboList;
        emit comboListChanged();
    }

}

int ComboBoxModel::count()
{
    return m_count;
}

void ComboBoxModel::setCount(int cnt)
{
    if (cnt != m_count)
    {
        m_count = cnt;
        emit countChanged();
    }
}

void ComboBoxModel::addElement(const QString &element)
{
    m_comboList.append(element);
    emit comboListChanged();
    setCount(m_comboList.count());
    emit countChanged();

    for (int i = 0; i<m_count; i++)
    {
        qDebug() << m_comboList.at(i);
    }
}

void ComboBoxModel::removeElement(int index)
{
    if (index < m_comboList.count())
    {
        m_comboList.removeAt(index);
        emit comboListChanged();
        setCount(m_comboList.count());
        emit countChanged();
    }

    for (int i = 0; i<m_count; i++)
    {
        qDebug() << m_comboList.at(i);
    }
}

main.cpp

#include <QApplication>
#include <QQmlApplicationEngine>
#include <qqmlengine.h>
#include <qqmlcontext.h>
#include <qqml.h>
#include <QStringList>

#include "comboboxmodel.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);


    QQmlApplicationEngine engine;
    ComboBoxModel combo;

    QStringList tmp;
    tmp << "1" << "2" << "3" << "4" << "5" << "6" << "7";
    combo.setComboList(tmp);

    QQmlContext *ownContext = engine.rootContext();
    ownContext->setContextProperty("myModel", QVariant::fromValue(combo.comboList()));

    QQmlContext *classContext = engine.rootContext();
    classContext->setContextProperty("comboModel", &combo);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec(); }

main.qml

import QtQuick 2.3 import QtQuick.Controls 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    menuBar: MenuBar {
        Menu {
            title: qsTr("File")
            MenuItem {
                text: qsTr("&Open")
                onTriggered: console.log("Open action triggered");
            }
            MenuItem {
                text: qsTr("Exit")
                onTriggered: Qt.quit();
            }
        }
    }

    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }

    ComboBox {
        id: comboBox1
        x: 258
        y: 54
        model: myModel
        editable: true
        onAccepted: {
             if (editableCombo.find(currentText) === -1) {
                 model.append({text: editText})
                 currentIndex = editableCombo.find(editText)
             }
         }

    }

    Button {
        id: button1
        x: 280
        y: 139
        text: qsTr("Remove Item")
        onClicked: comboModel.removeElement(comboBox1.currentIndex)
    }

    Rectangle{
        x: 281
        y: 316
        width: 80
        height: 20
        color: "white"

        TextEdit {
            id: textEdit1
            width: 80
            height: 20
            text: qsTr("Text Edit")
            font.pixelSize: 12
        }
    }

    Button {
        id: button2
        x: 280
        y: 388
        text: qsTr("Add Item")
        onClicked: comboModel.addElement(textEdit1.text)
    } }
like image 382
Edlanta Avatar asked Sep 29 '22 10:09

Edlanta


2 Answers

So i finnaly figured out how to do this kind of stuff.

In main.qml it should be:

model: comboModel.comboList

instead of:

model: myModel

Now i can add/remove items from my list and they are displayed correctly.

Thanks for your hint BaCaRoZzo.

Can somebody change this subject to "Solved"?

like image 114
Edlanta Avatar answered Oct 19 '22 06:10

Edlanta


The example has helped me a lot, thank you! Here's a slightly modified version as a finished working example:

comboboxmodel.h

#ifndef COMBOBOXMODEL_H
#define COMBOBOXMODEL_H

#include <QObject>
#include <QStringList>

class ComboBoxModel : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QStringList comboList READ comboList WRITE setComboList NOTIFY comboListChanged)
    Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged)
    Q_PROPERTY(int currentIndex READ currentIndex WRITE setcurrentIndex NOTIFY currentIndexChanged)

public:
    ComboBoxModel(QObject *parent = 0);
    ComboBoxModel(const QStringList &list,int count, QObject *parent = 0);

    const QStringList comboList();
    void setComboList(const QStringList &comboList);

    int count();
    void setCount(int cnt);

    int currentIndex();
    void setcurrentIndex(int index);

    Q_INVOKABLE void addElement(const QString &element);
    Q_INVOKABLE void removeElement(int index);

signals:

    void comboListChanged();
    void countChanged();
    void currentIndexChanged();

public slots:


private:

    QStringList m_comboList;
    int         m_count;
    int         m_currentIndex;
};

#endif // COMBOBOXMODEL_H

comboboxmodel.cpp

#include "comboboxmodel.h"
#include "qdebug.h"

ComboBoxModel::ComboBoxModel(QObject *parent) :
    QObject(parent)
{
}

ComboBoxModel::ComboBoxModel(const QStringList &list, int count, QObject *parent) :
    QObject(parent), m_comboList(list), m_count(count)
{

}

const QStringList ComboBoxModel::comboList()
{
    return m_comboList;
}

void ComboBoxModel::setComboList(const QStringList &comboList)
{

    if (m_comboList != comboList)
    {
        m_comboList = comboList;
        emit comboListChanged();
    }

}

int ComboBoxModel::count()
{
    return m_count;
}

void ComboBoxModel::setCount(int cnt)
{
    if (cnt != m_count)
    {
        m_count = cnt;
        emit countChanged();
    }
}

int ComboBoxModel::currentIndex()
{
    return m_currentIndex;
}

void ComboBoxModel::setcurrentIndex(int index)
{
    if (index != m_currentIndex)
    {
        m_currentIndex = index;
        qDebug()<<"current index is"<<index;
        emit currentIndexChanged();
    }
}
void ComboBoxModel::addElement(const QString &element)
{
    m_comboList.append(element);
    emit comboListChanged();
    setCount(m_comboList.count());
    emit countChanged();

    for (int i = 0; i<m_count; i++)
    {
        qDebug() << m_comboList.at(i);
    }
}

void ComboBoxModel::removeElement(int index)
{
    if (index < m_comboList.count())
    {
        m_comboList.removeAt(index);
        emit comboListChanged();
        setCount(m_comboList.count());
        emit countChanged();
    }

    for (int i = 0; i<m_count; i++)
    {
        qDebug() << m_comboList.at(i);
    }
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include <QStringList>

#include "comboboxmodel.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    ComboBoxModel combo;

    QStringList tmp;
    tmp << "1" << "2" << "3" << "4" << "5" << "6" << "7";
    combo.setComboList(tmp);

    QQmlContext *ownContext = engine.rootContext();
    ownContext->setContextProperty("myModel", QVariant::fromValue(combo.comboList()));

    QQmlContext *classContext = engine.rootContext();
    classContext->setContextProperty("comboModel", &combo);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml

import QtQuick 2.3
import QtQuick.Controls 2.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }

    ComboBox {
        id: comboBox1

        x: 258
        y: 54
        model: comboModel.comboList
        onActivated: {
            console.log("combomodel activated" + comboBox1.currentIndex)
            comboModel.currentIndex = comboBox1.currentIndex
         }

    }

    Button {
        id: button1
        x: 280
        y: 139
        text: qsTr("Remove Item")
        onClicked: comboModel.removeElement(comboBox1.currentIndex)
    }

    Rectangle{
        x: 281
        y: 316
        width: 80
        height: 20
        color: "white"

        TextEdit {
            id: textEdit1
            width: 80
            height: 20
            text: qsTr("Text Edit")
            font.pixelSize: 12
        }
    }

    Button {
        id: button2
        x: 280
        y: 388
        text: qsTr("Add Item")
        onClicked: comboModel.addElement(textEdit1.text)
    } }

pro-file

QT += quick
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += main.cpp \
    comboboxmodel.cpp

RESOURCES += qml.qrc

QML_IMPORT_PATH =
QML_DESIGNER_IMPORT_PATH =

qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    comboboxmodel.h
like image 1
metty Avatar answered Oct 19 '22 05:10

metty