En esta página

Mejores prácticas para QML y Qt Quick

A pesar de todas las ventajas que ofrecen QML y Qt Quick, pueden suponer un reto en determinadas situaciones. En las siguientes secciones se detallan algunas de las mejores prácticas que le ayudarán a obtener mejores resultados al desarrollar aplicaciones.

Utilice controles integrados en lugar de controles de interfaz de usuario personalizados

Una interfaz de usuario fluida y moderna es clave para el éxito de cualquier aplicación en el mundo actual, y ahí es donde QML tiene mucho sentido para un diseñador o desarrollador. Qt ofrece los controles de interfaz de usuario más básicos, necesarios para crear una interfaz de usuario fluida y moderna. Se recomienda consultar esta lista de controles de interfaz de usuario antes de crear su propio control de interfaz de usuario personalizado.

Además de estos controles de interfaz de usuario básicos ofrecidos por Qt Quick, también hay disponible un amplio conjunto de controles de interfaz de usuario en Qt Quick Controls. Cubren los casos de uso más comunes sin ningún cambio, y ofrecen muchas más posibilidades con sus opciones de personalización. En concreto, Qt Quick Controls ofrece opciones de estilo que se ajustan a las últimas tendencias de diseño de interfaz de usuario. Si estos controles de interfaz de usuario no satisfacen las necesidades de su aplicación, sólo entonces se recomienda crear un control personalizado.

Puede utilizar los controles cuando diseñe interfaces de usuario en Qt Design Studio. Además, proporciona animaciones basadas en líneas de tiempo, efectos visuales, diseños y una vista previa en vivo para la creación de prototipos de aplicaciones.

Convenciones de codificación

Consulte Convenciones de codificación QML.

Agrupación de recursos de la aplicación

La mayoría de las aplicaciones dependen de recursos, como imágenes e iconos, para proporcionar una experiencia de usuario enriquecida. A menudo puede ser un reto hacer que estos recursos estén disponibles para la aplicación independientemente del sistema operativo de destino. Los sistemas operativos más populares emplean políticas de seguridad que restringen el acceso al sistema de archivos, lo que dificulta la carga de estos recursos. Como alternativa, Qt ofrece su propio sistema de recursos que está integrado en el binario de la aplicación, permitiendo el acceso a los recursos de la aplicación independientemente del sistema operativo de destino.

Por ejemplo, para un proyecto C++, considere la siguiente estructura de directorios:

MyModule
├── images
│   ├── image1.png
│   └── image2.png
├── CMakeLists.txt
└── main.qml

Puede representar esta estructura como un módulo CMake QML de la siguiente manera:

qt_add_qml_module(my_module
   URI MyModule
   VERSION 1.0
   QML_FILES
       main.qml
   RESOURCES
       images/image1.png
       images/image2.png
   # ...
)

Todos los archivos QML que figuran en QML_FILES se compilará automáticamente antes de tiempo.

Usted debe mantener los archivos QML en el mismo directorio que el CMakeLists.txt con el qt_add_qml_module. De lo contrario, sus importaciones implícitas serán diferentes de los módulos QML a los que pertenecen. Esta es una fuente frecuente de errores.

Separar la interfaz de usuario de la lógica de negocio

Uno de los objetivos clave que la mayoría de los desarrolladores de aplicaciones quieren alcanzar es crear una aplicación fácil de mantener. Una de las formas de lograr este objetivo es separar la interfaz de usuario, el frontend, de la lógica de negocio, el backend. A continuación se exponen algunas razones por las que la interfaz de usuario de una aplicación debería escribirse en QML:

  • Los lenguajes declarativos son muy adecuados para definir interfaces de usuario.
  • El código QML es más sencillo de escribir, ya que es menos verboso que C++ y no está fuertemente tipado. Esto también hace que sea un lenguaje excelente para crear prototipos, una cualidad vital a la hora de colaborar con diseñadores, por ejemplo.
  • JavaScript puede utilizarse fácilmente en QML para responder a eventos.

