Qt Quick: как избежать повторения кода при создании похожих элементов GUI в QML?

Прежде всего, я хотел бы извиниться за то, что еще не прочитал всю документацию по QML. Но я должен спросить здесь, потому что это не дает мне спать, так что давайте перейдем к делу:

У меня есть элемент GUI, который повторяется 9 раз. Это прямоугольники, содержащие Image и MouseArea (каждый). Единственным свойством, которое отличает их друг от друга, является их положение в картезианской системе. Остальные свойства абсолютно одинаковы для каждого элемента.

Я нашел это: https://doc.qt.io/qt-6/qml-qtquick-repeater.html

Но тем временем я начал думать, есть ли в QML возможность объявления пользовательских классов, а затем вызывать объекты этого класса с помощью конструктора?

На данный момент мой код состоит из нескольких сотен строк, хотя приложение кажется очень простым. Я даже не представляю, как это будет выглядеть, если я начну что-то более сложное и не найду способа сделать это короче.

Итак, вопрос как в заголовке: Как избежать повторения кода при создании похожих элементов GUI в QML?

Вы можете создать новый файл qml, а затем инкапсулировать элемент управления (например, класс), который вы хотите

Zeus 19.12.2022 03:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
69
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Поскольку вы упомянули Rectangle, MouseArea и Image, я хотел убедиться, что вы проверяете существующие компоненты, такие как ItemDelegate и Button, которые поддерживают свойства background, icon, pressed и имеют сигнал onClicked.

С точки зрения рендеринга, есть не только Repeater, но и ListView и GridView, которые также поддерживают прокручиваемые полосы прокрутки.

В следующем примере я создал MyDelegate.qml, который содержит интерактивный делегат с настраиваемым прямоугольным фоном и настраиваемой иконкой и текстом, 9 экземпляров которого контролируются ListModel:

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
    ListModel {
        id: listModel
        ListElement { txt: "one"; ico: "frown.svg"; icol: "red" }
        ListElement { txt: "two"; ico: "smile.svg"; icol: "green" }
        ListElement { txt: "three"; ico: "smile.svg"; icol: "green" }
        ListElement { txt: "four"; ico: "frown.svg"; icol: "red" }
        ListElement { txt: "five"; ico: "smile.svg"; icol: "green" }
        ListElement { txt: "six"; ico: "frown.svg"; icol: "red" }
        ListElement { txt: "seven"; ico: "smile.svg"; icol: "green" }
        ListElement { txt: "eight"; ico: "frown.svg"; icol: "red" }
        ListElement { txt: "nine"; ico: "frown.svg"; icol: "red" }
    }
    ListView {
        anchors.fill: parent
        model: listModel
        delegate: MyDelegate { }
        ScrollBar.vertical: ScrollBar {
            width: 20
            policy: ScrollBar.AlwaysOn
        }
    }
}

// MyDelegate.qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
ItemDelegate {
    width: ListView.view.width - 20
    background: Rectangle {
        color: pressed ? "orange" : index & 1 ? "#eee" : "#ddd"
    }
    text: txt
    icon.source: ico
    icon.color: icol
}

// smile.svg
<svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 32 32"><path d = "M16 29.8A13.8 13.8 0 1 1 29.8 16 13.815 13.815 0 0 1 16 29.8zm0-26.6A12.8 12.8 0 1 0 28.8 16 12.815 12.815 0 0 0 16 3.2zm-4.5 10.6a1.2 1.2 0 0 0 .608-.168 1.52 1.52 0 0 0 .464-.43 1.927 1.927 0 0 0 .278-.572 2.234 2.234 0 0 0 0-1.26 1.927 1.927 0 0 0-.278-.571 1.52 1.52 0 0 0-.464-.431 1.185 1.185 0 0 0-1.216 0 1.52 1.52 0 0 0-.464.43 1.927 1.927 0 0 0-.277.572 2.234 2.234 0 0 0 0 1.26 1.927 1.927 0 0 0 .277.571 1.52 1.52 0 0 0 .464.431 1.2 1.2 0 0 0 .608.168zm9.608-.168a1.52 1.52 0 0 0 .464-.43 1.927 1.927 0 0 0 .278-.572 2.234 2.234 0 0 0 0-1.26 1.927 1.927 0 0 0-.278-.571 1.52 1.52 0 0 0-.464-.431 1.185 1.185 0 0 0-1.216 0 1.52 1.52 0 0 0-.464.43 1.927 1.927 0 0 0-.277.572 2.234 2.234 0 0 0 0 1.26 1.927 1.927 0 0 0 .277.571 1.52 1.52 0 0 0 .464.431 1.185 1.185 0 0 0 1.216 0zm3.223 5.743l-.926-.379a7.863 7.863 0 0 1-7.39 4.976.166.166 0 0 0-.032 0 7.863 7.863 0 0 1-7.388-4.976l-.926.379a8.846 8.846 0 0 0 8.313 5.597.21.21 0 0 0 .035 0 8.848 8.848 0 0 0 8.314-5.597z"/><path fill = "none" d = "M0 0h32v32H0z"/></svg>

