Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > [qt] пара общих вопросов


Автор: gordmiand 20.5.2010, 21:24
1. Есть проект, расположенный в папке Papka1…в дополнение к нему я создал (типа “Класс формы Qt Designer ”) еще одну ui-форму с ее классом в папке Papka1/pap2 – вроде все нужные файлы  (cpp, h, ui –файлы) вновь созданной формы хранятся в указном месте (папке pap2), но почему при компиляции проги ui-файл хидера новой формы каждый раз создается (???) не в папке pap2, а в главной папке приложения (Papka1)? Как это исправить, чтобы этот файл создавался в нужной мне папке (pap2)? Естес-но если я в проге при подключении этого ui-файла хидера новой формы задам путь к ..//pap2, то прога будет нечувствительна к изменениям состава виджетов на этой форме, так как все-таки будет браться (???) этот ui-h-файл из папки Papka1… заморочился таким вопросом по причине того, что просто хочу разложить, так сказать, все по полочкам – все файлы проекта – в одной папке, все вспомогательное – в другой… 
2. как мне сделать бесконечный цикл, чтобы он запускался сразу после загрузки проги? в конструкторе main-класса это сделать нельзя - прога подвисает на этапе запуска...
сначала я таймер использовал для этого - в событии обработки таймера (TimerEvent) у меня происходит прием данных по сети со своим внутренним таймаутом - и при совместном использовании таймера и таймаута в функции чтения данных из сети, судя по каким-то судорожным принтам приходящей информации, этот прием данных выполняется как-то прерывисто что ли...
оптимально и наиболее надежно все это сделать обычным вечным циклом с таймайтом при чтении данных из сети, но как сие осуществить при возникновении вышеуказанной проблемы подвисания проги сразу при ее загрузке...

Автор: ecspertiza 21.5.2010, 16:51
1. В *.pro файле прописываешь 
Код

UI_HEADERS_DIR = tmp/ui/include
UI_SOURCES_DIR = tmp/ui/src


Ну и там пути естественно какие тебе удобны


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

Автор: Remiznik 21.5.2010, 20:30
2. создай класс который загружается во время входа в программу и запусти в нём цикл. 

Автор: gordmiand 21.5.2010, 23:10
ecspertiza:
по п.1 - все понял - обяз-но поробую....
по п.2. да уж куда проще:
если взять консольное приложение:
Код

int  main(int argc, char *argv[])
{
int i=1;

while (i>0)
{
    read_from_net((char *)&buf, len, 100); // своя рабочая функция - включает в себя создание сокета, ioctl, bind и т.д.    
    …
    printf(...); 
    sleep(1);
    i++;
}

return 0;
}

то есть задача стояла следующая – я бесконечное число раз с заданным таймаутом (100 мс) читаю данные из сетевого буфера...
а как мне такой while сделать в гуишном кутэ? в консоли (см. пример выше) все окей работает...
если поставить такой while в сигнал какого-либо виджета (допустим онклик кнопки) или в конструктор главной формы, то прога вообще подвисает...вместо самого while-a пробовал использовать таймер с интервалом аж 1 мс (ну типа самое минимальное, аля как темп работы while-а), а тело while-a запихнул соответственно в timerEvent, но судя по печатям чего-либо в этом цикле он срабатывает неправильно – то есть значения выводятся верные, но непонятно с каким временным интервалом (1 мс + 100 мс ?) и печатаются сообщения неравномерно (то вообще ничено не принтуется, а то сразу несколько строк с данными)  

Автор: gordmiand 21.5.2010, 23:48
Remiznik: поправьте (напишите верно) Вашу идею в приложенной программке....и подскажите функцию кутей аля Sleep для вывода данных с задержкой...

Автор: borisbn 22.5.2010, 06:58
Цитата
.и подскажите функцию кутей аля Sleep

У кутей нет Sleep, поэтому я себе сделал маленький классик

Код

#ifndef SLEEPER_H_INCLUDED
#define SLEEPER_H_INCLUDED

#include <QThread>
class Sleeper : public QThread
{
public:
    static void go( int ms ) { msleep( ms ); }
};
#endif // SLEEPER_H_INCLUDED

и использую его
Код

Sleeper::go( 100 ); // sleep 100 мс


Автор: gordmiand 22.5.2010, 14:10
borisbn: 
спасибо за классик, только непонятно почему нельзя напрямую использовать  функцию msleep, если с помощью нее, как я понял, и реализуется задержка в Вашем методе go? и что это за метод - msleep?