Los lenguajes fuertemente tipados, como C++, son los más adecuados para la lógica de negocio de una aplicación, el backend. Normalmente, este tipo de código realiza tareas como cálculos complejos o procesamiento de datos, que son más rápidas en lenguajes fuertemente tipados que en QML.

Qt ofrece varios enfoques para integrar QML con un lenguaje fuertemente tipado en una aplicación. Un caso de uso típico es la visualización de una lista de datos en una interfaz de usuario. Si el conjunto de datos es estático, simple y pequeño, un modelo escrito en QML puede ser suficiente.

El siguiente fragmento muestra ejemplos de modelos escritos en QML:

model: [ "Item 1", "Item 2", "Item 3" ]

model: 10

Para conjuntos de datos más grandes y dinámicos, utilice un lenguaje fuertemente tipado, como C++, para manejar la lógica de negocio.

Exposición de datos de C++ a QML

Refactorizar QML es mucho más fácil que refactorizar C++, por lo que, para que el mantenimiento sea sencillo, debemos esforzarnos por mantener los tipos de C++ fuera de QML en la medida de lo posible. Esto se puede conseguir "empujando" las referencias a los tipos de C++ a QML.

Esto puede hacerse utilizando propiedades requeridas y estableciéndolas a través de QQmlApplicationEngine::setInitialProperties. También es posible crear uno o varios singletons que devuelvan todos los datos que la parte C++ desee proporcionar a QML.

Con este enfoque, el C++ permanece inalterado en caso de que el QML necesite ser refactorizado en el futuro.

Para obtener una guía rápida sobre cómo elegir el enfoque correcto para exponer tipos C++ a QML, consulte Elección del método de integración correcto entre C++ y QML.

Uso de Qt Design Studio

Qt Design Studio utiliza archivos de interfaz de usuario que tienen la extensión de nombre de archivo .ui.qml para separar las partes visuales de la interfaz de usuario de la lógica de interfaz de usuario que implementa en los archivos .qml. Debe editar los archivos de interfaz de usuario sólo en la vista 2D en Qt Design Studio. Si utiliza alguna otra herramienta para añadir código que Qt Design Studio no admite, mostrará mensajes de error. Corrija los errores para volver a permitir la edición visual de los archivos de interfaz de usuario. Normalmente, debe mover el código no compatible a un archivo .qml.

Uso de Qt Quick Views

Almacenar estado en modelos

Véase Avoid Storing State in Delegates.

Usando Qt Quick Layouts

Qt ofrece Qt Quick Layouts para organizar elementos Qt Quick visualmente en un diseño. A diferencia de su alternativa, los posicionadores de ítems, los Qt Quick Layouts también pueden redimensionar sus hijos al redimensionar la ventana. Aunque Qt Quick Layouts son a menudo la opción deseada para la mayoría de los casos de uso, lo siguiente debe ser considerado al usarlos:

Dos

  • Utilice anchors o las propiedades width y height para especificar el tamaño del diseño con respecto a su elemento padre no diseño.
  • Utilice la propiedad adjunta Layout para establecer los atributos de tamaño y alineación de los elementos hijos inmediatos del diseño.

Lo que no se debe hacer

  • No defina tamaños preferentes para elementos que proporcionen implicitWidth e implicitHeight, a menos que sus tamaños implícitos no sean satisfactorios.
  • No utilice anclajes en un elemento que sea hijo inmediato de una maquetación. En su lugar, utilice Layout.preferredWidth y Layout.preferredHeight:
    RowLayout {
        id: layout
        anchors.fill: parent
        spacing: 6
        Rectangle {
            color: 'orange'
            Layout.fillWidth: true
            Layout.minimumWidth: 50
            Layout.preferredWidth: 100
            Layout.maximumWidth: 300
            Layout.minimumHeight: 150
            Text {
                anchors.centerIn: parent
                text: parent.width + 'x' + parent.height
            }
        }
        Rectangle {
            color: 'plum'
            Layout.fillWidth: true
            Layout.minimumWidth: 100
            Layout.preferredWidth: 200
            Layout.preferredHeight: 100
            Text {
                anchors.centerIn: parent
                text: parent.width + 'x' + parent.height
            }
        }
    }

