I have already told in the article about the creation of dynamic widgets to Qt , how to create and delete buttons dynamically, as well as how to interact with them. And there used Vertical Layout, a case we can use QML ListView Qml, both similarly used when programming in Java for Android. That, incidentally, is also applicable when programming in Qt for Android.
The article about the dynamic creation of widgets used for example QButton class objects. This article will use the objects Button Qml, which customization was discussed in the following article . But the key will be placed in the ListView Qml.
Project structure for ListView Qml
This time dispense project created by default and even without the designer interface. Especially because at the time of this writing, not all parameters can be set in the designer. A following project structure:
- QmlDynamic.pro - the profile of the project;
- deployment.pri - deploy rules file on the target platform;
- main.cpp - the main application startup file;
- main.qml - qml file with the original program codes
main.qml
Since all of the other files do not represent any interest for us and created by default, then immediately move on to the the file main.qml.
The algorithm of the program is as follows. At the top of the application window has a Row object, which is a text box and two buttons. The remainder of the application window object takes ListView Qml . By pressing one of the buttons in the Row creates a dynamic object in the ListView Qml, which contains the button. By pressing the button, the dynamic in the text box on the Row passed ListElement index, which is the button on which the press was made. And then pressing the second button in the Row object on the index of the text box is removed an item from the ListView Qml, and the value in the text box is cleared.
Noteworthy is the fact that if you delete an item, which is located in the middle of the list, for example, indexes of all the elements following this reduced by one element. That is, the indices of the items are recalculated automatically.
import QtQuick 2.5 import QtQuick.Controls 1.4 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Hello World") /* Number created buttons for her visual identification of the demonstration project */ property int number: 0 /* The string field that displays dynamically pressed the button index button * to create dynamic buttons, and a button to delete the index of dynamic buttons * */ Row { id: row // Set line size and nailed to the top of the application window height: 50 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right Rectangle { width: (parent.width / 5) height: 50 // Set the text box to accommodate the key index Text { id: textIndex anchors.fill: parent text: "" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } // Button to create dynamic buttons Button { id: button1 text: qsTr("Create Button") width: (parent.width / 5)*2 height: 50 /* By clicking on the button to add the model ListView object * with the specified parameters * */ onClicked: { listModel.append({idshnik: "Button " + (++number)}) } } // Button to remove the dynamic buttons Button { id: button2 text: qsTr("Delete Button") width: (parent.width / 5)*2 height: 50 // Remove the button on its index in the ListView onClicked: { if(textIndex.text != ""){ listModel.remove(textIndex.text) textIndex.text = "" // Null text box with index } } } } // ListView to represent the data as a list ListView { id: listView1 // We place it in the remainder of the application window anchors.top: row.bottom anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right /* in this property we specify the layout of the object * that will be displayed in the list as a list item * */ delegate: Item { id: item anchors.left: parent.left anchors.right: parent.right height: 40 Button { anchors.fill: parent anchors.margins: 5 /* The most interesting in this facility We set text property variable name, * which will set the properties of the element * */ text: idshnik // By clicking on the button in the text box we return the index in the ListView onClicked: { textIndex.text = index } } } model: ListModel { id: listModel } } }
Conclusion
As a result, you will receive an application in which dynamically created and deleted with buttons that will appear as shown in the figure.
Здравствуйте,
Не хотелось бы повторяться. В статье по сигналам и слотам в QML есть вариант использования C++ объекта. Там используется тип Connections , который можно настроить на сигнал, который передаёт некое значение, тот же самый ID.
Большое спасибо за ответ.
А я не понимаю, как представление ссылается на модель? Нигде ведь не указано, что представление использует именно модель с id : listModel.
ps.
Ни JavaScript ни JSON не знаю, проблема в этом ? :)
Сама модель устанавливается в качестве property в представление.
Точно.
Я почему-то подумал, что парент у ListModel главное окно, а не представление.
Три закрывающие скобки сбили с толка :)
Спасибо.
Можно и окно парентом сделать, то есть написать код модели под представлением. Но тогда в property model потребуется передать id этой модели.
Не могу понять, как мы добавляем новый элемент в listModel на строчке 53.
Как я понял из прочитанного: delegate дополняет listModel своими данными, чтобы было удобно ее отображать. В данном случае этими данными является idshnik. Сама listModel не хранит idshnik.
Возникает вопрос, как мы можем писать следующее listModel.append({idshnik: "Button " + (++number)}).
Ведь что получается, что добавляя новый элемент в listModel мы передаем данные idshnik, а listModel их не хранит. Получается, они передаются сразу делегату? Или я запутался?
idshnik - это роль в модели данных.
Когда в QML в модель добавляются данные таким способом
строчки 111-114
Создается модель без каких-либо еще ролей, это так?При первом добавлении элемента задается роль?
Но ведь это всего лишь текст кнопки.
Роли здесь определяются автоматически. В самой модели в данном случае роль не определяется, как например сделано в этой статье , где имена ролей указываются в методе roleNames. Так что да, в строка 111-114 создаётся модель без предопределённых ролей.
Как я понимаю, когда делегат пытается получить данные из модели, он отправляет в модель имя роли, по которому модель отыскивает нужное свойство в объекте, который был добавлен в строке 53.
Отлично, теперь понял.
И изменить набор ролей уже будет нельзя, если мы их уже задали.
Что говорится в "Note that when creating content dynamically the set of available properties cannot be changed once set. Whatever properties are first added to the model are the only permitted properties in the model." на http://doc.qt.io/Qt-5/qml-qtqml-models-listmodel.html#append-method .
Благодарю, Евгений.
Приветствую. Подскажите пожалуйста, как сделать так что бы на элементе ListView изначально был activeFocus. Ни как не получается это сделать. Даже если добавить
То все равно
выдает сначала true, а потом сразу же false. Если же нажать Tab то актив фокус сразу же устанавливается на элементе ListView. Вроде доходчиво объяснил проблему. Помогите кто знает решение.
Наверное, у вас что-то ещё не успело загрузиться в тот момент, и это что-то забирает фокус на себя. Попробуйте найти тот виджет, который забирает фокус и после его инициализации верните фокус на ListView.
Дело в том, что на данный момент на странице нет ничего кроме этого ListView, а в нем лишь модель и делегат.
Не помню порядок инициализации в QML и вызова метода onCompleted, возможно, что объекты в делегате будут созданы последними в итоге.
Можете попробовать сделать задержку таймером установить фокус по сработке таймера.
Я нашел в чем проблема. Страница у меня эта не первая, и не единственная. И проблемы прилетали с основного файла где крутился StackView с моими страницами. И еще я реализовал разные страницы как Item, а не Page. То есть общий фон и на нем сменялись эти самые Item'ы. Перевел все на Page - и все проблемы исчезли.
Ну видите )) Было же ещё что-то кроме того ListView ))
Добрый день.
Очень полезная статья. Спасибо.
Вопрос такой: 1) нужно "взять" кнопку 2 пальцем (прикаснулись пальцем к кнопке 2, держим, через 2-3 кнопка оторвалась от ListView) и перетащить её между 7 и 8. Как такое в Qml реализовать? куда копать?
2) можно удалить кнопку "викинув" её? Т.е. горизонтально чиркнули по кнопке слева направо, кнопка визуально улетела и соседние кнопки сомкнулись. Наподобе как в андроиде удаляются уведомления.
Давно уже не работал с QML. Qt поддерживает во вторых котролах Material Design, но не знаю, насколько он реализует данный функционал. Felgo - QML based фреймворк реализует подобные вещи.
Но что касается drag and drop фунционала, то тут нужно создавать плавающий rectangle, который будет летать за пальцем, правильно высчитывать все позиции всех элементов и т.д. В общем достаточное количество кода будет.