Programación Gráfica en C++: Crear Lista Desplegable con Qt Quick ComboBox

Para crear una lista desplegable en Qt Quick, usaremos el componente ComboBox. Cuando ejecutes esta aplicación, verás un ComboBox que despliega la lista de elementos. Al seleccionar un elemento, se mostrará en la parte superior del ComboBox, y se imprimirá en la consola el elemento seleccionado.

import QtQuick
import QtQuick.Controls

ApplicationWindow {
    visible: true
    width: 400
    height: 200
    title: "Lista Desplegable"

    ComboBox {
        id: comboBox
        width: parent.width - 20
        model: ListModel {
            ListElement { text: "Elemento 1" }
            ListElement { text: "Elemento 2" }
            ListElement { text: "Elemento 3" }
        }

        onCurrentIndexChanged: {
            var selectedText = model.get(currentIndex).text;
            console.log("Seleccionaste: " + selectedText);
        }
    }
}

En este ejemplo, hemos utilizado un ComboBox que muestra una lista de elementos desplegables. Los elementos se definen en un modelo, y cuando seleccionas un elemento en el ComboBox, se ejecuta la función onCurrentIndexChanged, que imprime el elemento seleccionado en la consola.

Un ejemplo más elaborado: Crear, copiar los códigos y ejecutar el proyecto que contiene los 3 archivos siguientes: myObject.h, main.cpp y Main.qml:

myObject.h

// MyObject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <QObject>
#include <QQmlContext>
#include <QtQml>

class MyObject : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    Q_PROPERTY(int new_generateNumber MEMBER my_generateNumber NOTIFY generateNumber_slot);

public:
    explicit MyObject(QObject *parent = nullptr);
    Q_INVOKABLE void generateNumber(int min, int max);
    Q_INVOKABLE int getX();

public slots:
    void  generateNumber_slot();

signals:
    void generateNumber_signal(int);
private:
    int my_generateNumber = 0;
};

#endif // MYOBJECT_H

Aquí está una descripción de las principales líneas del código anterior:

  1. Inclusión de cabeceras: El código incluye varias cabeceras de Qt, como QObject, QQmlContext, QtQml, que son necesarias para trabajar con Qt Quick y para la creación de objetos QML.
  2. Declaración de la clase MyObject: La clase creada MyObject se deriva de QObject, lo que la hace una clase que puede ser utilizada en el sistema de objetos de Qt. Además, se marca con la macro Q_OBJECT, que es necesaria para habilitar la funcionalidad de señales y ranuras de Qt.
  3. Uso de la macro QML_ELEMENT: Esta macro se usa para registrar la clase como un elemento QML, lo que permite su uso en archivos QML.
  4. Declaración de una propiedad QML: Se declara una propiedad llamada new_generateNumber que se conecta al miembro my_generateNumber. Esto permitirá a los objetos QML acceder y modificar el valor de my_generateNumber a través de esta propiedad.
  5. Métodos Q_INVOKABLE: Se declaran dos métodos marcados como Q_INVOKABLE. Estos métodos pueden ser llamados desde el código QML. generateNumber toma dos parámetros (min y max) y getX no toma ningún parámetro. generateNumber_slot es un método público que se puede invocar desde fuera de la clase.
  6. Signals y slots: Se declara una señal llamada generateNumber_signal que emite un entero como argumento. También hay un slot llamado generateNumber_slot. Las señales y los slots se utilizan para la comunicación entre objetos en Qt.

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDebug>
#include <QRandomGenerator>
#include "MyObject.h"

// Funciones para manejar las señales
MyObject::MyObject(QObject *parent)
    : QObject(parent)
{
    QObject::connect(this, &MyObject::generateNumber_signal, this, &MyObject::generateNumber_slot);
}

void MyObject::generateNumber_slot(){
    my_generateNumber++;
    qInfo() << "Dentro de slot:" << my_generateNumber;
}

int MyObject::getX()
{
   return 10;
}

QStringList getList()
{
   QStringList dataList = {
       "Item A",
       "Item B",
       "Item C",
       "Item D"
   };

   return dataList;
}

void MyObject::generateNumber(int min, int max)
{
    const int num_aleatorio = QRandomGenerator::global()->bounded(min,max);
    qDebug() << "Called the c++ signal with num_aleatorio" << num_aleatorio;
    emit generateNumber_signal(num_aleatorio);

}


int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    const QUrl url(u"qrc:/MiProyectoQtQuick_1/Main.qml"_qs);

    engine.load(url);

    if (engine.rootObjects().isEmpty())
        return -1;

    engine.rootContext()->setContextProperty("comboModel2", getList() );

    return app.exec();
}

