Russian Qt Forum

Qt => Общие вопросы => Тема начата: Dragon от Май 13, 2010, 16:08



Название: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: Dragon от Май 13, 2010, 16:08
1. Начал изучать QT. Использую книгу М.Шлее (QT4.5. Профессиональное программирование на C++), Зоммерфельда и Бланшета, а также QT Assistant.
Опыт в С++ теоретический (недавно основы охватил по книге У.Савитч "Программирование на С++, 4 издание").

Читаю про элементы интерфейса, их создание (уже пообвыкся с указателями, немножечко начал понимать сигналы и слоты). Но чтобы что-то простое из прочитанного применить надо открывать книгу и не отрываясь от нее кодить. Конечно же вы ответите - "Все придет с практикой". Но практику эту нужно где-то взять. Хочется в этой сфере работать, но для этого надо знания. Посоветуйте, как подойти к вопросу изучения QT? Может есть какие-нить книги (англ?!) с заданиями или может присоветуете какой-нибудь подход в этом вопросе?

2. Вопрос по setFilterWildcard.
Есть две модели (model и proxyModel) и однострочное поле (роль фильтра).
В моделях выводится стринговый список. В поле вводим символы и в промежуточной модели (proxyModel) выводятся результаты в соответствии с регулярным выражением, которое обрабатывается слотом setFilterWildcard.
Как сделать, чтобы данные введенные в фильтр воспринимались setFilterWildcard как "XYZ*", а не "*XYZ*"?

Собственно код:
Код
C++ (Qt)
#include <QtGui>
 
int main(int argc, char** argv)
{
   QApplication app(argc, argv);
   QWidget wgt;
 
   QStringListModel model;
   model.setStringList(QStringList() << "Aurora" << "Permanent"
                                     << "Shock" << "Behind the wall"
                                     << "Material" << "Anesthesia");
 
   QSortFilterProxyModel proxyModel;
   proxyModel.setSourceModel(&model);
 
   QListView* pListView1 = new QListView;
   pListView1->setModel(&model);
 
   QListView* pListView2 = new QListView;
   pListView2->setModel(&proxyModel);
 
   QLabel* lbl = new QLabel("&Text:");
   QLineEdit* txt = new QLineEdit;
   lbl->setBuddy(txt);
 
   QObject::connect(txt, SIGNAL(textChanged(QString)),
                    &proxyModel, SLOT(setFilterWildcard(QString)));
 
   //Layout Setup
   QGridLayout* pgrdLayout = new QGridLayout;
   pgrdLayout->addWidget(pListView1, 0, 0);
   pgrdLayout->addWidget(pListView2, 0, 1);
   pgrdLayout->addWidget(lbl, 1, 0);
   pgrdLayout->addWidget(txt, 2, 0, 1, 2);
 
   wgt.setLayout(pgrdLayout);
   wgt.show();
 
   return app.exec();
}

Если я введу в поле "ne", то в proxyModel останутся записи Permanent и Anesthesia, вместо пустого списка.


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: crossly от Май 13, 2010, 16:21
я думаю лучше будет произвести обработку строки в отдельном слоте и использовать setFilterRegExp


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: Dragon от Май 13, 2010, 17:34
Хм, пока это мне кажется непосильной задачей. Случаем для этого отдельный класс разрабатывать не надо?


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: lit-uriy от Май 13, 2010, 21:29
>>Случаем для этого отдельный класс разрабатывать не надо?
а что там разрабатывать?
в myclass.h пишешь:
Код
C++ (Qt)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QtGui>
 
class MainWindow : pulic QWidget
{
   Q_OBJECT
public:
   // конструктор класса
   MainWindow(QWidget *parent = 0);
   // деструктор класса
   ~MainWindow();
 
public slots:
   // слот
   void mySlot(/*тут аргументы, как у сигнала, с которым будешь соединять*/);
};
#endif //MAINWINDOW_H

в myclass.cpp пишешь:
Код
C++ (Qt)
#include "myclass.h"
// конструктор класса
MainWindow::MainWindow(QWidget *parent = 0):QWidget(parent)
{
//Сюда перетаскиваешь большую часть кода из функции main
 
// соединяешь сигнал (для примера - someSignal(int value)) нужного объекта (для примера - object) со своим слотом:
   connect(object, SIGNAL(someSignal(int)),
               this, SLOT(mySlot()));
   // обрати внимание в функции connect для сигналов и слотов не пишут имена аргументов, а только их тип
}
// деструктор класса
MainWindow::~MainWindow()
{
//тут может быть пусто
}
// слот
void MainWindow::mySlot()
{
//тут код того, что должен делать этот слот
}
 
