QT: работаем со списком строк QStringList и стандартными контейнерами Tulip
В этой статье про стандартные контейнеры QT не упомянут самый удобный для начинающих контейнер - список строк QStringList
, потомок базового списка QList
.
Класс QStringList
удобен, прежде всего, потому, что имеет дополнительные методы для фильтрации данных и легко взаимодействует со стандартными компонентами QT, "понимающими" строки QString
.
Показанный в заметке проект
WidgetTemplate - своего рода шаблон приложения для обработки списка строк. Строки выгружаются из многострочного текстового поля QTextEdit
в QStringList
, а затем обрабатываются удобными методами QStringList
и QString
, после чего изменённый список загружается обратно. В моём случае обработка сводится к фильтрации строк списка (удаление пустых и состоящих только из разделителей строк, затем сжатие лишних разделителей между словами строк и удаление лишних пробелов в начале или конце строки.
Также пример показывает, как сделать верхнее меню в потомке QWidget
, просто прописать всё "ручками", готового в сети не нашёл. В норме QWidget
не имеет встроенного меню и не работает, например, "прямой" вызов menuBar()
из многочисленных книжных и сетевых примеров. В принципе,
проблема решается просто - достаточно сделать виджет наследником QApllication
, а не QWidget
.
Но можно и сделать меню не визуально, а логически, оставаясь наследником QWidget
.
Заслуживает внимания и "современный" способ центрирования окна виджета по декстопу с помощью метода setGeometry
. Для этого нам пришлось передать в конструктор виджета ссылку на экземпляр родительского приложения QApplication
.
Проект виджета создан на основе класса QWidget
без создания формы (так как весь интерфейс спроектирован логически в конструкторе).
Файл widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QtWidgets> class Widget : public QWidget { Q_OBJECT private: QVBoxLayout *layout; QTextEdit *textEdit; QMenuBar *menuBar; QMenu *fileMenu; QAction *newAction,*doAction,*exitAction; private slots: void newFile(void); void doFile(void); void exitFile(void); public: Widget(QApplication *a=0,QWidget *parent = 0); ~Widget(); }; #endif // WIDGET_H
Файл widget.cpp
#include "widget.h" Widget::Widget(QApplication *a,QWidget *parent) : QWidget(parent) { this->menuBar = new QMenuBar(this); this->fileMenu = new QMenu(tr("&Файл")); this->menuBar->addMenu(this->fileMenu); this->newAction = new QAction(tr("&Новый"),this->fileMenu); this->doAction = new QAction(tr("&Выполнить"),this->fileMenu); this->exitAction = new QAction(tr("В&ыход"),this->fileMenu); this->fileMenu->addActions( QList <QAction *> () << this->newAction << this->doAction << this->exitAction ); QObject::connect(this->newAction,SIGNAL(triggered()), this,SLOT(newFile())); QObject::connect(this->doAction,SIGNAL(triggered()), this,SLOT(doFile())); QObject::connect(this->exitAction,SIGNAL(triggered()), this,SLOT(exitFile())); this->textEdit = new QTextEdit(this); this->layout = new QVBoxLayout(this); this->layout->setMargin(5); this->layout->addWidget(this->textEdit); this->layout->setMenuBar(this->menuBar); this->setLayout(this->layout); this->setWindowTitle("Мой виджет"); this->setMinimumSize(320,240); this->resize(640,480); this->setGeometry(QStyle::alignedRect( Qt::LeftToRight,Qt::AlignCenter,this->size(), a->desktop()->availableGeometry())); } Widget::~Widget() { } void Widget::newFile(void) { this->textEdit->clear(); } void Widget::doFile(void) { QString String = this->textEdit->toPlainText(); QStringList list = String.split("\n"); //обработка QStringList QRegExp regExp("^(?!\\s*$).+"); list = list.filter(regExp); //убрали строки только из разделителей list.replaceInStrings(QRegularExpression("\\s+")," "); //убрали лишние разделители между словами list.replaceInStrings(QRegularExpression("^\\s+|\\s+$"),""); //убрали лишние разделители в начале или конце строк this->textEdit->clear(); this->textEdit->append(list.join("\n")); } void Widget::exitFile(void) { QApplication::quit(); }
Файл main.cpp
#include "widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w(&a); w.show(); return a.exec(); }
Скачать папку с этим проектом QT5 в архиве .zip (2 Кб)
Для демонстрации того, что работа с другими контейнерами может быть организована аналогично, изменим только наполнение метода doFile()
. В показанном ниже коде вводимые пользователем строки вида "ключ:значение", где "ключ" – целое число, а "значение" – строка, записываются в мультихэш (ассоциативный массив, в котором одному ключу может соответствовать несколько значений).
Полученный мультихэш выводится в консоль отладки. В реальной задаче после его формирования можно выполнять любые требуемые действия с данными, например, получить список всех значений, соответствующих ключу "0", мы можем так:
QList <QString> lst=hash.values(0);
Пример пользовательского ввода для формирования хэша:
1:345 1 2 3:44 1:567 1:789 string
И вывод в отладочной консоли QT для него:
Element: "1" Element: "1:345" Element: "1:567" Element: "1:789" Element: "2" Element: "3:44" Element: "string" Key= 0 Value= "1" Key= 1 Value= "2" Key= 1 Value= "789" Key= 1 Value= "567" Key= 1 Value= "345" Key= 2 Value= "string" Key= 3 Value= "44"
Вот изменённый метод doFile()
, также длинным комментарием пояснено первое регулярное выражение :)
void Widget::doFile(void) { QString String = this->textEdit->toPlainText(); QStringList list = String.split("\n"); list.removeDuplicates(); //Убрали дублирующие друг друга строки list.sort(Qt::CaseInsensitive);//Отсортировали с игнорированием регистра букв QRegExp regExp("^(?!\\s*$).+"); //^ (?! \\s * $) .+ //нач негативная разделитель ноль кон любой символ // проверка или более хотя бы один //Получается: //"если в строке есть хоть один символ - не надо разделителей слева от него" list = list.filter(regExp); //убрали строки только из разделителей list.replaceInStrings(QRegularExpression("\\s+")," "); //убрали лишние разделители между словами list.replaceInStrings(QRegularExpression("^\\s+|\\s+$"),""); //убрали лишние разделители в начале или конце строк //Пользовательская часть виджета QMultiHash <int,QString> hash; //Ключ - число, значения - строки QStringList::iterator it = list.begin(); int key=0; //Ключ для элементов, которым его не дал пользователь for (;it!=list.end();++it) { //Пройти по списку элементов "ключ:значение" QStringList item = (*it).split(":",QString::SkipEmptyParts); //разбить элемент по разделителю ":" if (item.size()<2) hash.insertMulti(key++,item.at(0)); else hash.insertMulti(item.at(0).toInt(),item.at(1)); //Добавили в хэш ключ (наш или заданный пользователем) и значение qDebug() << "Element: " << (*it); } //Вывести в консоль отладки мультихэш QMultiHash<int,QString>::iterator i = hash.begin(); for (;i!=hash.end();++i) qDebug() << "Key=" << i.key() << "Value=" << i.value(); //конец пользовательской части this->textEdit->clear(); this->textEdit->append(list.join("\n")); }
P.S. Замена QRegExp на QRegularExpression в Qt6.
24.03.2017, 15:27 [20412 просмотров]