и все-таки - как же в гуищном qt-проекте реализовать рабочий (независающий) бесконечный цикл?

Автор: borisbn 22.5.2010, 19:55
Цитата(gordmiand @  22.5.2010,  14:10 Найти цитируемый пост)
почему нельзя напрямую использовать  функцию msleep

http://doc.qt.nokia.com/4.6/qthread.html#msleep - статическая protected-функция класса QThread
Цитата(gordmiand @  22.5.2010,  14:10 Найти цитируемый пост)
в гуищном qt-проекте реализовать рабочий (независающий) бесконечный цикл

гуишный поток обработки сообщений сделан примернотак (псевдо-код)
Код

если в очереди есть сообщение
    обработать сообщение
    удалить сообщение из очереди
конец если

если ты в функции "обработать сообщение" организешь бесконечный цикл, то очередь перестанет обрабатываться, и ты не сможешь обработать даже сообщения перемещения мыши и т.п.
Для таких случаев предусмотрены отдельные потоки (в Qt - QThread), которые выполняются параллельно (или псевдопараллельно) с основным (гуишным) потоком

Автор: gordmiand 23.5.2010, 19:54
borisbn: то есть простой бесконечный while напрямую (прямо в mainwindow.cpp) сделать нельзя?
типа 
Код

int i=0;

while (i>=0)    
{

         // что-то делаем
          printf (" " ); 
    
i++;
}

в консольном приложении такой циклик нормально работает...
то есть мне надо этот цикл запихнуть в отдельный QThread-поток (класс-наследник от QThread) и вызывать его из основного main-потока???

Автор: gordmiand 23.5.2010, 21:26
Код

                                                                        klass2.h:
#include <QThread>
class klass2: public QThread 
{
public:
    klass2();
    int perem;
    void run();
};

///////////////////////////////////////////////////////
                                                                        klass2.cpp:
#include "klass2.h"
klass2::klass2()
{   }

void klass2::run()
{
       int i=1;
       perem=15;

/*
        while (i>0)
        {
            perem=5;
           i++;
        }
*/
}

                                                                             mainwindow.h
...
#include "klass2.h"

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

    klass2 *kl2;
….
}
                                                                            mainwindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

        kl2 = new klass2;

        kl2->start();     //или  QThread::IdlePriority);

        ui->listWidget->addItem(QString::number(kl2->perem));
}

2 вопроса:
1. Почему значение perem=0, а не 15, как задано в методе run? Как будто он вообще не запускается, хотя вроде должен был после вызова метода start сего класса (kl2->start();)?
2. как мне сделать вывод в listWidget главной формы циклически бесконечно задаваемых
(while (i>0) …) значений (=5) переменной perem из метода run класса klass2? 

Автор: borisbn 24.5.2010, 06:39
Поток запускается не сразу, а с какой-то задержкой, поэтому в переменной ноль (хотя мог быть и мусор). Так, как у тебя сделано, делать нельзя. Представь, что у тебя не целочисленная переменная, а структура типа "имя", "фамилия". Может получиться, что ты отобразишь имя одного человека, а фамилию другого. Чтобы этого не получилось используй QMutex для блокирования данных, используемых одновременно в двух потоках.
Ещё можно в QThread-классе добавить сигнал, который будет передавать значение переменной гуишному потоку, а в форме создать слот, принимающий и отображающий переменную. 
И не забудь связать этот сигнал с гуишным слотом

Код

// klass2.h
class klass2: public QThread 
{
public:
    klass2();
    int perem;
    void run();
signals:
    void drawPerem( int );
};
// klass2.cpp
void klass2::run()
{
       int i=1;
       perem=15;

       emit drawPerem( perem );
}
//mainwindow.h

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

    klass2 *kl2;
public slots:
    void onDrawPerem( int );
}
//mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

        kl2 = new klass2;
        connect( kl2, SIGNAL( drawPerem( int ) ), SLOT( onDrawPerem( int ) ) );

        kl2->start();     //или  QThread::IdlePriority);

}

void MainWindow::onDrawPerem( int perem )
{
        ui->listWidget->addItem( QString::number( perem ) );
}

как-то так