Nota: Tanto las maquetas como las anclas son tipos de objetos que consumen más memoria y tiempo de instanciación. Evita utilizarlos (especialmente en listas y tablas delegadas, y en estilos para controles) cuando basta con simples enlaces a las propiedades x, y, anchura y altura.

Seguridad de tipos

Cuando se declaran propiedades en QML, es fácil y cómodo utilizar el tipo "var":

property var name
property var size
property var optionsMenu

Sin embargo, este enfoque tiene varias desventajas:

  • Si se asigna un valor con un tipo incorrecto, el error notificado apuntará a la ubicación de la declaración de la propiedad, en lugar de a la ubicación donde se asignó la propiedad. Esto ralentiza el proceso de desarrollo al dificultar la localización de errores.
  • El análisis estático para detectar errores como los mencionados anteriormente no es posible.
  • El tipo real subyacente de la propiedad no siempre está claro para el lector.

En su lugar, utilice siempre que sea posible el tipo real:

property string name
property int size
property MyMenu optionsMenu

Señales de cambio de propiedad

Prefiera utilizar las señales de interacción explícitas a las señales de cambio de valor para evitar errores sutiles.

El uso de valueChanged puede dar lugar a cascadas de eventos en las que el valor cambia constantemente porque se redondea o normaliza de alguna manera.

El uso de señales de interacción explícitas evita toda esta clase de problemas.

Por ejemplo, Slider tiene estas señales similares: moved y valueChanged.

Slider {
    value: someValueFromBackend

    onValueChanged: pushToBackend(value)
    // or
    onMoved: pushToBackend(value)
}

Ambos casos parecen similares, y es posible que desee utilizar valueChanged.

Los desarrolladores a menudo pasan por alto el hecho de que Slider puede cambiar automáticamente su valor, por ejemplo, debido a la sujeción a valores mínimos/máximos o al redondeo. En este caso, se emite la señal valueChanged. Si utiliza la señal valueChanged, puede notar que se emite en momentos inesperados.

Para evitar posibles problemas, utilice una señal de interacción: la señal que se emite cuando el usuario interactúa con el control. En este ejemplo, si utilizas la señal moved, el slot sólo se disparará si el usuario cambia el control.

Rendimiento

Para obtener información sobre el rendimiento en QML y Qt Quick, consulte Consideraciones y sugerencias sobre el rendimiento en QML.

Prefiera los enlaces declarativos a las asignaciones imperativas

En QML, es posible utilizar código JavaScript imperativo para realizar tareas como responder a eventos de entrada, enviar datos a través de una red, etcétera. El código imperativo ocupa un lugar importante en QML, pero también es importante saber cuándo no se debe utilizar.

Por ejemplo, considere la siguiente asignación imperativa:

Rectangle {
    Component.onCompleted: color = "red"
}

Tiene las siguientes desventajas:

  • Es lenta. La propiedad color se evaluará primero con un valor construido por defecto, y de nuevo con "red" más tarde.
  • Retrasa los errores que podrían encontrarse en tiempo de compilación a tiempo de ejecución, ralentizando el proceso de desarrollo.
  • Sobrescribe cualquier vinculación declarativa existente. En la mayoría de los casos esto es intencionado, pero a veces puede ser involuntario. Consulte Depuración de la sobreescritura de enlaces para obtener más información.
  • Interfiere con las herramientas; Qt Quick Designer, por ejemplo, no admite JavaScript.

El código puede reescribirse para que sea una vinculación declarativa:

Rectangle {
    color: "red"
}

No almacenar estado en delegados

No almacenes un estado en un delegado. El problema aquí es que el delegado se crea y se destruye varias veces, por lo que el estado guardado se perderá.