не забываешь добавить в pro-файл оба этих фала
Код
Bash
SOURSES += myclass.cpp
HEADERS += myclass.h


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: Dragon от Май 14, 2010, 10:00
Цитировать
а что там разрабатывать?
Концепция класса в Qt отличается от классов в C++ по ряду вещей (наличие слотов и сигналов в Qt, к примеру). Я пока только изучаю элементы управления, создание их программно. Все примеры, которые сопровождаются и где использованы классы, унаследованные от какого-либо класса Qt относительно сложны т.к. по сути реализация той или иной функции происходит методами Qt (если можно так сказать).

За наводку спасибо. Буду разбираться, экспериментировать, пытаться что-либо сделать.
Если что, буду дальше задавать вопросы :)


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: lit-uriy от Май 14, 2010, 10:34
>>Концепция класса в Qt отличается от классов в C++
да нет не отличается, просто халява добавлена вместо функций обратного вызова.
Слот - функция С++, с возможностью присоединения к нему сигналов. Всю химию о сигнально-слотовой связи берёт на себя MOC - метаобъектный компилятор.


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: Dragon от Май 14, 2010, 15:28
Запутался в слотах и сигналах и окончательно перестал что-либо понимать.

myregexp.h
Код
C++ (Qt)
#ifndef MYREGEXP_H
#define MYREGEXP_H
#include <QtGui>
 
class MyRegExp : public QWidget
{
public:
   MyRegExp(QWidget *parent = 0);
 
   ~MyRegExp();
 
public slots:
   void chkRegExp(QString);
};
 
#endif // MYREGEXP_H

myregexp.cpp
Код
C++ (Qt)
#include <QtGui>
#include "myregexp.h"
 
MyRegExp::MyRegExp(QWidget *parent)
{
   QStringListModel model;
   model.setStringList(QStringList() << "Aurora" << "Permanent"
                                     << "Shock" << "Behind the wall"
                                     << "Material" << "Anesthesia");
 
   QSortFilterProxyModel proxyModel;
   proxyModel.setSourceModel(&model);
 
   QListView* pListView1 = new QListView;
   pListView1->setModel(&model);
 
   QListView* pListView2 = new QListView;
   pListView2->setModel(&proxyModel);
 
   QLabel* lbl = new QLabel("&Text:");
   QLineEdit* txt = new QLineEdit;
   lbl->setBuddy(txt);
 
   connect(txt, SIGNAL(textChanged(QString)), this, SLOT(chkRegExp(QString)));
}
 
MyRegExp::~MyRegExp()
{
 
}
 
void MyRegExp::chkRegExp(QString)
{
}

В "void MyRegExp::chkRegExp(QString) {}" нужно писать, что будет делать слот. Т.е. проверка регулярного выражения. Но как я получу то, что уже есть в однострочном поле?

Была бредовая идея сделать что-нибудь вроде такого:
- получить строку из *txt
- ^ + содержимое *txt + "*" (для любого кол-ва символов после)
- отправить это все в proxyModel для вывода результатов по фильтру.



Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: crossly от Май 14, 2010, 15:41
для этого у тебя есть
Код:
connect(txt, SIGNAL(textChanged(QString)), this, SLOT(chkRegExp(QString)))
...
как только ты изменишь текст в поле ввода будет вызван слот chkRegExp в который будет передана твоя строка...
только нужно
Код:
chkRegExp(const QString &text/* <- это и будет текст который ты ввел */)


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: lit-uriy от Май 14, 2010, 16:55
>>void MyRegExp::chkRegExp(QString)
правило о том, что нельзя писать имя аргумента, относится только к функции connect. Т.е. свой слот пишешь так:
Код
C++ (Qt)
void MyRegExp::chkRegExp(QString value)
{
   QString var = value;
}
Ещё один полезный нюанс, функция sender() будучи вызванной в слоте вернёт указатель на QObject, который отправил сигнал в этот слот. Например, если с одним слотом соединены несколько виджетов, например кнопка (QPushButton) и поле ввода (QLineEdit), то можно для каждого определить свою обраьотку:
Код
C++ (Qt)
void MyRegExp::chkRegExp(QString value)
{
   QObject *o = sender();
   QLineEdit *le = qobject_cast<QLineEdit *>(o);
   // Если указатель не нулевой, то приведение типа удалось
   // это означает, что отправитель - объект типа QLineEdit
   if(le){
       // обработка для поля ввода
       QString var = value;
   }else{
      // обработка для остальных отправителей
   }
}


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: Dragon от Май 15, 2010, 16:27
Решил проверить работу собственного слота (так сказать, разобраться в работе слотов и сигналов на практике через пробы и ошибки).

