Версия для печати темы
Форум на CrossPlatform.RU _ Qt Ввод/Вывод, Сеть. Межпроцессное взаимодействие _ Как закрыть файл при закрытии приложения
Автор: silver47 5.4.2011, 9:35
Приложение пишет лог в файл. Необходимо чтобы при закрытии приложения, собственно, этот лог сохранился. Не могу отловить событие закрытия
QObject::connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(appClose()));
. Деструктор тоже не выполняется. Может кто может помочь?
Спасибо.
Автор: abc 5.4.2011, 9:54
окну нужно присвоить флаг deleteOnClose, вроде так пишется, тогда деструктор выполнится
ещё
closeEvent - у твоего главного окна есть такая виртуальная функция
а ещё стоит сохранять лог периодически, потому что программа может завершиться аварийно
не вижу ничего плохого в том, чтобы с каждой записью открывать и закрывать файл
Автор: silver47 5.4.2011, 10:30
Цитата(abc @ 5.4.2011, 11:54)
окну нужно присвоить флаг deleteOnClose, вроде так пишется, тогда деструктор выполнится
ещё
closeEvent - у твоего главного окна есть такая виртуальная функция
а ещё стоит сохранять лог периодически, потому что программа может завершиться аварийно
не вижу ничего плохого в том, чтобы с каждой записью открывать и закрывать файл
По поводу того, чтобы с каждой записью открывать и закрывать файл, сам только подумал и переделал уже. А вот про deleteOnClose, как присвоить его окну?
Автор: wiz29 5.4.2011, 11:02
QWidget* pWidget(new QWidget);
pWidget->setAttribute (Qt::WA_DeleteOnClose, true);
раз у тебя оконное приложение попробуй обработать сигнал от QApplication : void lastWindowClosed ().
Автор: silver47 5.4.2011, 11:03
Цитата(wiz29 @ 5.4.2011, 13:02)
QWidget* pWidget(new QWidget);
pWidget->setAttribute (Qt::WA_DeleteOnClose, true);
раз у тебя оконное приложение попробуй обработать сигнал от QApplication : void lastWindowClosed ().
У меня оно не наследуется от QWidget. У меня нет окон - нечего закрывать.
Пока сделал так, чтобы файл с логом был всегда закрыт. открывается лишь на незначительное время для добавления записи, для решения задачи этого вполне достаточно. Но может все-же можно как-то понять, что твое приложение закрыли тем или иным образом? Вроде встречал на каком-то форуме, что платформонезависимо нельзя, но это касается только консольных приложений.
Автор: wiz29 5.4.2011, 11:29
можешь линкануть код функции main?
просто в любом случае одной обработкой сигнала от QCoreApplication нельзя отделаться.
Автор: silver47 5.4.2011, 11:39
Цитата(wiz29 @ 5.4.2011, 13:29)
можешь линкануть код функции main?
main, в моем случае не делает ничего, кроме создания экземпляра класса и запуска лупа.
#include <QtCore/QCoreApplication>
#include <QTextCodec>
#include "mainapp.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//***************************************************************
QTextCodec *codec=QTextCodec::codecForName("UTF8");
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
//***************************************************************
MainApp aplication;
QObject::connect(&aplication, SIGNAL(connectFailed()), &a, SLOT(quit()));
return a.exec();
}
Автор: wiz29 5.4.2011, 11:50
объект "logger" синглтон в приложении?
если это так то все просто нужно немного модифицировать код твоего main и все будет в "шоколаде".
строку return a.exec(); поменяй на 2:
int ret = a.exec();
//закрыть логер
и вначале обязательно сделай переопределение стандартного обработчика "terminate handler function", это поможет тебе при завершении логера в случае непредвиденного завершения приложения. инфу можно посмотреть тут http://www.cplusplus.com/reference/std/exception/set_terminate/
Автор: silver47 5.4.2011, 12:02
Цитата(wiz29 @ 5.4.2011, 13:50)
объект "logger" синглтон в приложении?
если это так то все просто нужно немного модифицировать код твоего main и все будет в "шоколаде".
строку return a.exec(); поменяй на 2:
int ret = a.exec();
//закрыть логер
и вначале обязательно сделай переопределение стандартного обработчика "terminate handler function", это поможет тебе при завершении логера в случае непредвиденного завершения приложения. инфу можно посмотреть тут http://www.cplusplus.com/reference/std/exception/set_terminate/
Простите. Совсем не понял. Объект "логгер" пишет в файл события, которые происходят при обработке данных другими классами, они кидают ему их посредством сигналов. Другие классы должны выполняться в лупе, то есть всегда, это не парсер чего-либо. Если они выполнили свою работу они уничтожаются, родительский класс создает новый объект, как только работа появиться. Надеюсь понятно объяснил.
Автор: abc 5.4.2011, 12:02
Wiz,
имеешь ввиду?
int res = a.exec();
file.close();
return res;
про terminate только на днях прочёл, оказывается, вот где можно использовать)
Автор: wiz29 5.4.2011, 12:22
Цитата(silver47 @ 5.4.2011, 12:02)
Простите. Совсем не понял. Объект "логгер" пишет в файл события, которые происходят при обработке данных другими классами, они кидают ему их посредством сигналов. Другие классы должны выполняться в лупе, то есть всегда, это не парсер чего-либо. Если они выполнили свою работу они уничтожаются, родительский класс создает новый объект, как только работа появиться. Надеюсь понятно объяснил.
Невижу никаких проблем с тем чтобы ваш "логгер" был глобальным в приложении (даже если он потомок QObject) или же у вас есть некий общий файл в который все "сливается" с разных объектов (т.е. разделенный доступ к лог файлу)? (тогда здесь не все понятно с синхронизацией доступа к файлу).
p.s. Что конкретно не понятно? (синглтон - объект одиночка для всего приложения, в qt например, это QCoreApplication объект, как правило имеет метод instance() или нечто подобное)
кстати обработка сигнала aboutToQuit нормально работает только при корректном завершении приложения: вызовом метода QCoreApplication::instance()->quit(); в остальных случая код завершения не 0 и сигнал не генерится.
Автор: silver47 5.4.2011, 12:41
Логгер глобальный и один для всех объектов.
Конкретно не понятно как работает set_terminate.
По примеру мы устанавливаем метод, который будет вызываться в случае ненормального завершения программы. Это так? зачем тогда заменять a.exec(); на int res = a.exec();?
Если сделать все чисто по примеру, то вроде как не работает. Добавил консоль в сборку:
#include <QtCore/QCoreApplication>
#include <iostream>
#include <QTextCodec>
#include "mainapp.h"
void abnormalExit(){
std::cout << "Abnormal exit";
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//***************************************************************
QTextCodec *codec=QTextCodec::codecForName("UTF8");
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
//***************************************************************
MainApp aplication;
QObject::connect(&aplication, SIGNAL(connectFailed()), &a, SLOT(quit()));
std::set_terminate(abnormalExit);
return a.exec();
}
По Ctrl+C тихо закрывается. Ничего не оставляет после себя. Если вставить throw; до return a.exec() то исключение вызывает метод abnormalExit.
Автор: wiz29 5.4.2011, 13:26
1. менять не обязательно.
2. std::set_terminate работает следующим образом: если в какойто части программы возникает исключительная ситуация exception и данная ситуация не обработана ни одним перехватчиком искл. ситуаций то приложение аварийно завершается, перед своим завершением вызываться некая специальная глобальная функция terminate handler , собственно указатель на нее и устанавливает данный метод (это коротко , на "палцах") за более подробной инфой обратитесь к справочникам по C++. При закрытии консольного окна "через крестик" реально сам не смог отловить завершение.
Средставми Qt закрытие консоли с помощью Сtr + C или Alt + F4 скорее всего обработать не выйдет, придется писать платформозависимый код. (других путей пока не вижу)
Автор: Алексей1153 5.4.2011, 17:05
вообще говоря, достаточно просто всегда записывать данные в файл. Когда приложение умирает, система закрывает все дескрипторы, занятые приложением - файл автоматом закроется. По крайней мере в винде так
Автор: abc 5.4.2011, 19:33
Алексей, что происходит здесь?
http://www.forum.crossplatform.ru/index.php?showtopic=6720
Автор: Алексей1153 5.4.2011, 19:42
abc,
ну да, если что-то не успело записаться, то оно и не сохранится. А по топику в ссылке, навскидку:
вызывать flush после каждой записи - это гарантия перекидывания в файл из внутренних буферов. А close там ни при чём ИМХО
опять же, тонкости работы линукса я не знаю, а в винде файл просто закроется и ничего не потеряется из уже в него записанного
Автор: abc 5.4.2011, 20:06
я в винде компилировал, QString не пишется, QPixmap пишется... Как может не успеть записаться? дальше этих двух типов не проверял
Автор: Алексей1153 5.4.2011, 20:17
abc, а с flush тоже не пишется ?
Автор: abc 5.4.2011, 20:20
не пробовал, но если даже пишется, то вопрос изменится на - почему QString записать нужен flush, а QPixmap нет...
Автор: Алексей1153 5.4.2011, 20:25
abc, возможно, оператор << у них по разному устроен - в одном flush вызывается, в другом нет
Автор: abc 5.4.2011, 20:36
хмм, ладно, надо провести более качественные проверки для продолжения беседы)
Автор: silver47 6.4.2011, 6:05
Цитата(Алексей1153 @ 5.4.2011, 22:17)
abc, а с flush тоже не пишется ?
В случае, если используется QTextStream для вывода в файл, то flush бесполезен.
void QTextStream::flush ()
Flushes any buffered data waiting to be written to the device.
If QTextStream operates on a string, this function does nothing.
Если писать в файл напрямую, не используя QTextStream, то QFile::flush решает проблему. Я ее все-же предпочел решить по другому - держать файл закрытым (в лог сыплются лишь сообщения об ошибках), теперь вопрос в другом, так сказать для общего развития: Как узнать что твое приложения прибили тем или иным способом? Как я понимаю платформонезависимо никак.
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)