Автор: gordmiand 24.5.2010, 10:19
понятно...то есть получается, что получить доступ к данным, изменяющимся в методе run, одного потока из другого можно только через сигналы (то есть передавая/принимая нужные данные через connect - т.е. соединение типа сигнал-слот),  а "по-простому" (получить значение нужной переменной стороннего класса через его экземпляр) нельзя, хотя поток тоже является классом (наследником QThread), a run - методом? 
а если я хочу пользоваться в главном потоке приложения не одной переменной из стороннего потока (klass2), а, допустим, десятком данных (значениями массивов, структур этого потока), то мне всех их надо запихивать в сигнал (в виде целикового массива)? 
но сторонний поток мне в любом случае нужен (для ускорения работы проги)...

Автор: borisbn 24.5.2010, 14:23
Цитата(gordmiand @  24.5.2010,  10:19 Найти цитируемый пост)
доступ к данным, изменяющимся в методе run, одного потока из другого можно только через сигналы

нет. не только. это один из способов. другой способ - использовать QMutex для блокирования данных, используемых одновременно в двух потоках.
Код

// klass2.h
class klass2: public QThread 
{
public:
    klass2();
    int perem;
    int array[ 1000 ];
    void run();

    QMutex m_dataLocker;
    int getPerem();
    void getArray( int * a );
};
// klass2.cpp
void klass2::run()
{
       int i=1;
...
       m_dataLocker.lock();
       perem=15;
       array[ i ] = 10;
       m_dataLocker.unlock();
...
}
int klass2::getPerem()
{
       QMutexLocker locker( &m_dataLocker );
       return perem;
}
void klass2::getArray( int * a )
{
       QMutexLocker locker( &m_dataLocker );
       memcpy( a, array, sizeof( array ) );
}

//mainwindow.cpp
void MainWindow::doSomething()
{
        ui->listWidget->addItem( QString::number( kl2->getPerem() ) );
        int array[ 1000 ];
        kl2->getArray( array );
}

Автор: gordmiand 24.5.2010, 20:06
вау...как все сложно - какой-то QMutexLocker locker,  memcpy...
можно получить хотя бы краткое пояснение сего кода?

по поводу предыдущего (перед мутексами) сообщения - все работает, спасибо за подсказку.
То есть получается, что данная переменная perem будет доступна в классе (mainwindow) главного потока  только в слоте (PotokPerem), в который она была „передана“?  
Код

#include <QThread>
class klass2: public QThread                               
{
    Q_OBJECT
public:
    klass2();
    int perem;
    void run();
signals:
      void ShowPer(int);
};

///////////////////////////////////////////////////////
klass2::klass2()     
{
     perem=0;
}


void klass2::run()
{
       int i=1;
       perem = 11;
      
        emit  ShowPer( 55 );
}
///////////////////////////////////////////////////////

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
    klass2 *kl2;
public slots:
    void PotokPerem(int);
...
};
///////////////////////////////////////////////////////

MainWindow::MainWindow(QWidget *parent) :  QMainWindow(parent),  ui(new Ui::MainWindow)
{
    ui->setupUi(this);


             kl2 = new klass2;
             kl2->start();        

             connect(kl2,    SIGNAL(ShowPer(int)),     this,   SLOT(PotokPerem(int))  );
}

void MainWindow::PotokPerem(int )
{
       ui->listWidget->addItem(QString::number(kl2->perem));
}
///////////////////////////////////////////////////////

Почему, если задать в качестве аргумента для emit ShowPer не perem, а, допустим, любую константу (55) или что-то еще, но не perem, то все равно при выводе (слот PotokPerem) в главном потоке значение переменной perem = 11, как и задано в методе run, но я же вроде как не передаю эту переменную в сигнале (а, например, задана отвлеченная константа 55) в слот главного потока... 
Непонятно зачем здесь вообще нужны параметры  для сигнала ShowPer и слота PotokPerem, когда и без них все работает (в главном потоке выводится значение (11) переменной perem)???

Автор: djamshud 24.5.2010, 20:41
memcpy - это так модно массивы копировать (не все!). Про мутексы полно информации в интернетах. Можно воспользоваться и другими, системными, приемами синхронизации. Например на семафорах можно сделать, чтобы данные могли читаться одновременно из N процессов/потоков, а писались синхронно (дождавшись завершения их чтения).

Добавлено через 20 секунд
В Qt оказывается тоже семафоры есть...

Автор: borisbn 25.5.2010, 09:34
Цитата(gordmiand @  24.5.2010,  20:06 Найти цитируемый пост)
То есть получается, что данная переменная perem будет доступна в классе (mainwindow) главного потока  только в слоте (PotokPerem), в который она была „передана“?  

в слоте "видна" копия этой переменной

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