Пока он выглядит так (может это и бред, но прошу камнями не брсоаться, суть вопроса не в допустимости создания такого регулярного выражения):
Код
C++ (Qt)
void MyRegExp::chkRegExp(QString text)
{
   QRegExp rx("^" + text + "*");
}

Проверять буду дебаггером.
Но тут возник глупый вопрос. Т.к. весь код (списки, Proxy Model, однострочное поле для ввода, подпись (Label), ) находится в конструкторе класса. То в main.cpp остается только создать объект класса и отобразить его. Но что в таком случае нужно передать в конструктор класса чтобы все, что было записано в конструкторе, отобразилось?

При обычном:
Код
C++ (Qt)
MyRegExp reg;
reg.show();
Запускается просто пустое окно (Layout добавил в конструктор).


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: lit-uriy от Май 15, 2010, 20:18
>>Layout добавил в конструктор
А остальные виджеты в компоновщик добавил или они где-то в воздухе остались висеть?


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: Dragon от Май 15, 2010, 20:46
Вот так выглядит полностью конструктор:
Код
C++ (Qt)
MyRegExp::MyRegExp(QWidget *parent):QWidget(parent)
{
   QWidget wgt;
 
   QStringListModel model;
   model.setStringList(QStringList() << "Aurora" << "Permanent"
                                     << "Shock" << "Behind the wall"
                                     << "Material" << "Anesthesia");
 
   QSortFilterProxyModel proxyModel;
   proxyModel.setSourceModel(&model);
 
   QListView* pListView1 = new QListView;
   pListView1->setModel(&model);
 
   QListView* pListView2 = new QListView;
   pListView2->setModel(&proxyModel);
 
   QLabel* lbl = new QLabel("&Text:");
   QLineEdit* txt = new QLineEdit;
   lbl->setBuddy(txt);
 
   //chkRegExp SLOT
   connect(txt, SIGNAL(textChanged(QString)), this, SLOT(chkRegExp(QString)));
 
   //Layout setup
   QGridLayout* pgrdLayout = new QGridLayout;
   pgrdLayout->addWidget(pListView1, 0, 0);
   pgrdLayout->addWidget(pListView2, 0, 1);
   pgrdLayout->addWidget(lbl, 1, 0);
   pgrdLayout->addWidget(txt, 2, 0, 1, 2);
 
   wgt.setLayout(pgrdLayout);
}


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: lit-uriy от Май 15, 2010, 21:55
:) Си++!

QWidget wgt; - это было в main'е, а тепрь твой класс им и является.
Собственно, когда конструктор закончит работу, то это объект будет разрушен (вышли из функции, в которой он объявлен) и его дочерние виджеты тоже.

Просто удали эту строку, т.к. вместо него ты и создавал класс MyRegExp.
а последнюю строку замени на
this->setLayout(pgrdLayout);
или просто
setLayout(pgrdLayout);


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: Dragon от Май 15, 2010, 22:09
Ага. Понял теперь где собака зарыта. Спасибо :)

Т.е. в классе, в частности в конструкторе, лучше создавать объекты, выделяя динамическую память?
По крайней мере пришлось таким образом обойтись с моделями данных (чтобы данные списка отображали):
Код
C++ (Qt)
QStringListModel* model = new QStringListModel;
QSortFilterProxyModel* proxyModel = new QSortFilterProxyModel;

P.S> А Qt мне нравится все больше и больше - дружелюбная она что-ли :)


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: lit-uriy от Май 15, 2010, 22:19
>>Т.е. в классе, в частности в конструкторе, лучше создавать объекты, выделяя динамическую память?
НЕТ.
объекты нужно создавать так, как этого требует логика программы. Если объект нужен только в конструкторе, то создавать на стеке (обычная переменная). Если объект будет нужен и по окончании работы функции/конструктора, то динамически. А если к объекту нужно будет неоднократно обращаться из функций класса, то его нужно создавать динамически и указатель на него объявить членом класса (т.е. в описании, а не в конструкторе) иначе за пределами функции/конструктора сам указатель будет разрушен (и невиден компилятору).

Так, например, если тебе понадобится обращаться к модели  в других функциях класса, то указатель на неё нужно объявлять не в конструкторе, а в описании класса.


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: Dragon от Май 16, 2010, 21:09
Приношу извинения, что так дотошно интересуюсь, но до конца еще понять не могу.