Este código anterior es la implementación principal de la aplicación en C++ que utiliza Qt y Qt Quick para crear una interfaz de usuario y conectarla con la clase MyObject que hemos definido previamente:

  1. Incluye las cabeceras necesarias, como QGuiApplication, QQmlApplicationEngine, QQmlContext, QDebug, QRandomGenerator y el archivo de cabecera "MyObject.h", que contiene la definición de la clase MyObject.
  2. En la función main, se crea una instancia de QGuiApplication para manejar la aplicación y una instancia de QQmlApplicationEngine para cargar y ejecutar la interfaz de usuario QML.
  3. Se carga el archivo QML principal (Main.qml) desde un recurso Qt utilizando la URL qrc:/MiProyectoQtQuick_1/Main.qml.
  4. Si la carga del motor de aplicaciones QML tiene éxito, se establece el contexto de la raíz del motor para exponer un modelo de datos (comboModel2) al QML. En este caso, el modelo de datos es una lista de cadenas obtenidas de la función getList().
  5. Se ejecuta la aplicación llamando a app.exec(), lo que inicia el bucle principal de la aplicación y muestra la ventana de la interfaz de usuario.
  6. En el código de la clase MyObject, se definen las funciones que se conectan a señales y se pueden llamar desde QML. La función generateNumber_slot se conecta a la señal generateNumber_signal, y cuando se emite esta señal, incrementa el valor de my_generateNumber y muestra un mensaje de registro con el nuevo valor. La función getX simplemente devuelve el valor 10.
  7. La función generateNumber genera un número aleatorio entre los valores min y max, emite la señal generateNumber_signal con ese número y muestra un mensaje de registro con el número aleatorio generado.

Main.qml

import QtQuick 2.3
import QtQuick.Controls 2.2
import QtQuick.Layouts
import QtQuick.Controls.Material
import MiProyectoQtQuick_1

ApplicationWindow {
    id: window1
    visible: true
    width: 640
    height: 480
    title: qsTr("App: " + windowTitle)
    property string windowTitle: "Hola Mundo"
    property int randNum:0

    MyObject {
        id: myObject
        onGenerateNumber_signal:  (num) => {
                          randNum = num
                         }
    }

    ComboBox {
        id: comboBox1
        x: 258
        y: 50
        model: comboModel
        onActivated: {
            console.log("ComboBox activated:" + comboBox1.currentIndex)
         }

    }

    ComboBox {
        id: comboBox2
        currentIndex: 0
        model: comboModel2
        x: 258
        y: 120
    }

    ListModel {
        id: comboModel
        ListElement { text: "Item 1" }
        ListElement { text: "Item 2" }
        ListElement { text: "Item 3" }
    }

    Button {
        id: button1
        x: 258
        y: 200
        text: qsTr("Remove Item de ComboBox1")
        onClicked: comboModel.remove(comboBox1.currentIndex)
    }

    Button {
        id: button2
        x: 258
        y: 250
        text: qsTr("Add Item al ComboBox1")
        onClicked: comboModel.insert(0, { text: "Nuevo Item" })
    }

    Button {
        id: button3
        x: 258
        y: 300
        text: qsTr("Add Item desde Función C++")
        onClicked: {
            onClicked: comboModel.insert(0, { text: myObject.getX().toString() })
            console.log(" X=" +  myObject.getX())
        }
    }

    Button {
        id: button4
        x: 258
        y: 350
        text: qsTr("Add Item desde Signal C++")
        onClicked: {
            myObject.generateNumber(1, 5)
            onClicked: comboModel.insert(0, { text: randNum.toString() })
        }       
    }

    Button {
        id: button5
        x: 258
        y: 400
        text: qsTr("Add Item desde Slot  C++")
        onClicked: {
            myObject.new_generateNumber++
            onClicked: comboModel.insert(0, { text: myObject.new_generateNumber.toString() })
        }
    }

}

El código anterior es una interfaz de usuario en QML que utiliza el objeto MyObject que hemos definido previamente en C++.

  1. Importaciones: Se importan varios módulos de Qt Quick y Qt Quick Controls que se utilizarán en la interfaz de usuario. Además, se importa un módulo llamado MiProyectoQtQuick_1, que contiene la definición de la clase MyObject que creamos.
  2. ApplicationWindow: Se crea una ventana de la aplicación (ApplicationWindow) con propiedades como width, height, title, etc. Se define una propiedad windowTitle que se utiliza como título de la ventana y una propiedad randNum que se utiliza para almacenar un número generado desde el objeto MyObject.
  3. MyObject: Se crea una instancia de la clase MyObject con el id myObject. Cuando la señal generateNumber_signal de myObject se emite, se actualiza la propiedad randNum con el valor emitido.
  4. ComboBox: Se crean dos listas despegables (ComboBox) con comboBox1 y comboBox2. comboBox1 utiliza un modelo llamado comboModel que contiene elementos de lista. comboBox2 utiliza un modelo llamado comboModel2.
  5. ListModel: Se define un modelo llamado comboModel que contiene elementos de lista (ListElement) con texto, que se utilizarán en comboBox1. Este modelo se inicializa con tres elementos.
  6. Botones: Se crean cinco botones con etiquetas y funciones asociadas:
  • button1: Elimina el elemento seleccionado en comboBox1.
  • button2: Inserta un nuevo elemento al principio de comboBox1.
  • button3: Llama a la función getX de myObject para obtener un valor desde C++ y lo inserta al principio de comboBox1.
  • button4: Llama al método generateNumber de myObject para generar un número y lo inserta al principio de comboBox1.
  • button5: Incrementa la propiedad new_generateNumber de myObject y lo inserta al principio de comboBox1.
Ejemplo de Qt Quick View C++

Deja un comentario