#c #qt #unix
#c #qt #unix
Вопрос:
У меня есть QApplication
, которое, в зависимости от параметров командной строки, иногда на самом деле не имеет окна GUI, а просто запускается без GUI. В этом случае я хочу корректно завершить работу, если был нажат CTRL—C. В основном мой код выглядит следующим образом:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
... // parse command line options
if (no_gui) {
QObject::connect(amp;app, SIGNAL(unixSignal(int)),
amp;app, SLOT(quit()));
app.watchUnixSignal(SIGINT, true);
app.watchUnixSignal(SIGTERM, true);
}
...
return app.exec();
}
Однако это не работает. CTRL—C кажется, что это перехвачено (приложение не завершается), но оно также не завершается. Чего мне не хватает?
Комментарии:
1. Это очень хорошо задокументировано. Воспользуйтесь документацией.
Ответ №1:
Возможно, есть способ сделать это изначально с помощью Qt — я немного покопался в документах QKeySequence, прежде чем сдаться, но вы можете просто использовать signal
. На данный момент на моем компьютере нет настроек Qt / C , но у меня есть привязки к Python.
import sys, signal
from PyQt4 import QtGui
app = QtGui.QApplication(sys.argv)
signal.signal(signal.SIGINT, signal.SIG_DFL)
sys.exit(app.exec_())
Это работает и закроет приложение, когда я выполню Ctrl—C. Итак, я считаю, что ваше приложение могло бы адаптировать этот код, и в итоге получилось бы что-то вроде этого:
#include <signal.h>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
... // parse command line options
if (no_gui) {
signal(SIGINT, SIG_DFL);
}
...
return app.exec();
}
К сожалению, я не могу скомпилировать это, поэтому, вероятно, потребуется несколько исправлений, но это должно дать вам общее представление. Используя SIG_DFL
обработчик, вы даете вашей программе указание использовать действие по умолчанию, связанное с Ctrl—C.
Ответ №2:
Поскольку это не задокументировано, QApplication::watchUnixSignal
не следует использовать. И, судя по прочтению кода, он не будет работать должным образом при использовании диспетчера событий glib (который используется в Linux по умолчанию).
Однако, в целом, вы можете безопасно перехватывать сигналы Unix в приложениях Qt, вам просто нужно написать немного кода самостоятельно. В документации даже есть пример — вызов функций Qt из обработчиков сигналов Unix.
Комментарии:
1. Поскольку нет способа прокомментировать эту страницу, я просто задам здесь краткий вопрос в надежде, что он будет полезен другим: почему часть инициализации была выделена в собственный статический метод «static int setup_unix_signal_handlers()» ?
2. Я не вижу никаких причин, по которым setup_unix_signal_handlers() является статическим, и он отлично работает как часть метода экземпляра. Массивы файловых дескрипторов также могут быть нестатическими, но только при наличии синтаксиса инициализации C 11 или более поздней версии.
Ответ №3:
Вы можете использовать QApplication::instance()
(или более короткую версию макроса qApp
), оба доступны, по крайней мере, с Qt4:
#include <QApplication>
#include <csignal>
void sigHandler(int s)
{
std::signal(s, SIG_DFL);
qApp->quit();
}
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
std::signal(SIGINT, sigHandler);
std::signal(SIGTERM, sigHandler);
return app.exec();
}
Ответ №4:
Я не нашел больше QApplication::watchUnixSignal
документации, за исключением однострочника для Qt 4.0; особенно это не задокументировано в более поздних версиях Qt. Таким образом, похоже, что эта функциональность не рекламируется (и, следовательно, предполагается) для работы. При выполнении этого «Qt way», очевидно, хорош, я бы просто вернулся к использованию вместо этого системного вызова signal.
Ответ №5:
Как упоминал Jerkface Jones, похоже, что это не работает с использованием обработчика событий по умолчанию в Linux.
Если Qt использует необработанный обработчик событий Unix (не glib), Qt сразу же перехватит и обработает ^ C в своем обработчике сигналов, но сигнал unixSignal (int) не будет отправлен, пока Qt не выполнит обработку событий.
Если у вас запущен код (а не простаивает в ожидании отправки сигналов Qt), то вам нужно будет вызвать QApplication::processEvents(), чтобы Qt отправил сигнал.