Название: Не получается разобраться в механизме потоков
Отправлено: nata267 от Июля 19, 2011, 10:35
Я - никогда не использовала раньше потоки . Но у меня такая задача. Я написала свой класс потока, в нем должна выполняться единственная операция по выборке данных для модели QSqlQueryModel, так как данных много то выборка тормозиться, соответственно я решила вынести в отдельный поток. Получилась полная чушь. Что я делаю не так?? Данные выбираются криво, в конце куча пустых строк, и столбцы которые я скрываю показываются. .h class ContentRefresher : public QThread { Q_OBJECT public: ContentRefresher(QTableView *contentView); ~ContentRefresher(); void refreshContent();
signals: void contentRefreshed();
private: void run();
volatile bool m_abort; QTableView *m_contentView; QMutex m_mutex; };
.cpp ContentRefresher::ContentRefresher(QTableView *contentView) { m_abort = false; m_contentView = contentView; }
ContentRefresher::~ContentRefresher() { if(!isRunning()) return;
m_mutex.lock(); m_abort = true; m_mutex.unlock(); wait(); }
void ContentRefresher::refreshContent() { start(); }
void ContentRefresher::run() {
ContentModel *model = qobject_cast<ContentModel *>(m_contentView->model()); model->refresh();
m_contentView->setColumnHidden(0,true); m_contentView->setColumnHidden(2,true); m_contentView->resizeColumnsToContents(); m_contentView->resizeRowsToContents(); m_contentView->horizontalHeader()->setStretchLastSection(true);
emit contentRefreshed(); }
использую его так: CentralWidget::CentralWidget(QWidget *parent) : contentRefresher(0),........ { ..... contentModel = new ContentModel(this); m_ui.contentView->setModel(contentModel); m_ui.contentView->setSelectionBehavior(QAbstractItemView::SelectRows); m_ui.contentView->setSelectionMode(QAbstractItemView::SingleSelection); m_ui.contentView->verticalHeader()->hide(); m_ui.contentView->setItemDelegate(new ContentDelegate(m_ui.contentView)); m_ui.contentView->installEventFilter(this);
............. QTimer::singleShot(0, this, SLOT(refreshContentModel())); }
CentralWidget::~CentralWidget() { ....... delete contentRefresher; }
void CentralWidget::refreshContentModel() { contentRefresher = new ContentRefresher(m_ui.contentView); connect(contentRefresher, SIGNAL(contentRefreshed()), this, SLOT(contentRefreshed()));
m_ui.progressWidget->setVisible(true); contentRefresher->refreshContent(); }
void CentralWidget::contentRefreshed() { m_ui.progressWidget->setVisible(false); }
Название: Re: Не получается разобраться в механизме потоков
Отправлено: nata267 от Июля 19, 2011, 10:41
Кроме того функция refreshContentModel(), будет вызываться неоднократно из программы, каждый раз когда пользователь будет нажимать кнопку Поиск, соответственно будет создаваться новый поток. Наверно это тоже неправильно??
Название: Re: Не получается разобраться в механизме потоков
Отправлено: GreatSnake от Июля 19, 2011, 11:27
Для начала не мешало бы усвоить правило - всё что связано с gui должно работать в основном потоке.
Название: Re: Не получается разобраться в механизме потоков
Отправлено: nata267 от Июля 19, 2011, 12:34
Для начала не мешало бы усвоить правило - всё что связано с gui должно работать в основном потоке.
я переписала, но проблемы остались, почему-то ProgressBar зависает как рас во время работы потока, и программа через раз вылетает, и опять же куча пустых строчек вконце добавляется: ContentRefresher::ContentRefresher(ContentModel *contentModel) { m_abort = false; m_contentModel = contentModel; }
ContentRefresher::~ContentRefresher() { if(!isRunning()) return;
m_mutex.lock(); m_abort = true; m_mutex.unlock(); wait(); }
void ContentRefresher::refreshContent() { start(); }
void ContentRefresher::run() { while(!m_abort) { m_contentModel->refresh(); emit contentRefreshed(); } m_mutex.lock(); m_abort = false; m_mutex.unlock(); }
void ContentRefresher::stop() { m_mutex.lock(); m_abort = true; m_mutex.unlock(); } [codе]
вот его использование:
[code] void CentralWidget::refreshContentModel() { contentRefresher = new ContentRefresher(contentModel); connect(contentRefresher, SIGNAL(contentRefreshed()), this, SLOT(contentRefreshed()), Qt::QueuedConnection);
m_ui.progressWidget->setVisible(true); m_ui.contentView->setVisible(false); contentRefresher->refreshContent(); }
void CentralWidget::contentRefreshed() { contentRefresher->stop();
m_ui.contentView->setModel(contentModel); m_ui.contentView->setColumnHidden(0,true); m_ui.contentView->setColumnHidden(2,true); m_ui.contentView->resizeColumnsToContents(); m_ui.contentView->resizeRowsToContents(); m_ui.contentView->horizontalHeader()->setStretchLastSection(true); m_ui.contentView->setVisible(true); m_ui.progressWidget->setVisible(false); }
[/code]
Название: Re: Не получается разобраться в механизме потоков
Отправлено: Странник от Июля 19, 2011, 14:05
соединение с БД может использоваться только из того потока, в котором было создано. создавайте соединение в run() потока, потом устанавливайте модели запрос через void QSqlQueryModel::setQuery ( const QString & query, const QSqlDatabase & db = QSqlDatabase() ), где вторым параметром передается созданное соединение.
Название: Re: Не получается разобраться в механизме потоков
Отправлено: nata267 от Июля 21, 2011, 13:43
щас поменяла. Модель создается и выборка производится в другом потоке, а потом через сигнал/слот передается в главный поток, но все равно интерфейс пользователя на время выборки зависает, не пойму почему, вот класс потока: class ContentRefresher : public QThread { Q_OBJECT public: ContentRefresher(QObject *parent = 0); ~ContentRefresher();
void processQuery(const QString &qStr, const QString &hStr);
signals: void sendContent(ContentModel *contentModel);
public slots: void stopProcess();
protected: void run();
private: QString m_queryString; QString m_headerString; bool m_abort; ContentModel *m_contentModel; QMutex mutex; };
ContentRefresher::ContentRefresher(QObject *parent) : QThread(parent) { m_abort = false; }
ContentRefresher::~ContentRefresher() { mutex.lock(); m_abort = true; mutex.unlock();
wait(); }
void ContentRefresher::processQuery(const QString &qStr, const QString &hStr) { m_queryString = qStr; m_headerString = hStr; m_abort = false; start(); }
void ContentRefresher::run() { ContentModel *contentModel = new ContentModel(); contentModel->setQueryString(m_queryString, m_headerString); contentModel->refresh(); emit sendContent(contentModel); if (m_abort) return; }
void ContentRefresher::stopProcess() { mutex.lock(); m_abort = true; mutex.unlock(); }
вот его использование из главного потока: .... contentRefresher = new ContentRefresher(); connect(contentRefresher, SIGNAL(finished()), this, SLOT(resetUi())); connect(contentRefresher, SIGNAL(sendContent(ContentModel *)), this, SLOT(setContent(ContentModel *))); ....
void CentralWidget::refreshContentModel(const QString &qStr, const QString &hStr) { m_ui.progressWidget->setVisible(true); contentRefresher->processQuery(qStr, hStr); }
void CentralWidget::setContent(ContentModel *contentModel) { m_ui.contentView->setModel(contentModel); m_ui.contentView->setColumnHidden(0,true); m_ui.contentView->setColumnHidden(2,true); m_ui.contentView->resizeColumnsToContents(); m_ui.contentView->resizeRowsToContents(); m_ui.contentView->horizontalHeader()->setStretchLastSection(true); m_ui.contentView->setVisible(true); loadFirstRecipe(); }
void CentralWidget::resetUi() { m_ui.progressWidget->setVisible(false); }
Название: Re: Не получается разобраться в механизме потоков
Отправлено: nata267 от Июля 21, 2011, 14:04
может нельзя выбирать данные функцией setQuery, а разбить на шаги и добавлять каждую строчку??
Название: Re: Не получается разобраться в механизме потоков
Отправлено: nata267 от Июля 21, 2011, 14:34
или может быть изза того что приложение запускается в Windows Mobile, там потоки работают, никто не в курсе??
Название: Re: Не получается разобраться в механизме потоков
Отправлено: danquimby от Июля 21, 2011, 15:30
нет девушка , вы как то странно подходите к "велосипеду" не с той стороны. И вообще в потоке virtual run должен быть зациклен который будет ждать данных на обработку или который будет забирать в отдельном потоке эти данные. Так же прочитайте про QWaitCondition тоже может помочь А так вы вообще не так делаете . Посмотрите в примерах от qtsdk И еще потоки это очень пухленькая нагрузка на программу . если что то хотите инициализировать то void run(){ CreateWidgets(); forever(){ // что то делаете } exec(); }
Название: Re: Не получается разобраться в механизме потоков
Отправлено: nata267 от Июля 22, 2011, 14:29
опять я все переписала, вот: класс потока: class ContentRefresher : public QThread { Q_OBJECT public: ContentRefresher(QObject *parent = 0); ~ContentRefresher();
void processQuery(const QString &qStr, const QString &hStr);
signals: void sendRecord(const ContentRecord &record);
public slots: void stopProcess();
protected: void run();
private: bool m_abort; QMutex mutex;
QString m_queryString; QString m_headerString; };
ContentRefresher::ContentRefresher(QObject *parent) : QThread(parent) { m_abort = false; }
ContentRefresher::~ContentRefresher() { mutex.lock(); m_abort = true; mutex.unlock(); wait(); }
void ContentRefresher::processQuery(const QString &qStr, const QString &hStr) { m_queryString = qStr; m_headerString = hStr; m_abort = false; start(); }
void ContentRefresher::run() { QSqlQuery query(m_queryString); while(query.next()) { ContentRecord record(query.record()); emit sendRecord(record); if (m_abort) return; msleep(10); } }
void ContentRefresher::stopProcess() { mutex.lock(); m_abort = true; mutex.unlock(); }
вот использование из главного потока: ... contentRefresher = new ContentRefresher(); connect(contentRefresher, SIGNAL(finished()), this, SLOT(resetUi())); connect(contentRefresher, SIGNAL(sendRecord(ContentRecord)), this, SLOT(addRecord(ContentRecord))); ...
void CentralWidget::refreshContentModel(const QString &qStr, const QString &hStr) { // m_ui.progressWidget->setVisible(true); contentModel->clear(); contentRefresher->processQuery(qStr, hStr); }
void CentralWidget::addRecord(const ContentRecord &record) { contentModel->addContentRecord(record.record()); qApp->processEvents(); }
void CentralWidget::resetUi() { //m_ui.progressWidget->setVisible(false); m_ui.contentView->resizeRowsToContents(); loadFirstRecipe(); }
проблема в том, что m_ui.contentView->resizeRowsToContents(); нужно вызывать после окончания выполнения процесса, если выполнять в функции addRecord, т.е. после вставки каждой строки, то программа зависнет. и таким образом сначала строчки добавляются неправильной высоты, то есть кривые, и толко по завершении выборки они становятся такими какие должны быть. но это уже вопрос наверно не в теме потоков, а в теме модель-отображение и интерфейс все равно немного подвисает, смысл тогда этого потока в чем?? можно выбирать в основном потоке и в цикле делать qApp->processEvents(); не могу я понять смысл этих потоков((((((((((((
Название: Re: Не получается разобраться в механизме потоков
Отправлено: danquimby от Июля 22, 2011, 14:40
девушка вы снова что то ... написали если честно не хотца смотреть ((( 1.run это цикл а я как видел , при завершении вы выходите из цыкла , то бишь треда закрывается (нуна правда проверить)
смотрите как я делал . в треде вам нужно делать выборку по базе и выложить куда нить результат поиска и всяких там преобразований. А в главном потоке сделайте так. 1.дайте данные , и возбудите поток thread.start(); 2.а в главном потоке ну не знаю, повесьте qtimer который будет смотреть данные, которая треда положил по завершению. Пока их нет(после нажатии кнопки Search делайте что бы клиент мог нажать тока Cancel) Ну так вот как данные появятся их и показать. В поток не нужно пихать ... какие то странные вещи, дайте ему заниматься своими делами, то есть трудоемкими и времязатратными. И при этом у вас главный поток (GUI) будет в работе (ну кроме таймер будет смотреть данные) а треда будет заниматься своим делом.
ps сумбурно но надеюсь ... хоть что то дошло(не учитель))) )
|