Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Spark от Июль 16, 2013, 15:13



Название: Утечка памяти
Отправлено: Spark от Июль 16, 2013, 15:13
Функция перебора вертикального списка имен для передачи пунктов списка иной функции (слайдшоу).
Код
C++ (Qt)
void MainWindow::slideshowOn(bool on)
{
   if(!on)return;
   slideShowQuit = false;
   slideShowStop = false;
 
   QString importPath;
   if( cfg.contentExportPath.isEmpty() )
       importPath = QDir::homePath();
   else
   {
       importPath = QDir::fromNativeSeparators( cfg.contentExportPath );
       if( !QDir( importPath ).exists() )
           importPath = QDir::homePath();
   }
 
   QString fileName = QFileDialog::getOpenFileName( this, tr( "Slideshow content from file" ),
                                                    importPath,
                                                    tr( "Text files (*.txt);;All files (*.*)" ) );
   if( fileName.size() == 0)
   {
       slideshowButton->setChecked(false);
       return;
   }
 
   QFileInfo fileInfo( fileName );
   QString contentName = fileInfo.baseName();
   QFile file( fileName );
   int n(0);
 
 
   // Count slides
   if ( file.open( QFile::ReadOnly ) )
   {
 
       char buf[1024];
       qint64 lineLength;
       forever
       {
           lineLength = file.readLine(buf, sizeof(buf));
           if (lineLength > 0)
           {
               ++n;
           }
           else if (lineLength == -1)
           {
               break;
           }
       }
       file.close();
   }
 
 
       if ( file.open( QFile::ReadOnly | QIODevice::Text ) )
 
       {
 
 
       QTextStream fileStream( & file );
       QString itemStr, trimmedStr;
 
 
       QString str;
       str.setNum(n);
 
 
       slidePopup->setWindowTitle( contentName + "/" + str );
 
// slide Show
       do
       {
 
// Pause
           do
           {
               QEventLoop loop;
               QTimer::singleShot(0, &loop, SLOT(quit()));
               loop.exec();
           } while(slideShowStop);
 
 
           itemStr = fileStream.readLine();
           if( fileStream.status() >= QTextStream::ReadCorruptData )
               break;
 
           trimmedStr = itemStr.trimmed();
           if( trimmedStr.isEmpty() )
               continue;
 
           if(slideshowPopup->isChecked())slidePopup->slideTranslationFor( trimmedStr );
           if(slideshowGrand->isChecked())showTranslationFor( trimmedStr );
 
           QEventLoop loop3;
           QTimer::singleShot(cfg.preferences.slideShowTimer, &loop3, SLOT(quit()));
           loop3.exec();
 
           if(slideShowQuit)break;
 
       } while( !fileStream.atEnd() );
 
       file.close();
       }
}
Запускаю слайдошоу с основного окна mainwindow.cc. Все функционирует как надо и при маленьком и при большом списке. Никакой утечки не наблюдается. Если окно слайдов предварительно закрыть, то сама программа закрывается благополучно. Если окно слайдшоу включено, то при маленьком списке программа закрывается нормально.
Но если список велик (например 100 тысяч), то при включенном окне слайдшоу не получается нормально закрыть программу. Висит. А в диспетчере задач наблюдается быстрое увеличение объема памяти для программы в момент закрытия.
В чем может быть проблема?


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 09:31
Понимаю, что необходимо предварительно закрыть слайдшоу.

Если выхожу корректно, отсылая предварительно сигнал на слот(нажимаю кнопку "стоп слайды" в основном окне):
Код
C++ (Qt)
void MainWindow::slideshowOff( bool )
{
   slideShowQuit = true;
}
После этого закрытие всей программы благополучное.

В mainwindow.cc прописал связь:
Код
C++ (Qt)
 connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(slideshowOff( bool )));
Не срабатывает. Если слайдшоу еще работает, программа не может выйти корректно.


Название: Re: Утечка памяти
Отправлено: kambala от Июль 17, 2013, 11:48
у слота не может быть параметров больше, чем у сигнала (только если они не по умолчанию). непонятно зачем ты вообще туда этот bool прилепил.


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 12:09
у слота не может быть параметров больше, чем у сигнала (только если они не по умолчанию). непонятно зачем ты вообще туда этот bool прилепил.
Да вроде я это понимаю. Экспериментировал.

Но функция, останавливающая void MainWindow::slideshowOn(bool on), перестает работать в таком виде :
Код
C++ (Qt)
void MainWindow::slideshowOff()
{
   slideShowQuit = true;
}
Как я это реализовал видно здесь http://www.prog.org.ru/index.php?topic=25276.msg180591#msg180591
А ка бы вы остановили slideshowOn(bool on)?