// frown.svg
<svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 32 32"><path d = "M16 29.8A13.8 13.8 0 1 1 29.8 16 13.815 13.815 0 0 1 16 29.8zm0-26.6A12.8 12.8 0 1 0 28.8 16 12.815 12.815 0 0 0 16 3.2zm6.318 20.026l.692-.723c-3.604-3.451-10.418-3.452-14.02 0l.692.723c3.19-3.057 9.448-3.055 12.636 0zM11.5 13.8a1.2 1.2 0 0 0 .608-.168 1.52 1.52 0 0 0 .464-.43 1.927 1.927 0 0 0 .278-.572 2.234 2.234 0 0 0 0-1.26 1.927 1.927 0 0 0-.278-.571 1.52 1.52 0 0 0-.464-.431 1.185 1.185 0 0 0-1.216 0 1.52 1.52 0 0 0-.464.43 1.927 1.927 0 0 0-.277.572 2.234 2.234 0 0 0 0 1.26 1.927 1.927 0 0 0 .277.571 1.52 1.52 0 0 0 .464.431 1.2 1.2 0 0 0 .608.168zm9.608-.168a1.52 1.52 0 0 0 .464-.43 1.927 1.927 0 0 0 .278-.572 2.234 2.234 0 0 0 0-1.26 1.927 1.927 0 0 0-.278-.571 1.52 1.52 0 0 0-.464-.431 1.185 1.185 0 0 0-1.216 0 1.52 1.52 0 0 0-.464.43 1.927 1.927 0 0 0-.277.572 2.234 2.234 0 0 0 0 1.26 1.927 1.927 0 0 0 .277.571 1.52 1.52 0 0 0 .464.431 1.185 1.185 0 0 0 1.216 0z"/><path fill = "none" d = "M0 0h32v32H0z"/></svg>

Вы можете Попробовать онлайн!

Конечно же, есть и подобные существующие объекты! В любом случае стоит приступить к созданию пользовательских типов. Честно говоря, в последние несколько дней я начал всерьез задумываться о том, стоит ли специализироваться на Qt, хотя он выглядит огромным. Гигантская библиотека + изучение нового языка

Mstfktr1983 20.12.2022 01:26
Ответ принят как подходящий

У вас есть несколько вариантов определения типов объектов QML, посмотрите документацию.

Определение типа объекта с помощью файла QML

Для создания типа объекта документ QML должен быть помещен в текстовый файл с именем TypeName.qml, где TypeName — желаемое имя тип.

// ImageButton.qml
import QtQuick 2.0

Item {
    width: 100
    height: 100

    Image {
        anchors.fill: parent
        source: "test.png"
    }

    MouseArea {
        anchors.fill: parent
        onClicked: console.info("Button clicked!")
    }
}

Поскольку файл называется ImageButton.qml, теперь его можно использовать как тип с именем ImageButton в любом другом файле QML в том же каталоге.

// myapplication.qml
import QtQuick 2.0

ImageButton {}

Определение встроенного типа объекта

Вы можете использовать встроенные компоненты для объявления нового компонента внутри файла.

// myapplication.qml
import QtQuick 2.0

component ImageButton : Item {
    width: 100
    height: 100

    Image {
        anchors.fill: parent
        source: "test.png"
    }

    MouseArea {
        anchors.fill: parent
        onClicked: console.info("Button clicked!")
    }
}

ImageButton {}

Используйте Компонент Тип QML

Я бы предпочел использовать один из приведенных выше вариантов, потому что этот вариант имеет некоторые ограничения на использование ваших пользовательских компонентов. Я бы использовал тип Component QML, если компонент будет использоваться только в качестве делегата. Вот цитата из документации:

Иногда бывает неудобно создавать новый файл для типа, т.к. instance при повторном использовании небольшого делегата в нескольких представлениях. если вы не на самом деле нужно выставить тип, но нужно только создать экземпляр, Компонент является опцией. Но если вы хотите объявить свойства с помощью типы компонентов, или если вы хотите использовать его в нескольких файлах, Component это не вариант. В этом случае вы можете использовать встроенные компоненты.

Другие вопросы по теме