QT: список с автосохранением
В блоге уже есть несколько заметок о списках в QT, очередной учебный список будет отличаться тем, что данные подгружаются из текстового файла при создании окна приложения и записываются обратно в файл перед закрытием виджета.
Запустив QT Creator, создадим проект на основе шаблона QWidget
и сделаем форму во встроенном дизайнере, действуя, как в этой заметке, только на шаге 7 перетащим на форму компонент QListWidget
, справа от него поместим QLabel
и нажмём на шаге 8 комбинацию клавиш Ctrl+H
(скомпоновать по горизонтали) вместо Ctrl+L
.
В правую ячейку получившейся сетки под текстовой меткой последовательно поместим однострочное поле ввода QLineEdit
, пять кнопок QPushButton
и Vertical Spacer, который "прижмёт" компоненты к верхнему краю ячейки, получится вот такая форма:

форма приложения
Отдельная кнопка редактирования нам не понадобится, так как мы всегда можем скопировать элемент в поле ввода кликом по нему, затем удалить, исправить текст в поле ввода и заново добавить кнопкой Add.
Имеющийся в widget.cpp
конструктор виджета изменим так, чтобы включить в него действия, нужные для загрузки элементов списка из текстового файла data.txt
, находящегося в текущей папке приложения. Если файл не существует, создадим 2 элемента "вручную", просто для демонстрации того, как это делается.
Элемент 1 добавляется как строка, а элемент 2 - как объект класса QListWidgetItem
(закомментировано в листинге).
Вот что вышло:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); ui->lineEdit->setFocus(); //Автозагрузка списка при запуске виджета QFile file("data.txt"); if (file.open(QIODevice::ReadOnly)) { QTextStream stream(&file); while (!stream.atEnd()) { QString s = stream.readLine(); ui->listWidget->addItem(s.trimmed()); } file.close(); } else { //Как добавить элемент-строку: ui->listWidget->addItem(QString(tr("Элемент 1"))); //Как добавить элемент QListWidgetItem: /* QListWidgetItem *item = new QListWidgetItem(); item->setText(QString(tr("Элемент 2"))); item->setToolTip(QString(tr("Подсказка"))); ui->listWidget->addItem(item); */ } }
По щелчку на элементе списка будем получать его текущий элемент в виде строки QString
и дублировать его в поле ввода QLineEdit
.
Чтобы получить пустую подпрограмму-"заготовку" достаточно в режиме дизайна формы щёлкнуть правой кнопкой мыши на списке и перейти к слоту clicked
.
Для кнопок будем выбирать аналогичный слот (см. шаги 10-11 здесь).
void Widget::on_listWidget_clicked(const QModelIndex &index){ this->unselectAll(); ui->listWidget->setSelectionMode(QAbstractItemView::SingleSelection); ui->lineEdit->setText( //Получить текущий элемент как строку ui->listWidget->currentItem()->text()); }
Служебный метод unselectAll
будет снимать выделение со всего, что было выделено в списке, вот его код, конечно, нужно не забыть указать прототип метода в файле widget.h
, как и прописать там нужные заголовочные файлы (см. код этого файла в конце заметки).
void Widget::unselectAll () { //Снять выделение со всего, что было выделено: QList <QListWidgetItem *> items = ui->listWidget->selectedItems(); foreach (QListWidgetItem *item,items) item->setSelected(false); }
Все коды обработки нажатий кнопок приведены ниже, они показывают, как работать с Item-based списком, не заботясь о модели, и выполнять основные действия по добавлению уникального элемента, удалению выбранного элемента, поиску в списке по неполному соответствию строки (найденные элементы выделяются), сортировке списка в прямом и обратном порядке, а также полной очистке списка с подтверждением действия.
void Widget::on_pushButton_clicked() { //Добавить QString text = ui->lineEdit->text().trimmed().simplified(); //Почистить строку от лишних разделителей if (text.isEmpty()) return; QList <QListWidgetItem *> list0 = //Поискать элемент ui->listWidget->findItems(text,Qt::MatchContains|Qt::MatchFixedString); if (list0.count()) { //Уже есть такой - заменить элемент QListWidgetItem *item=list0.at(0); int index = ui->listWidget->row(item); ui->listWidget->setCurrentRow(index); on_pushButton_2_clicked(); //Удалить старый ui->listWidget->insertItem(index,text); //Вставить новый } else { //Или добавить новый ui->listWidget->addItem(text); } ui->lineEdit->setText(""); ui->lineEdit->setFocus(); } void Widget::on_pushButton_2_clicked() { //Удалить int row = ui->listWidget->currentRow(); if (row<0) { QMessageBox msgBox; msgBox.setText(QString(tr("Удаление элемента"))); msgBox.setInformativeText(QString(tr("Выберите элемент для удаления"))); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.exec(); return; } QListWidgetItem *item = ui->listWidget->takeItem(row); ui->lineEdit->setText(item->text()); //Скопировать текст удалённого ui->listWidget->setCurrentRow(row); } void Widget::on_pushButton_3_clicked() { //Поиск //Разрешить выделять несколько элементов: ui->listWidget->setSelectionMode(QAbstractItemView::MultiSelection); this->unselectAll(); //Поискать text в списке: QString text = ui->lineEdit->text().trimmed().simplified(); if (text.isEmpty()) return; QList <QListWidgetItem *> selected = ui->listWidget->findItems (text, Qt::MatchContains|Qt::MatchFixedString); if (selected.count()) { //Найдено foreach (QListWidgetItem *item,selected) item->setSelected(true); //Выделить найденное ui->listWidget->scrollToItem(selected[0],QAbstractItemView::PositionAtTop); //Скроллить к найденному } else { //Не найдено QMessageBox msgBox; msgBox.setText(QString(tr("Ничего не найдено"))); msgBox.exec(); } } void Widget::on_pushButton_4_clicked() { //Сортировка //ui->listWidget->setSortingEnabled(true); static Qt::SortOrder Order = Qt::DescendingOrder; if (Order==Qt::AscendingOrder) { Order = Qt::DescendingOrder; ui->listWidget->sortItems(Order); ui->pushButton_4->setText(QString(tr("Sort(v)"))); } else { Order = Qt::AscendingOrder; ui->listWidget->sortItems(Order); ui->pushButton_4->setText(QString(tr("Sort(^)"))); } } void Widget::on_pushButton_5_clicked() { //Очистить QMessageBox msgBox; msgBox.setText(QString(tr("Очистка списка"))); msgBox.setInformativeText(QString(tr("Вы уверены?"))); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::Yes); if (msgBox.exec()==QMessageBox::Yes) ui->listWidget->clear(); }
Осталось предусмотреть в виджете обработчик события "закрытие окна" и вписать туда код для сохранения элементов списка в файле.
void Widget::closeEvent(QCloseEvent *event) { //Автосохранение списка при выходе - событие closeEvent int size=ui->listWidget->count(); if (size) { QFile file("data.txt"); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); for (int i=0; i<size; i++) { stream << ui->listWidget->item(i)->text().trimmed().simplified() << (i<size-1 ? "\r\n" : ""); } stream.flush(); file.close(); } } }
Этот метод также прописывается в файле widget.h
, со всеми предыдущими изменениями он получается таким:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> /* необходимые библиотеки */ #include <QtWidgets> #include <QEvent> #include <QTextStream> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private slots: void on_listWidget_clicked(const QModelIndex &index); void on_pushButton_clicked(); void on_pushButton_2_clicked(); void on_pushButton_3_clicked(); void on_pushButton_4_clicked(); void on_pushButton_5_clicked(); void closeEvent(QCloseEvent *); /* обработчик закрытия окна */ private: Ui::Widget *ui; void unselectAll (); /* метод для снятия выделения с элементов */ }; #endif // WIDGET_H
Приложение можно собирать и запускать, проверено в QT 5.X.
Скачать этот проект Qt6 в архиве .zip, развернуть в новую папку (4 Кб)
12.04.2018, 09:36 [4091 просмотр]