Qt: создаём список QListWidget и управляем его элементами
Просто чтобы не затерялся пример в недрах авторизованного мира, а вообще, в блоге уже есть несколько статей по спискам в Qt.
В Qt есть две группы встроенных списочных виджетов:
- Model-based: рассчитаны на проектирование приложений, работающих с данными в парадигме MVC (см., например, здесь);
- Item-based: основаны на прямой работе с элементами. Пока займёмся ими, как более понятными.
Создадим виджет с формой на основе класса QWidget как в предыдущих примерах.
С помощью стандартных средств компоновки подготовим форму со списком QListWidget и панелью кнопок для выполнения типовых действий над списком.
форма окна приложения
Можно было создать список и программно, например, в конструкторе виджета:
QListWidget *list = new QListWidget(this);
Элементы списка QListWidgetItem могут быть добавлены в список программно или же созданы без родительского элемента-списка и потом добавлены отдельно (выполним этот код по кнопке 1):
void Widget::on_pushButton_clicked() { new QListWidgetItem(tr("Элемент 1"),ui->listWidget); QString item2Title ("Элемент 2"); QListWidgetItem *item2 = new QListWidgetItem; item2->setText(item2Title); item2->setIcon(QIcon(":/images/new.png")); item2->setToolTip("Всплывающая подсказка"); item2->setStatusTip("Сообщение в строку статуса"); item2->setWhatsThis("Подсказка \"Что это?\""); ui->listWidget->addItem(item2); }
Из примера видно, что элемент легко снабдить дополнительными "украшениями", такими как иконка-пиктограмма и три вида подсказок. Конечно, чтобы все подсказки работали, нужно, чтобы были доступны соответствующие элементы окна (строка статуса, кнопка "What’s This?").
Иконка загружается из ресурсов проекта (см. файл application.qrc и подключение ресурсов в ListWidget1.pro:
RESOURCES = application.qrc
По умолчанию элементы списка отсортированы в порядке их добавления. Легко отсортировать список и в алфавитном порядке (выполним по кнопке 2):
void Widget::on_pushButton_2_clicked() { static Qt::SortOrder order = Qt::AscendingOrder; ui->listWidget->sortItems(order); if (order == Qt::AscendingOrder) order = Qt::DescendingOrder; else order = Qt::AscendingOrder; }
По кнопке 3 посмотрим основные возможности получения элемента списка в виде строки QString:
void Widget::on_pushButton_3_clicked() { QListWidgetItem *item = ui->listWidget->currentItem(); //получить текущий if (!item) { QMessageBox::information(this,tr("Не могу получить currentItem"),"NULL"); } else { QMessageBox::information(this,tr("Получение currentItem"),item->text()); } QListWidgetItem *item2 = ui->listWidget->item(ui->listWidget->currentRow()); //получить по индексу if (!item2) { QMessageBox::information(this,tr("Не могу получить элемент по индексу"),"NULL"); } else { QMessageBox::information(this,tr("Получение по индексу"),item->text()); } }
По кнопке 4 сделаем выбранный текущий элемент редактируемым:
void Widget::on_pushButton_4_clicked() { QListWidgetItem *item = ui->listWidget->currentItem(); if (!item) { QMessageBox::information(this,tr("Ошибка"),tr("Не выбран элемент в списке")); return; } item->setFlags (item->flags () | Qt::ItemIsEditable); }
Теперь его можно открыть двойным кликом для изменения. Чтобы проверять и, при необходимости, отменять сделанные пользователем изменения, можно отслеживать их с помощью сигнала QListWidget::itemChanged. Правда, есть 2 проблемы:
- Любое другое изменение элемента в списке также вызовет этот сигнал, поэтому нужно заключить любой код, который изменяет элементы, в вызовы QObject::blockSignals, чтобы заблокировать нежелательные сигналы;
- Нет способа получить предыдущий текст, вы можете получить только новый текст. Решением является либо сохранение всех данных списка в переменную, их использование и обновление при изменении, либо сохранение текста отредактированного элемента перед его редактированием, как мы и сделали.
void Widget::on_listWidget_itemChanged(QListWidgetItem *item) { if (!item) return; QString text = item->text(); ui->listWidget->blockSignals(true); if (text.contains(QRegExp("^[\\w\\s]+$"))) item->setText(text); //Только алфафитно-цифровые или разделители else item->setText(this->previousText); ui->listWidget->blockSignals(false); } void Widget::on_listWidget_itemDoubleClicked(QListWidgetItem *item) { if (item) this->previousText = item->text(); }
Мы создали эти обработчики, нажав правой кнопкой мыши на списке и перейдя к соответствующим слотам, названия которых видны из названий функций.
Вообще же, если от виджета требуется нетипичное поведение, обычно целесообразней писать класс-потомок с нужными изменениями, чем пытаться перехватывать или модифицировать сигналы исходного виджета.
Кнопку 5 научим удалять элемент, это просто:
void Widget::on_pushButton_5_clicked() { QListWidgetItem *item = ui->listWidget->item(ui->listWidget->currentRow()); if (!item) { QMessageBox::information(this,tr("Ошибка"),tr("Не выбран элемент в списке")); return; } ui->listWidget->takeItem (ui->listWidget->currentRow()); }
А кнопка 6 очистит весь список:
void Widget::on_pushButton_6_clicked() { ui->listWidget->clear(); }
Кнопка 7 будет переключать между режимами выделения одного и нескольких элементов в списке, выделение нескольких элементов по умолчанию допускается при зажатой клавише Ctrl:
void Widget::on_pushButton_7_clicked() { static QAbstractItemView::SelectionMode mode = QAbstractItemView::SingleSelection; if (mode == QAbstractItemView::SingleSelection) mode = QAbstractItemView::MultiSelection; else mode = QAbstractItemView::SingleSelection; ui->listWidget->setSelectionMode(mode); }
Кнопка 8 покажет в отдельном окне диалога текст всех выбранных элементов, если таковые есть:
void Widget::on_pushButton_8_clicked() { QList <QListWidgetItem *> selected = ui->listWidget->selectedItems(); if (selected.size()==0) { QMessageBox::information(this,tr("Ошибка"),tr("Нет выбранных элементов")); return; } QString str(""); foreach(QListWidgetItem *item, selected) { str += item->text() + "\n"; } QMessageBox::information(this,tr("Выбранные элементы"),str); }
Кнопка 9 сохранит список в текстовый файл с именем data.txt (только текст элементов), а кнопка 10 загрузит данные из файла:
void Widget::on_pushButton_9_clicked() { QFile file("data.txt"); if (!file.open(QFile::WriteOnly | QIODevice::Text)) { QMessageBox::critical(this,tr("Ошибка"),tr("Не могу записать в data.txt")); return; } for (int row = 0; row < ui->listWidget->count(); row++) { QListWidgetItem *item = ui->listWidget->item(row); QTextStream out(&file); out << item->text() << "\n"; } file.close(); } void Widget::on_pushButton_10_clicked() { QFile file("data.txt"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::critical(this,tr("Ошибка"),tr("Не могу прочитать data.txt")); return; } QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); QListWidgetItem *item = new QListWidgetItem; item->setText(line); ui->listWidget->addItem(item); } file.close(); }
Слот 10 не очищает список перед загрузкой в него элементов из файла, при необходимости это легко исправить с помощью слота 6.
Нам остаётся дать кнопкам чуть более понятные надписи, дважды кликнув по каждой и вписав новый текст, а потом заархивировать проект.
Скачать этот проект QT 5.X в архиве .zip, папка уже создана внутри архива (5 Кб)
P.S. Замена QRegExp на QRegularExpression в Qt6.
06.04.2021, 13:10 [13377 просмотров]