Если система слотов это аналог функций С++, то код:
Код
C++ (Qt)
QRegExp rx(text);
имеет право на жизнь. По идее rx равен text. Но дебаггер (qDebug() << "Rx: " << rx;) у меня показывает:
Цитировать
Rx:  QVariant(QRegExp, )

И сразу в догонку вопрос, как из моего слота передать данные в proxyModel, как это было тут:
Код
C++ (Qt)
QObject::connect(txt, SIGNAL(textChanged(QString)),&proxyModel, SLOT(setFilterWildcard(QString)));

Или где посмотреть реализацию слота "setFilterWildcard(QString)", не могу понять как он преобразовывает строку в регулярное выражение и далее применяет его в качестве фильтра к списку стрингов :(


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: lit-uriy от Май 16, 2010, 21:27
опять всё от туда (С++), смотри свой конструктор и мой ответ №12, сколько времени живёт твоя модель посредник, доживёт ли она, до момента, когда текст в поле ввода изменится?


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: Dragon от Май 17, 2010, 15:17
Я понял суть проблемы с дебагером. Для вывода в дебаггер нужно выводить паттерн (а не то что я пытался вывести):
Код
C++ (Qt)
qDebug() << rx.pattern();

Переработал немного класс и он выглядит так:
myregexp.h
Код
C++ (Qt)
#ifndef MYREGEXP_H
#define MYREGEXP_H
#include <QtGui>
 
class MyRegExp : public QWidget
{
   Q_OBJECT
public:
   //Конструктор по-умолчанию
   MyRegExp(QWidget *parent = 0);
 
   //Деструктор
   ~MyRegExp();
 
public slots:
   //Слот для проверки регулярного выражения
   void chkRegExp(QString text);
 
private:
   //18.05.10
   QSortFilterProxyModel proxyModel; //Промежуточная модель
   QStringList data; //Список данных
};
 
#endif // MYREGEXP_H

myregexp.cpp
Код
C++ (Qt)
#include <QtGui>
#include "myregexp.h"
 
MyRegExp::MyRegExp(QWidget *parent):QWidget(parent)
{
   QStringListModel* model = new QStringListModel;
   data << "Aurora" << "Permanent" << "Shock" << "Behind the wall"
        << "Material" << "Anesthesia";
   model->setStringList(data);
 
   proxyModel.setSourceModel(model);
 
   QListView* pListView1 = new QListView;
   pListView1->setModel(model);
 
   QListView* pListView2 = new QListView;
   pListView2->setModel(&proxyModel);
 
   QLabel* lbl = new QLabel("&Text:");
   QLineEdit* txt = new QLineEdit;
   lbl->setBuddy(txt);
 
   //chkRegExp SLOT
   connect(txt, SIGNAL(textChanged(QString)), this, SLOT(chkRegExp(QString)));
 
   //Layout setup
   QGridLayout* pgrdLayout = new QGridLayout;
   pgrdLayout->addWidget(pListView1, 0, 0);
   pgrdLayout->addWidget(pListView2, 0, 1);
   pgrdLayout->addWidget(lbl, 1, 0);
   pgrdLayout->addWidget(txt, 2, 0, 1, 2);
 
   this->setLayout(pgrdLayout);
}
 
MyRegExp::~MyRegExp()
{
 
}
 
void MyRegExp::chkRegExp(QString text)
{
   QRegExp rx(text + "*");
   rx.setPatternSyntax(QRegExp::Wildcard);
 
   //Сверка списка с регулярным выражением
   QStringList::const_iterator constIterator;
   for(constIterator = data.constBegin(); constIterator != data.constEnd(); ++constIterator)
   {
       QString temp = *constIterator; //Очередная строка из списка
       if(rx.exactMatch(temp))
       {//Вывести в proxyModel
           //Суть вопроса//
       }
   }
}

Как из слота теперь выводить результат в proxyModel  ???


Название: Re: Как лучше подойти к вопросу изучения QT? А также вопрос по setFilterWildcard.
Отправлено: Dragon от Май 18, 2010, 17:02
Вобщем все оказалось в разы проще, чем я это намалевал. Содержимое слота:
Код
C++ (Qt)
proxyModel.setFilterRegExp("^" + text);

Да с Qt нужно искать простые пути решения вопроса, а не придумывать себе задачи и этим самым нагромождать код, что к лучшей работе не приведет точно.

P.S> Хотя хотелось бы реализовать вывод в proxyModel и сложным путем, коим я шел изначально.