Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Белый пони от Ноябрь 25, 2009, 23:53



Название: Обновление QLCDNumber в цикле?
Отправлено: Белый пони от Ноябрь 25, 2009, 23:53
Здравствуйте!
Есть программа, которая в консольном режиме считывает байты приходящие на com-порт() и выводить printf'ом на экран, при нажатии ESC программа завершается. Всё работает как надо.

Попытался сделать аналогичную штуку в Qt 4.5  (просто убрал принтфы и заменил на "ui->myLcd->display(int( R[0] ));", fp - file descriptor последовательного порта). Всё интересное в цикле while :

Код:
void myWid::on_myButton_clicked()
{
int i = 0;
char R[5] = {0};

struct termios tp1;
struct termios tp2;

tcgetattr( 0, &tp1);

tp2 = tp1;

  tp2.c_iflag&=~ICRNL;
  tp2.c_lflag&=~ICANON;
  tp2.c_lflag&=~ECHO;
  tp2.c_cc[VMIN ]=1;
  tp2.c_cc[VTIME]=0;
  tp2.c_cc[VINTR]=0xFF;
  tp2.c_cc[VSUSP]=0xFF;
  tp2.c_cc[VQUIT]=0xFF;

tcsetattr( 0, TCSANOW, &tp2);

fd_set set0, set;
FD_ZERO( &set);
FD_SET( fp, &set);
FD_SET(  0, &set);
set0 = set;

while(1)
        {
        if ( select( fp+1, &set, NULL, NULL, NULL ) > 0)
                {
                if( FD_ISSET( fp, &set))
                        {
                        i = read( fp, R, 1);
                        ui->myLcd->display(int( R[0] ));
                        //break;
                        }
                if( FD_ISSET( 0, &set) )
                        {
                        i = read( 0, R, 1);
                        if( R[0] == 27){ break;}
                        }
                }

        set = set0;
        }

tcflush( fp, TCIOFLUSH);
tcsetattr( 0, TCSANOW, &tp1);
}

Байты то считываются, но из них всех на LCDNumber отображается только последний, после выхода из цикла.
Как сделать так, чтобы показания QLCDNumber менялась сразу при получении байта, до завершения цикла?   Пытался добавлять "ui->myLcd->update();", не получилось :(

И ещё проблема:  с клавиатуры ничего не принимается с том числе и ESC :(
Можно ли вообще читать клавиатуру read'ом в Qt 4.5 ? Что я делаю не так? :(


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: niXman от Ноябрь 26, 2009, 00:09
Цитировать
отображается только последний, после выхода из цикла.
Так и должно быть. Цикл сообщений заблокирован.

Твой цикл нужно вынести в поток. И все ;)


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: sLiva от Ноябрь 26, 2009, 00:24
Можно в теле цикла вызвать qApp->processEvents()

http://qt.nokia.com/doc/4.5/qcoreapplication.html#processEvents

Но это замедлит скорость работы цикла


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: Белый пони от Ноябрь 26, 2009, 00:57
Твой цикл нужно вынести в поток. И все ;)
Я совсем новичок :) Я правильно понял, нужно создать экземпляр QThread и поместить мой цикл в функцию run() ?


Можно в теле цикла вызвать qApp->processEvents()
http://qt.nokia.com/doc/4.5/qcoreapplication.html#processEvents
Но это замедлит скорость работы цикла
Спасибо! Так тоже попробую!


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: niXman от Ноябрь 26, 2009, 01:21
Цитировать
Можно в теле цикла вызвать qApp->processEvents()
Логически не правильное решение.

Цитировать
нужно создать экземпляр QThread и поместить мой цикл в функцию run() ?
Именно.

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

Что-то типа:
Код
C++ (Qt)
signals:
  void update_signal(int);
 

в run()
Код
C++ (Qt)
while ( true ) {
  ...
  emit update_signal(int( R[0] ));
}
 

и в myWid::myWid()
Код
C++ (Qt)
mythread = new MyThread(this);
connect(mythread, SIGNAL(update_signal(int)), ui->myLcd, SLOT(display(int)));
mythread->start();
 

ничего не упустил?


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: Белый пони от Ноябрь 26, 2009, 02:38
Цитировать
Так же нужно декларировать сигнал, который будет испускаться когда хочешь отобразить данные.

Что-то типа:

Спасибо огромное! ;D

Но пока не получилось :(

Вот такой mythread.h:
Код:
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class MyThread : public QThread
 {
 public:
     void run();

 signals:
   void update_signal(int);

 };

#endif // MYTHREAD_H
Вот такой mythread.cpp:
Код:
#include "mythread.h"

void MyThread::run()
 {
 int i = 0;
 while( i < 100)
     {
     i++;
     msleep(10);
     emit update_signal( i );
     }
 }

И вот myWid::myWid()
Код:
4    myWid::myWid(QWidget *parent)
5        : QWidget(parent), ui(new Ui::myWidClass)
6    {
7        ui->setupUi(this);
8        mythread = new MyThread(this);
9        connect(mythread, SIGNAL(update_signal(int)), ui->myNum, SLOT(display(int)));
10       mythread->start();
11   }

В последнем на 8-ой строчке находятся 2 ошибки:
/qtest/zikl/blinkwidget.cpp:8: error: ‘mythread’ was not declared in this scope
и
/qtest/zikl/blinkwidget.cpp:8: error: no matching function for call to ‘MyThread::MyThread(blinkWidget* const)’  :(

Все инклуды вроде на месте.


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: niXman от Ноябрь 26, 2009, 03:21
MyThread должен выглядеть так:
Код
C++ (Qt)
class MyThread : public QThread
{
Q_OBJECT
public:
    MyThread(QObject* o):QThread(o) {
        /** other initialization's are needed put here */
    }
    void run();
 
signals:
  void update_signal(int);
 
};
 
 

В приватную секцию класса myWid
добавь:
Код
C++ (Qt)
MyThread* mythread;
 

Цитировать
8-ой строчке находятся 2 ошибки:
Замени ее на:
Код
C++ (Qt)
mythread = new MyThread(parent);
 


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: kuzulis от Ноябрь 26, 2009, 08:35
И мои 5 копеек ! :)

Если не лень, (как вариант) - то можешь использовать библиотеку QSerialDevice (это не PR ;) ) : http://fireforge.net/snapshots.php?group_id=199

