LINUX.ORG.RU

Qt + boost


0

0

Имеем .
1. Библиотека для работы с CAN-Bus , сообщения читаются в отдельном треде(boost) и отсылаются сигналом(boost).
2. Класс-морда на Qt , унаследованный от QWidget , бустовский сигнал соединен с функцией класса ( сигнал посылается из треда )

В функции я разбираю сообщения и вывожу на LCDNumber's , которые обновляются с большой задержкой , но если минимироватъ , а потом максимировать окно , происходит мгновенное обновление . QApplication::processEvents() не помогает .
Также не могу ничего нарисовать на плоте и не работает qDebug() :-)
Буквально "на днях" столкнулся с multithreading-овым программированием , хелп ми плиз .
Кстати , что можно и нужно почитать на эту тему ?

★★★

>>В функции я разбираю сообщения и вывожу на LCDNumber's , которые обновляются с большой задержкой , но если минимироватъ , а потом максимировать окно , происходит мгновенное обновление

Не совсем понятно..

В paintEvent() есть какой-то код, не связанный с отрисовкой ?

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

насчет первого разобрался , qt-шный foreach глючит .
QwtPlot не хочет рисовать из другого треда .

kitov ★★★
() автор топика
Ответ на: комментарий от kitov

у меня работает (Qt3), проверь свой код

#include <qapplication.h>
#include <qvbox.h>
#include <qthread.h>

#include <qwt_plot.h>
#include <qwt_curve.h>

class SQ_Thread : public QObject, public QThread
{
    Q_OBJECT

    public:
        SQ_Thread() : QObject(), QThread()
        {}
        ~SQ_Thread()
        {}

    signals:
        void doit();

    protected:
        virtual void run()
        {
            QThread::msleep(1000);

            emit doit();
        }
};

class SQ_Example : public QVBox
{
    Q_OBJECT

    public:
        SQ_Example() : QVBox()
        {
            plot = new QwtPlot(this);

            plot->setCanvasLineWidth(1);

            curv = plot->insertCurve("G1");

            thr = new SQ_Thread;

            connect(thr, SIGNAL(doit()), this, SLOT(doit()));

            thr->start();
        }

        ~SQ_Example()
        {}

    public slots:
        void doit()
        {
            const int sx = 20;
            const int sy = 20;
            double x[sx], y[sy];

            for(int i = 0;i < sx;i++)
                x[i] = i;

            for(int i = 0;i < sy;i++)
                y[i] = (1.0 + i/20.0) * i;

            plot->setCurveStyle(curv, QwtPlotCurve::Lines);
            plot->setCurveData(curv, x, y, sx);

            // replot...
            plot->replot();
        }

    private:
        QwtPlot *plot;
        long curv;
        SQ_Thread *thr;
};

int main(int argc, char ** argv)
{
    QApplication app(argc, argv);

    SQ_Example d;

    d.show();

    app.setMainWidget(&d);

    d.setActiveWindow();

    return app.exec();
}

#include "main.moc"

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

Добрался наконец-то до русской клавиатуры .

Plot уже рисует , но если , я создаю QwtLegend в ГУИ-треде ,
а QwtPlotCurve в другом треде , то всё вылетает нахрен .
Ещё интересно почему от qDebug-a в треде сегфолтится .

kitov ★★★
() автор топика
Ответ на: комментарий от kitov

Вообще ничего не понятно с этими тредами :-(
Вызивается следующий слот :

void
RuptureValve1InchWpcTest::receiveCANMessages(
const std::vector<CAN::Message> messages)
{
QMutexLocker locker(&data_->mutex);// thread safe

std::vector<CAN::Message>::const_iterator iter=messages.begin();

//lcdBar()->displayValue(1, 10);

if( data_->msgIdToReceive[0]==iter->id() ) {
lcdBar()->displayValue(1, 20);

}

строка в if выполняется , но на виджете рисуется только после изменения
размера , если расскоментировать строку lcdBar()->displayValue(1, 10);
то все выводит сразу .
У меня уже мозги кипят :-(

kitov ★★★
() автор топика
Ответ на: комментарий от kitov

Не знаю как в Qt, но во многих GUI средах принято рисовать только из одного треда (Swing, оффтопик). Иначе генерится ошибка.

Может быть, есть какой-нибудь стандартный хелпер или функция, которая бы могла приостановить любой другой тред и передать из него управление на код, который бы уже выполнялся в GUI-треде. Если делать самому, то буквально из самого GUI треда нужно просечь, что какой-то другой тред хотел бы запустить какую-то функцию в GUI треде.

В общем, часто делаетсся именно так. Наверняка, в Qt должны быть штатные средства.

dave ★★★★★
()
Ответ на: комментарий от dave

в Qt практически все изменения виджета будь QLCDNumber или QLabel вызывают update(), который в свою очередь шлёт сообщение QPaintEvent в основной GUI поток.

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

А сами изменения виджета разве не требуют GUI треда? Они, наверняка, несинхронизированные. Если нет, то тогда может что-угодно случиться...

То есть, в данном случае нельзя передавать сигнал по слоту напрямую из другого треда. По получении данных нужно синхронно/асинхронно вызвать Qt хелпер и передать ему адрес некой функции, затем этот хелпер внутри себя уже каким-то образом вызывает нужную функцию в GUI треде, а функция уже безопасно передает сигнал внутри одного и того же треда.

Я примерно так себе представляю со скидкой на то, что мои представления о Qt минимальны :)

dave ★★★★★
()
Ответ на: комментарий от dave

согласно документации

In Qt, one thread is always the GUI or event thread. This is the thread that creates a QApplication object and calls QApplication::exec(). This is also the initial thread that calls main() at program start.

** This thread is the only thread that is allowed to perform GUI operations, including generating and receiving events from the window system

сейчас пробежался по QLCDNumber - там отрисовка разветвляется на либо обычный postEvent+QPaintEvent, либо прямую отрисовку с помощью QPainter. Скорее всего срабатывает второе, и согласно доке не работает.

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

alex_custov ★★★★★
()
Ответ на: комментарий от alex_custov

Откопал из своего запасника туториал по Qt3 :) Cудя по всему, решением будет использование метода QApplication::postEvent(). И это очень похоже на то, о чем я писал выше.

dave ★★★★★
()
Ответ на: комментарий от dave

Простой QWidget::update() рабоатает .
Сейчас попробую сигнал редиректить .

kitov ★★★
() автор топика
Ответ на: комментарий от alex_custov

Как обяснить что не происходит отрисовка в коде после if ,
выношу код из if - рисует , помещаю обратно - только после изменения размера или QWidget::update() .
Просто мистика какая-то .

kitov ★★★
() автор топика
Ответ на: комментарий от kitov

Если обьявляю переменную static int counter=0 и
lcdBar()->displayValue(1,++counter) коректно выводит на LCD ,
если не инкрементировать счетчик - ничего .
Это компилятор гонит или я ?

kitov ★★★
() автор топика
Ответ на: комментарий от kitov

No. Using Boost.Signals in a multithreaded concept is very dangerous, and it is very likely that the results will be less than satisfying. Even trying to invoke the same signal from two different threads is dangerous. Although we would like to make Signals thread-safe, it is unlikely to happen without help from other developers.

твою мать...

kitov ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.