Название: How To: перехват закрытия приложения на Маке Отправлено: Авварон от Февраль 02, 2012, 15:40 При закрытии приложения на маке из меню в доке Qt сразу же вызывает QCoreApplication::quit(), не давая возможности спросить пользователя или отменить закрытие приложения.
При наличии в приложении открытых window-modal окон, созданных на стеке, есть вероятность краш при закрытии приложения. Это связано с тем, что при стандартном разрушении объектов (удалении то-левел окон) будет сначала разрушаться топ-левел окно, оно будет удалять модальный диалог, для к-ого является родителем, а потом тот будет повторно разрушаться на стеке при выходе из exec(). К счастью, при закрытии приложения из дока, Qt посылает QCloseEvent QApplication'у и его можно перехватить. Ниже привожу пример перехвата и установку фокуса на одно из активных модальных окон при попытке закрытия приложения. Код: class Application : public QApplication Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Akon от Февраль 02, 2012, 21:03 имхо, некоторые вещи в Qt крупно гранулированны, например, QWidget - на редкость жирен. Например, множеству виджетов не нужен фокус ввода, им не нужны системные ресурсы и функционал, связанный с обработкой фокуса.
QWidget::parent имеет две обязанности: владение (т.е. удаляет детей) и отрисовку (детей). В некоторых либах эти обязанности разделяются на owner (владение) и parent (отрисовка). При таком подходе в случае с модальным стековым диалогом у него был бы только parent - и никаких проблем. Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Авварон от Февраль 03, 2012, 12:51 Диалоги и топлевелы это скорее исключение из правила - большая часть виджетов имеет и овнера и парента.
Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Akon от Февраль 03, 2012, 13:25 Разделение на овнера и парента покрывает тот случай (не покрывающийся одним только парентом), когда дети по паренту должны переживать этого самого парента, т.е. иметь овнера != паренту. В случае чайлд-виджетов это будет иметь место, если созданный чайлд подсовывается паренту, и парент может сдохнуть. В случае одного только парента (без овнера) проблема, конечно, легко решается, но лишние телодвижения.
Ну и если посмотреть снизу, то QObject::isWidgetType() (ну нах. на уровне QObject знать чего то там о виджетах) как раз костыть для разруливания двух обязанностей (овнера и парента) в одном поле. Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Авварон от Февраль 03, 2012, 14:42 QObject::isWidgetType нужен тупо для того, что он работает гораздо быстрее, чем каст к виджету. Явот ни разу не сталкивался с тем, что чайлдвиджеты должны удаляться после парента.
И проблема не в том, что виндоу модал диалог удаляется после парент окна, а в том, как это решить правильно для юзера - он не имеет право выключать приложение, имея модальные окна (например вопрос о том, нужно ли сохранять документ, к-ый задается при выходе). Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Akon от Февраль 03, 2012, 15:37 Цитировать QObject::isWidgetType нужен тупо для того, что он работает гораздо быстрее, чем каст к виджету. Я имел ввиду не реализацию этого метода, а контекст использования. Почему бы не сделать по аналогии QWidget::isPushButtonType()? А потому что начиная с QWidget::parent() паренту для виджета добавляется обязанность отрисовки, т.е. парент должен быть виджетом, и для этого QWidget добавляет setParent(QWidget*). Т.е. имеет место сокрытие метода.Код: QObject parent; Соответственно при разделении на овнер и парент такой костыль был бы не нужен: овнер - это QObject, парент - это QWidget, и ошибка в компайл-тайм. Цитировать Явот ни разу не сталкивался с тем, что чайлдвиджеты должны удаляться после парента. Да я тохе не сталкивался, но если подумать, то типичный пример - сменный декоратор.Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Авварон от Февраль 03, 2012, 16:25 Я имел ввиду не реализацию этого метода, а контекст использования. Почему бы не сделать по аналогии QWidget::isPushButtonType()? А потому что начиная с QWidget::parent() паренту для виджета добавляется обязанность отрисовки, т.е. парент должен быть виджетом, и для этого QWidget добавляет setParent(QWidget*). Т.е. имеет место сокрытие метода. Еще раз, QObject::isWidgetType нужен чтобы повысить производительность кода. Код: if (object->isWidgetType()) { Код: QWidget *w = qobject_cast<QWidget*>(object); Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Igors от Февраль 03, 2012, 19:01 Статья/урок по делу, попытка конструктивной критики:
- причем здесь Mac? Судя по изложению - проблема на любой платформе - trуQuit сделано на соплях, не хватает солидности. А если один модал испустил другой, так что, хватать первый? Или нет вообще модалов, так что, потеряем последние изменения? Где вообще (virtual) CanClose() ? По поводу приведения (isWidgetType и.т п.) - разумно обсудить в отдельной теме, здесь это только мешает Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Авварон от Февраль 03, 2012, 20:56 Статья/урок по делу, попытка конструктивной критики: Вся соль тут не в переборе модалов (я думаю с этим справятся все) а в том, как отследить на маке попытку закрыть приложение из дока. Это не описано в доках и помогло только курение сорцов. Вместо tryQuit() может быть любой пользовательский код. И в общем случае, его нужно звать из нескольких мест (например из клоз евента глав окна), не только из перехвата.- причем здесь Mac? Судя по изложению - проблема на любой платформе - trуQuit сделано на соплях, не хватает солидности. А если один модал испустил другой, так что, хватать первый? Или нет вообще модалов, так что, потеряем последние изменения? Где вообще (virtual) CanClose() ? Если один модал открыл другой, то первым в списке будет второй (так устроен allWidgets - он хранит виджеты в порядке, обратным порядку создания). Вся соль тут в этом куске кода: Код: bool Application::event(QEvent *e) Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Akon от Февраль 03, 2012, 21:04 Цитировать Еще раз, QObject::isWidgetType нужен чтобы повысить производительность кода. Да, согласен. Использование этого метода в setParent() непринципиальный момент.Вам очевидно не приходилось вешать эвент фильтр на куаппликейшн с целью перехвата событий виджетов. Там каждая милисекунда важна, тк событый проходят через фильтр тысячи. И тогда, и только тогда этот метод нужен, когда каст слишком затратен. Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Igors от Февраль 04, 2012, 05:56 А почему не решить это через QWidget::closeEvent (virtual), или он здесь не приходит?
Название: Re: How To: перехват закрытия приложения на Маке Отправлено: Авварон от Февраль 04, 2012, 10:15 Куда он будет приходить, если окон нет?
|