там смотри пример /examples/sreader

используя этот пример ты можешь просто приконнектиться к сигналу readyRead()
т.е что то типа:
Код:
connect(mySerialDevice, SIGNAL(readyRead()), myLCD, SLOT(updateLCD()));

при этом слот updateLCD()  может выглядеть так:
Код:
void myLCD::updateLCD()
 {
    QByteArray ba = mySerialDevice->read(1);
    myLCD->data = (тут преобразование/приведение типа) ba;
 }


При этом можно потоки вообще не использовать. (вообще это в реале уже нужно смотреть по тому факту - тормозит ли GUI или нет)


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: spectre71 от Ноябрь 26, 2009, 11:35
Конечно выносить длительные расчеты в отдельный Thread лучше всего! Но если скорость отклика GUI во время вычисления не важна, а важна только индикация процесса, то можно сделать проще.

Example(не запускать в конструкторе :)):
Код
C++ (Qt)
void MyMainWindow::longStandingCalculation(void) {
 for(int i=0; i<1024*1024*1024; i++) {
   if(i%1000 == 0) {
     updateValue(i);
   }
 }
}
 
void MyMainWindow::updateValue(int value) {
 static QTime CurTime = QTime::currentTime();
 if(CurTime.msecsTo(QTime::currentTime()) >= 100) {
   CurTime = QTime::currentTime();
   ui.label->setText(QString::number(value));
   QApplication::processEvents();
 }
}


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: Белый пони от Ноябрь 26, 2009, 11:39
MyThread должен выглядеть так:

Всё подправил, теперь выдаётся одна ошибка в mythread.cpp:

/qtest/zikl/mythread.cpp:10: undefined reference to `MyThread::update_signal(int)'
 error: collect2: ld returned 1 exit status

Код:
1   #include "mythread.h"
2   
3   void MyThread::run()
4   {
5    int i = 0;
6    while( i < 100)
7        {
8        i++;
9        msleep(10);
10       emit update_signal( i );
11       }
12   }

Пытался гуглить, пишут надо подключать библиотеки,но я не понял какие и как ( использую Qt Creator).


Цитировать
И мои 5 копеек !

Если не лень, (как вариант) - то можешь использовать библиотеку QSerialDevice (это не PR Подмигивающий ) : http://fireforge.net/snapshots.php?group_id=199

там смотри пример /examples/sreader

Спасибо!
Пока запас быстродействия есть.

Но самый быстрый вариант это с использованием потока?


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: niXman от Ноябрь 26, 2009, 11:44
Тот файл в котором декларирован MyThread, добавь к целям moc


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: Белый пони от Ноябрь 26, 2009, 11:53
Тот файл в котором декларирован MyThread, добавь к целям moc
А как? :) Добавить его в файл .pro ? Он уже там есть:
Код:
TARGET = zikl
TEMPLATE = app
SOURCES += main.cpp \
    myWid.cpp \
    mythread.cpp
HEADERS += myWid.h \
    mythread.h
FORMS += myWid.ui


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: niXman от Ноябрь 26, 2009, 11:59
Кстати, Q_OBJECT у тебя вписан сразу за открывающейся фигурной скобкой?


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: Белый пони от Ноябрь 26, 2009, 12:07
Кстати, Q_OBJECT у тебя вписан сразу за открывающейся фигурной скобкой?

Ай. нет. Сейчас добавил. получилось так:

Код:
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class MyThread : public QThread
 {

    Q_OBJECT

 public:
    MyThread(QObject* o):QThread(o) {     }
     void run();

 signals:
   void update_signal(int);

 };

#endif // MYTHREAD_H

Теперь добавилась ещё одна строчка в сообщении об ошибке:
Цитировать
/qtest/zikl/mythread.h:12: undefined reference to `vtable for MyThread'
/qtest/zikl/mythread.cpp:10: undefined reference to `MyThread::update_signal(int)'
error: collect2: ld returned 1 exit status
:(


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: niXman от Ноябрь 26, 2009, 12:21
Цитировать
Теперь добавилась ещё одна строчка в сообщении об ошибке:
О!, Это уже хорошо!

Почисть от "продуктов" компиляции. Потом qmake и make.
И усё.


Название: Re: Обновление QLCDNumber в цикле?
Отправлено: Белый пони от Ноябрь 26, 2009, 12:35
Цитировать
Теперь добавилась ещё одна строчка в сообщении об ошибке:
О!, Это уже хорошо!

Почисть от "продуктов" компиляции. Потом qmake и make.
И усё.

Получилось :)
Спасибо огромное за подробную помощь! :)