Честно говоря отчаялся правильно реализовать. Видимо придется оставить как есть (работает однако) до осознания данного момента.


Название: Re: Утечка памяти
Отправлено: kambala от Июль 17, 2013, 12:34
я бы QEventLoop loop3 поместил в класс и останавливал бы ее перед установкой флажка


Название: Re: Утечка памяти
Отправлено: Old от Июль 17, 2013, 12:39
А почему вместо организации задержки, не менять картинки по сигналу таймера?


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 12:46
Т.е. пока, что так. Есть кнопка в главном окне, нажимая на которую испускаем сигнал:
Код
C++ (Qt)
 connect( slideshowButton, SIGNAL( toggled( bool ) ),
          this, SLOT( slideshowOn( bool ) ) );

Срабатывает слот:
Код
C++ (Qt)
void MainWindow::slideshowOff( bool )
{
   slideShowQuit = true;
}

Однако, функция слайдшоу slideshowOn(bool on) срабатывает и заряжает:
Код
C++ (Qt)
slideShowQuit = false;

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


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 12:54
А почему вместо организации задержки, не менять картинки по сигналу таймера?
Т.е вы имеете ввиду вместо:
Код
C++ (Qt)
           QEventLoop loop3;
           QTimer::singleShot(cfg.preferences.slideShowTimer, &loop3, SLOT(quit()));
           loop3.exec();