// Wrong approach:
ListView {
    // ...

    delegate: Button {
        // ...
        property bool someStateProperty
        onClicked: someStateProperty = true
    }
}

En su lugar, almacena el estado fuera del delegado. Por ejemplo, en un modelo. Cuando se destruye el delegado, el estado guardado no se pierde.

// Right approach:
ListView {
    // ...

    delegate: Button {
        // ...
        onClicked: model.someStateProperty = true
    }
}

Traduzca las cadenas de texto orientadas al usuario

Se recomienda hacer traducibles las cadenas orientadas al usuario desde el principio. Consulte Escribir código fuente para la traducción.

ToolButton {
    id: selectionToolButton
    // ...
    icon.source: "qrc:/images/selection.png"

    Tooltip.Text: qsTr("Select pixels within an area and move them")

    onClicked: canvas.tool = ImageCanvas.SelectionTool
}

No personalice los estilos nativos

Los estilos nativos (estilos de Windows y macOS) no admiten personalización. Asegúrese de no personalizar un estilo nativo.

// Wrong approach:
import QtQuick.Controls.Windows

// Don't customize a native style
Button {
    background: Rectangle { /*...*/ }
}

En su lugar, se recomienda basar siempre un control personalizado sobre un único estilo que esté disponible en todas las plataformas, por ejemplo, Basic Style, Fusion Style, Imagine Style, Material Style, Universal Style. De este modo, se garantiza que siempre tendrá el mismo aspecto, independientemente del estilo con el que se ejecute la aplicación. Para aprender a utilizar un estilo diferente, consulte Uso de estilos en Qt Quick Controls. También puede crear su propio estilo.

// Right approach:
import QtQuick.Controls.Basic

// You can customize a commonly available style
Button {
    background: Rectangle { /*...*/ }
}

Herramientas y utilidades

Para obtener información sobre herramientas y utilidades útiles que facilitan el trabajo con QML y Qt Quick, consulte Qt Quick Herramientas y utilidades.

Gráfico de escenas

Para obtener información sobre el gráfico de escenas de Qt Quick, consulte Qt Quick Gráfico de escenas.

Interfaces de usuario escalables

A medida que mejoran las resoluciones de pantalla, se hace cada vez más importante disponer de una interfaz de usuario escalable. Uno de los métodos para conseguirlo es mantener varias copias de la interfaz de usuario para distintas resoluciones de pantalla y cargar la adecuada en función de la resolución disponible. Aunque esto funciona bastante bien, aumenta la sobrecarga de mantenimiento.

Qt ofrece una solución mejor a este problema y recomienda a los desarrolladores de aplicaciones seguir estos consejos:

  • Utilizar anclajes o el módulo Qt Quick Layouts para distribuir los elementos visuales.
  • No especificar anchura y altura explícitas para un elemento visual.
  • Proporcione recursos de interfaz de usuario, como imágenes e iconos, para cada resolución de pantalla que admita su aplicación. El ejemplo de la galería Qt Quick Controls lo demuestra bien proporcionando qt-logo.png para las resoluciones @2x, @3x y @4x, permitiendo a la aplicación adaptarse a pantallas de alta resolución. Qt elige automáticamente la imagen apropiada que es adecuada para la pantalla dada, siempre que la función de escalado de alta DPI esté explícitamente habilitada.
  • Utilizar imágenes SVG para iconos pequeños. Mientras que los SVG más grandes pueden ser lentos de renderizar, los pequeños funcionan bien. Las imágenes vectoriales evitan la necesidad de proporcionar varias versiones de una imagen, como ocurre con las imágenes de mapa de bits.
  • Utiliza iconos basados en fuentes, como Font Awesome. Se adaptan a cualquier resolución de pantalla y permiten colorearlos. El ejemplo del editor de texto Qt Quick Controls lo demuestra muy bien.

De este modo, la interfaz de usuario de tu aplicación se adaptará a la resolución de pantalla disponible.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.