Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > [qt4.5] QThread & QSqlQueryModel


Автор: zloyGamer 3.5.2009, 22:46
над чтобы долгий процесс загрузки данных с БД выполнялся независимо от главного потока(чтоб приложение не подвисало), и время от времени выводилось сообщение о выполнении процесса..

щас решил сделать 2 потока: 
один будет посылать главному приложению сообщения о процессе выполнения а второй будет выполнять запросы к бд,
как только 2й поток закончит выполнение то оба потока завершают свою работу..

и вроде все честно сделал но проблема в том что работает оно нестабильно - всмысле при выполнении одних и тех-же запросов - результат выводится неполностью или выдаются ещё пустые строки и количество QSqlQueryModel::rowCount() выдается разное..

итак:
поток который сообщает о процессе выплнения главному приложению
Код

class MyThread : public QThread
{
    Q_OBJECT
  public:

    MyThread_exec   *m_MyThread_exec;  //поток который выполняет запрос

    QLineEdit       *m_QLineEdit_exec;  // куда выводим время вып-я
    QLineEdit       *m_QLineEdit_rows;  // кол-во стрк

    QTableView      *m_QTableView; 
    QString         m_sql;

    QTime           time;

  public:
    MyThread();
    ~MyThread();

    void set_sql (QTableView *p_QTableView,
                  QLineEdit *p_exec,
                  QLineEdit *p_QLineEdit_rows,
                  const QString &p_sql);

    void run();

  public slots:
    void  stopThread();

  signals:
    void set_time_text(const QString &p_txt);
    void set_rows_text(const QString &p_txt);

};
.....
///////////////////////////////////////////////////////////////////////////////////////////////////
MyThread::MyThread()
    :m_QTableView(0),
     m_MyThread_exec(new MyThread_exec(this)),
     m_QLineEdit_exec(0)
{
    qDebug() << "MyThread::MyThread() begin "<< QString::number( (int)this,16 );

    QObject::connect( m_MyThread_exec, SIGNAL(   finished ()) , this , SLOT(  stopThread()) );
    QObject::connect( m_MyThread_exec, SIGNAL(  terminated()) , this , SLOT(  stopThread()) );
    QObject::connect(            this, SIGNAL(  terminated()) , m_MyThread_exec , SLOT(  terminate()) );

}
///////////////////////////////////////////////////////////////////////////////////////////////////
MyThread::~MyThread()
{
  m_MyThread_exec->terminate();
  delete m_MyThread_exec;
  terminate();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void MyThread::set_sql (QTableView *p_QTableView,
                        QLineEdit *p_exec,
                        QLineEdit *p_QLineEdit_rows,
                        const QString &p_sql)
{
    m_QTableView=0;
    m_QLineEdit_exec=p_exec;
    m_QLineEdit_rows=p_QLineEdit_rows;
    m_sql=p_sql;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void MyThread::stopThread()
{
  m_MyThread_exec->terminate ();
  terminate ();

  emit set_time_text( QString("%1").arg( ((double)time.elapsed())/1000,10,'f',2 ) );  //  выводим время вып-я
  emit set_rows_text( QString::number( m_MyThread_exec->m_model->rowCount() ) ); // кол-во строк

}
///////////////////////////////////////////////////////////////////////////////////////////////////
void MyThread::run()
{
  QObject::   connect( this, SIGNAL( set_rows_text(const QString &) ) , m_QLineEdit_rows , SLOT(  setText(const QString &) ) );
  QObject::   connect( this, SIGNAL( set_time_text(const QString &) ) , m_QLineEdit_exec , SLOT(  setText(const QString &) ) );
  m_MyThread_exec->start();
  time.start();
  while(1)
  {
    emit set_time_text( QString("%1").arg( ((double)time.elapsed())/1000,10,'f',2 ) );  //  выводим время вып-я
    emit set_rows_text( QString::number( m_MyThread_exec->m_model->rowCount() ) ); // кол-во строк
    msleep(50);

  }
  quit();
}
///////////////////////////////////////////////////////////////////////////////////////////////////



поток который выполняет запрос
Код

class MyThread_exec : public QThread
{
  public:

    QSqlDatabase      m_db;  //для этого потока создаем отдельное подключение к бд
    QSqlQueryModel   *m_model;


    MyThread         *m_MyThread;

    //MyThread_exec(QSqlQueryModel *p_model,MyThread *p_MyThread);

    MyThread_exec(MyThread *p_MyThread);
    ~MyThread_exec();
    void run();


};
...
///////////////////////////////////////////////////////////////////////////////////////////////////
MyThread_exec::MyThread_exec(MyThread *p_MyThread)
    :m_db(),
     m_model(new QSqlQueryModel() ),
     m_MyThread(p_MyThread)
{
    m_db = QSqlDatabase::addDatabase( tr("QODBC"),"connect_name__test_" );
}
///////////////////////////////////////////////////////////////////////////////////////////////////
MyThread_exec::~MyThread_exec()
{
    terminate();
    m_model->clear();
    delete m_model;
    m_db.close();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void MyThread_exec::run()
{

  m_db.close();
  m_db.setDatabaseName( "test_dbf" );

  if(!m_db.open())
  {
      QMessageBox::information(0, QString("err"),m_db.lastError().text());
      return ;
  }

  m_model->setQuery( m_MyThread->m_sql , m_db);  

  while (m_model->canFetchMore())
  {
    m_model->fetchMore();
    msleep(100);
  }
  quit();

}
///////////////////////////////////////////////////////////////////////////////////////////////////


и как все это выполняем:
Код

void MainWindow::pushButton_test_on_clicked()
{

  if(!m_thread)
  {
      m_thread = new MyThread();
      ui->tableView_all_records->setModel( m_thread->m_MyThread_exec->m_model );
  }

  // если не писать следующей строки то приложение иногда ведет себя ещё более неадекватно
  m_thread->m_MyThread_exec->m_model->moveToThread( QThread::currentThread() ); 


  m_thread->set_sql(ui->tableView_all_records,
                    ui->lineEdit_execute_time,
                    ui->lineEdit_rows,
                    "SELECT * FROM test_table"
                    );

  m_thread->start();

}



поток m_thread - уничтожаем тока после того как полученные данные уже будут не нужны,
т.к. m_model - которая отображается в QtableView - находится в его дочернем потоке и уничтожается вместе с ним!


вообщем проблема в том что в QtableView иногда выводится слишком много записей с пустыми строками, и иногда не все строки загружаются(выводятся пустыми)...
подскажите как корректно решить задачку?


Автор: zloyGamer 5.5.2009, 20:40
может есть пример чего то похожего или кто ните делал что т подобное
дайте код поковырять

Автор: zloyGamer 6.5.2009, 22:22
ребята я нехочу обратно к wxWidgetam возвращаться smile
подскажите хоть что нибудь...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)