поставить:
QTest::Sleep (5000);
У меня непутевого не сработало. Компилятор ругается: ошибка: undefined reference to `QTest::qSleep(int)'


Название: Re: Утечка памяти
Отправлено: Alex Custov от Июль 17, 2013, 12:56
QT += testlib


Название: Re: Утечка памяти
Отправлено: Old от Июль 17, 2013, 12:57
У меня непутевого не сработало. Компилятор ругается: ошибка: undefined reference to `QTest::qSleep(int)'
Нет, я предлагаю использовать QTimer, который будет генерировать сигнал с нужным интервалом, по которому будут изменяться картинки.


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 13:02
Спасибо.
Сейчас буду пытаться понять ваши советы и экспериментировать :). Все таки каждый шаг осознания дается с боем.


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 13:03
У меня непутевого не сработало. Компилятор ругается: ошибка: undefined reference to `QTest::qSleep(int)'
Нет, я предлагаю использовать QTimer, который будет генерировать сигнал с нужным интервалом, по которому будут изменяться картинки.
По этому поводу скажите только одно. Это может решить текущую проблему? Или в противном случае изучение этого метода лучше отложить?


Название: Re: Утечка памяти
Отправлено: Old от Июль 17, 2013, 13:19
По этому поводу скажите только одно. Это может решить текущую проблему? Или в противном случае изучение этого метода лучше отложить?
Это другой подход (на мой взгляд более правильный) к решению вашей задачи.


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 14:00
Попутно опубликую второй момент, который хотелось бы решить.
Думаю ясно как реализован запуск и пауза слайдшоу:
http://www.prog.org.ru/index.php?topic=25276.msg180591#msg180591
Но такой подход не очень эргономичен:
- Нажатие кнопки вызывает выбор текстового списка слайдшоу.
- Второе нажатие (отжимает кнопку) выключает слайдшоу.
- Пауза работает с контекстного меню.

А хотелось бы, что бы второе нажатие вызывало паузу. В общем то это не сложно. Сложно продолжить слайдшоу после паузы, нажав на эту же кнопку. Как ни пытался не получилось.
Может подскажете не сложный способ или направите в нужное русло?


Название: Re: Утечка памяти
Отправлено: Kurles от Июль 17, 2013, 15:11
А хотелось бы, что бы второе нажатие вызывало паузу. В общем то это не сложно. Сложно продолжить слайдшоу после паузы, нажав на эту же кнопку. Как ни пытался не получилось.
Может подскажете не сложный способ или направите в нужное русло?
Тему не читай - сразу отвечай: что мешает где нибудь хранить состояние кнопки, да хотя бы в свойствах (bool QObject::setProperty ( const char * name, const QVariant & value ) и QVariant QObject::property ( const char * name ) const)?


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 15:28
Дело в том, что первоначально кнопка запускает функцию выбора текстового списка и в этой же функции прописан цикл слайдшоу.
И во второй раз нажимая кнопку (после паузы) мне не удалось избавиться от процесса выбора списка. Пришлось использовать дополнительную кнопку или контекстное меню кнопки для запуска дополнительной функции, переключающей булевой переменную - переключателя плей/пауза.

P.S. Но может я не понял совет. Вот если бы можно было как то заставлять нажатие кнопки генерировать иной сигнал, после смены состояния булевой переменной. Тогда было бы просто.


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 17:02
До кучи еще один вопрос на будущее. Каким образом организовывается рандомное чтение строк списка?


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 18:40
Пока разделил функцию. Проблему не решило, но может будет проще?
Код
C++ (Qt)
void MainWindow::slideshowOn(bool on)
{
   if(!on)return;
   slideShowQuit = false;
   slideShowStop = false;
 
   QString importPath;
   if( cfg.contentExportPath.isEmpty() )
       importPath = QDir::homePath();
   else
   {
       importPath = QDir::fromNativeSeparators( cfg.contentExportPath );
       if( !QDir( importPath ).exists() )
           importPath = QDir::homePath();
   }
 
   QString fileName = QFileDialog::getOpenFileName( this, tr( "Slideshow content from file" ),
                                                    importPath,
                                                    tr( "Text files (*.txt);;All files (*.*)" ) );
   if( fileName.size() == 0)
   {
       slideshowButton->setChecked(false);
       return;
   }
 
   QFileInfo fileInfo( fileName );
   QString contentName = fileInfo.baseName();
   QFile file( fileName );
   int n(0);
 
 
   // Count slides
   if ( file.open( QFile::ReadOnly ) )
   {
 
       char buf[1024];
       qint64 lineLength;
       forever
       {
           lineLength = file.readLine(buf, sizeof(buf));
           if (lineLength > 0)
           {
               ++n;
           }
           else if (lineLength == -1)
           {
               break;
           }
       }
       file.close();
   }
 
 
       if ( file.open( QFile::ReadOnly | QIODevice::Text ) )
 
       {
 
 
       QTextStream fileStream( & file );
       QString itemStr;
 
 
       QString str;
       str.setNum(n);
 
 
       slidePopup->setWindowTitle( contentName + "/" + str );
 
// slide Show
       do
       {
 
// Pause
           do
           {
               QEventLoop loop;
               QTimer::singleShot(0, &loop, SLOT(quit()));
               loop.exec();
           } while(slideShowStop);
 
 
           itemStr = fileStream.readLine();
           if( fileStream.status() >= QTextStream::ReadCorruptData )
               break;
 
           trimmedStr = itemStr.trimmed();
           if( trimmedStr.isEmpty() )
               continue;
 
           QEventLoop loop3;
           QTimer::singleShot(cfg.preferences.slideShowTimer, &loop3, SLOT(quit()));
           loop3.exec();
 
           updateShow();
 
           if(slideShowQuit)break;
 
       } while( !fileStream.atEnd() );
 
       file.close();
       }
}
 
void MainWindow::updateShow()
{
           if(slideshowPopup->isChecked())slidePopup->slideTranslationFor( trimmedStr );
           if(slideshowGrand->isChecked())showTranslationFor( trimmedStr );
}


Название: Re: Утечка памяти
Отправлено: Spark от Июль 17, 2013, 18:43
И еще, я конечно много недопонимаю.
Но может поясните, почему в этой конструкции таймер не сработал:
Код
C++ (Qt)
       do
       {
 
           do
           {
               QEventLoop loop;
               QTimer::singleShot(0, &loop, SLOT(quit()));
               loop.exec();
           } while(slideShowStop);
 
 
           itemStr = fileStream.readLine();
           if( fileStream.status() >= QTextStream::ReadCorruptData )
               break;
 
           trimmedStr = itemStr.trimmed();
           if( trimmedStr.isEmpty() )
               continue;
 
 
           QTimer::singleShot(cfg.preferences.slideShowTimer, this, SLOT(updateShow()));
 
           if(slideShowQuit)break;
 
     } while( !fileStream.atEnd() );
 
Слайды показываются - пробегают.
Где напутал?

P.S.
Понял свою ошибку. Эта конструкция бессмысленна, но кажется осознал, что хотел сказать Old. Ну что ж учимся потихоньку. Уже завтра попробуем организовать слайдшоу по иному.


Название: Re: Утечка памяти
Отправлено: Kurles от Июль 18, 2013, 11:15
P.S. Но может я не понял совет. Вот если бы можно было как то заставлять нажатие кнопки генерировать иной сигнал, после смены состояния булевой переменной. Тогда было бы просто.
Хандли состояние этой переменной в слоте, кот. привязан к кнопке.
Код
C++ (Qt)
enum states {
   fristState,
   secondState,
   nState
};
 
void MainWindowtete::onButtonPushed()
{
 
   switch (state) {
   // первоначальное состояние
   case fristState:
   {
       doWork1(); // ... некоторая работа
       state = secondState; // в сл. раз при вызове этого слота уже на выполнится блок в сл. case
   }
       break;
   case secondState:
   {
       doWork2(); // .. некоторая другая работа...
       state = nState;
   }
       break;
   case nState:
   {
       doWorkN(); // завершающая работа
       state = fristState; // переходим к первоначальному состоянию
   }
       break;
   default:
       break;
   }
}


Название: Re: Утечка памяти
Отправлено: Spark от Июль 18, 2013, 16:50
Kurles
Спасибо за наводку. Пошел несколько иначе, более традиционным способом (для меня), но пищу дали для размышления как можно реализовать. Сейчас кнопка работает как задумал. Сначала выбираем файл, а затем уже  она работает как Pause/Play.
Код
C++ (Qt)
void MainWindow::slideshowOn(bool on)
{
   if(!on)
   {
       slideShowPause = true;
       return;
   }
   else if(slideShowPlay && slideShowPause)
   {
       slideShowPause = false;
       return;
   }
   else
   {
       slideShowPlay = true;
       slideShowPause = false;
 
       QString importPath;
       if( cfg.historyExportPath.isEmpty() )
           importPath = QDir::homePath();
       else
   {
       importPath = QDir::fromNativeSeparators( cfg.contentExportPath );
       if( !QDir( importPath ).exists() )
           importPath = QDir::homePath();
   }
 
   QString fileName = QFileDialog::getOpenFileName( this, tr( "Slideshow content from file" ),
                                                    importPath,
                                                    tr( "Text files (*.txt);;All files (*.*)" ) );
   if( fileName.size() == 0)
   {
       slideshowButton->setChecked(false);
       return;
   }
 
   QFileInfo fileInfo( fileName );
   QString contentName = fileInfo.baseName();
   QFile file( fileName );
   int n(0);
 
   // Count slides
   if ( file.open( QFile::ReadOnly ) )
   {
 
       char buf[1024];
       qint64 lineLength;
       forever
       {
           lineLength = file.readLine(buf, sizeof(buf));
           if (lineLength > 0)
           {
               ++n;
           }
           else if (lineLength == -1)
           {
               break;
           }
       }
       file.close();
   }
 
       if ( file.open( QFile::ReadOnly | QIODevice::Text ) )
 
       {
 
       QTextStream fileStream( & file );
       QString itemStr;
 
       QString str;
       str.setNum(n);
 
       slidePopup->setWindowTitle( contentName + "/" + str );
 
// slide Show
       do
       {
 
// Pause
           do
           {
               QEventLoop loop;
               QTimer::singleShot(0, &loop, SLOT(quit()));
               loop.exec();
           } while(slideShowPause);
 
                    // Play
           itemStr = fileStream.readLine();
           if( fileStream.status() >= QTextStream::ReadCorruptData )
               break;
 
           trimmedStr = itemStr.trimmed();
           if( trimmedStr.isEmpty() )
               continue;
 
           QEventLoop loop3;
           QTimer::singleShot(cfg.preferences.slideShowTimer, &loop3, SLOT(quit()));
           loop3.exec();
 
           updateShow();
 
           if(slideShowQuit)break;
 
       } while( !fileStream.atEnd() );
 
       file.close();
       }
}

Осталось решить одну глобальную проблему - нормальный выход из программы. Тем более, что данная реализация усугубляет проблему. В режиме паузы, выход тоже затруднен. Процесс слайдшоу то по существу не закрыт. Конечно в дальнейшем наверное паузу надо реализовать как то иначе, не путем пустого цикла. Может гуру подскажут иную реализацию. Ясно, что как то надо запомнить номер строки и в следующий раз начать с нее.


Название: Re: Утечка памяти
Отправлено: Spark от Июль 19, 2013, 04:04
Сделал простенько, но со вкусом:

  connect( ui.quit, SIGNAL( triggered() ),
           qApp, SLOT( quit() ) );

Код
C++ (Qt)
 connect( ui.quit, SIGNAL( triggered() ),
          this, SLOT( quitApp() ) );
 
void MainWindow::quitApp()
{
   slideShowStop = true;
   qApp->quit();
}

Вроде как работает.