主函数里面调用的是:
看下原理:
qcoreapplication.h中
#define qApp QCoreApplication::instance()
static QCoreApplication *self;
static QCoreApplication *instance() { return self; }
QCoreApplication构造
QCoreApplication::QCoreApplication(int &argc, char **argv)
: QObject(*new QCoreApplicationPrivate(argc, argv, _internal))
{
d_func()->q_ptr = this;
d_func()->init();
QCoreApplicationPrivate::eventDispatcher->startingUp();
}
void QCoreApplicationPrivate::init()
{
Q_Q(QCoreApplication);
//如果self已经存在,直接中断退出程序
Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object");
//self这里指向q_ptr即this
QCoreApplication::self = q;
}
结合构造函数我们知道:
QCoreApplication app(argc, argv);定义app后self就指向了app;
并且一个程序就只能定义一个app对象。
qguiapplication.h中
#include <QtCore/qcoreapplication.h> //引用qcoreapplication.h
#if defined(qApp)
#undef qApp //先取消qApp宏定义
#endif
#define qApp (static_cast<QGuiApplication *>(QCoreApplication::instance()))
//重新定义qApp宏定义,指向QGuiApplication
#if defined(qGuiApp)
#undef qGuiApp
#endif
#define qGuiApp (static_cast<QGuiApplication *>(QCoreApplication::instance()))
//多定义了个,qGuiApp宏定义,与qApp一样功能
qapplication.h中
#include <QtCore/qcoreapplication.h> //引用qcoreapplication.h
#include <QtGui/qguiapplication.h> //qguiapplication.h
#if defined(qApp)
#undef qApp //先取消qApp宏定义
#endif
#define qApp (static_cast<QApplication *>(QCoreApplication::instance()))
//重新定义qApp宏定义QApplication
QCoreApplication::QCoreApplication(int &argc, char **argv)
: QObject(*new QCoreApplicationPrivate(argc, argv, _internal))
{
d_func()->q_ptr = this;
d_func()->init();
QCoreApplicationPrivate::eventDispatcher->startingUp();
}
QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint flags)
: QObjectPrivate(),argc(aargc)
, argv(aargv)
, application_type(QCoreApplicationPrivate::Tty) //注意这里的app类型是tty
, in_exec(false)
, aboutToQuitEmitted(false)
, threadData_clean(false)
{
app_compile_version = flags & 0xffffff;
QCoreApplicationPrivate::is_app_closing = false;
QThread *cur = QThread::currentThread();
}
void QCoreApplicationPrivate::init()
{
//这里断言,一个程序只能创建一个app,只能创建一个app对象
Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object");
QCoreApplication::self = q;
auto thisThreadData = threadData.loadRelaxed();
eventDispatcher = thisThreadData->eventDispatcher.loadRelaxed();
if (!eventDispatcher)
createEventDispatcher();//创建事件分发器
Q_ASSERT(eventDispatcher);
if (!eventDispatcher->parent()) {
eventDispatcher->moveToThread(thisThreadData->thread.loadAcquire());
eventDispatcher->setParent(q);
}
thisThreadData->eventDispatcher = eventDispatcher;
eventDispatcherReady();
//解析命令行参数
processCommandLineArguments();
qt_call_pre_routines();
qt_startup_hook();
#ifndef QT_BOOTSTRAPPED
if (Q_UNLIKELY(qtHookData[QHooks::Startup]))
reinterpret_cast<QHooks::StartupCallback>(qtHookData[QHooks::Startup])();
#endif
is_app_running = true; // No longer starting up.
}
创建事件分发器流程
void QCoreApplicationPrivate::createEventDispatcher()
{
Q_Q(QCoreApplication);
QThreadData *data = QThreadData::current();
Q_ASSERT(!data->hasEventDispatcher());
eventDispatcher = data->createEventDispatcher();
eventDispatcher->setParent(q);
}
QAbstractEventDispatcher *QThreadData::createEventDispatcher()
{
QAbstractEventDispatcher *ed = QThreadPrivate::createEventDispatcher(this);
eventDispatcher.storeRelease(ed);
ed->startingUp();
return ed;
}
//根据平台创建不同的事件分发器
QAbstractEventDispatcher *QThreadPrivate::createEventDispatcher(QThreadData *data)
{
Q_UNUSED(data);
#if defined(Q_OS_DARWIN)
bool ok = false;
int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
if (ok && value > 0)
return new QEventDispatcherCoreFoundation;
else
return new QEventDispatcherUNIX;
#elif !defined(QT_NO_GLIB)
const bool isQtMainThread = data->thread.loadAcquire() == QCoreApplicationPrivate::mainThread();
if (qEnvironmentVariableIsEmpty("QT_NO_GLIB")
&& (isQtMainThread || qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB"))
&& QEventDispatcherGlib::versionSupported())
return new QEventDispatcherGlib;
else
return new QEventDispatcherUNIX;
#else
return new QEventDispatcherUNIX;
#endif
}
//QEventDispatcherGlib
QEventDispatcherGlib::QEventDispatcherGlib(QObject *parent)
: QAbstractEventDispatcher(*(new QEventDispatcherGlibPrivate), parent)
{
}
QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(GMainContext *context)
: mainContext(context)
{
//注册处理函数
postEventSource = postEventSourceFuncs;
socketNotifierSource = socketNotifierSourceFuncs;
timerSource = timerSourceFuncs;
idleTimerSource = idleTimerSourceFuncs;
}
static GSourceFuncs postEventSourceFuncs = {
postEventSourcePrepare,
postEventSourceCheck,
postEventSourceDispatch,
nullptr,
nullptr,
nullptr
};
static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer)
{
GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s);
source->lastSerialNumber = source->serialNumber.loadRelaxed();
QCoreApplication::sendPostedEvents();
source->d->runTimersOnceWithNormalPriority();
return true; // i dunno, george...
}
void QCoreApplication::sendPostedEvents(QObject *receiver, int event_type)
{
QThreadData *data = QThreadData::current();
QCoreApplicationPrivate::sendPostedEvents(receiver, event_type, data);
}
设置和清除某属性,如果on为真,则设置属性attribute;否则清除该属性。
返回是否设置了属性
设置了此标志后程序执行将会以拥有者的身份去执行。
如果allow为false(默认值),并且Qt检测到应用程序正在使用与实际用户id不同的有效用户id运行,则在创建QCoreApplication实例时将终止应用程序。
注意:强烈建议不要启用此选项,因为它会引入安全风险。
static bool isSetuidAllowed()
返回是否设置了uid属性
使用notify()函数将事件事件直接发送给接收者。同步执行,返回从事件处理程序返回的值。
事件发送后不会被删除。通常的方法是在栈上创建事件
QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);
QApplication::sendEvent(mainWindow, &event);
将事件事件(以对象接收者作为事件接收者)添加到事件队列并立即返回。异步执行。
post事件队列将获得事件的所有权,并在事件被发布后将其删除。事件必须在堆上分配,
在事件发布之后再访问它是不安全的。
QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress, pos, 0, 0, 0);
QApplication::postEvent(mainWindow, &event);
立即调度所有先前在QCoreApplication::postEvent()中排队的事件,这些事件属于对象接收者receiver,并且事件类型为event_type。
注意:这个方法必须从其QObject参数receiver所在的线程中调用。
static QString applicationDirPath();//返回程序所在目录
static QString applicationFilePath();//返回程序路径
static qint64 applicationPid() ;//返回当前程序的进程号
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug()<<a.applicationDirPath();
qDebug()<<a.applicationFilePath();
qDebug()<<a.applicationPid();
return a.exec();
}
输出:
"E:/workspace/debug"
"E:/workspace/debug/guitest.exe"
5272
一般用不到这些函数
static void setOrganizationDomain(const QString &orgDomain);
static QString organizationDomain();
static void setOrganizationName(const QString &orgName);
static QString organizationName();
static void setApplicationName(const QString &application);
static QString applicationName();//不设置,默认返回程序名称
static void setApplicationVersion(const QString &version);
static QString applicationVersion();
[static] QStringList QCoreApplication::arguments()函数
返回命令行参数,前提构造时必须传入argc和argv
int main(int argc, char *argv[])
{
QApplication a(argc, argv);//这里传入了argc和argv
qDebug()<<a.arguments();
return a.exec();
}
./demo.exe arg1 arg2 3 4
输出:
("E:\workspace\\debug\demo.exe", "arg1", "arg2", "3", "4")
设置运行时库所搜的路径。所有现有的路径将被删除,路径列表将由paths中给出的路径组成。
返回运行时搜索的库路径
添加运行时库所搜的路径
移除某个运行时的搜索路径
返回s的翻译版本
s,需要翻译的字符串
c,消歧字符串
n,包含复数的字符串的值n;
如果没有合适的翻译字符串可用,则返回QString::fromUtf8(sourceText)。
此函数包含的字符串将作为需要翻译的字符串,被lupdate收集到翻译文件中(见下面所述)
1.新增要生成的翻译文件
pro文件里面添加TRANSLATIONS = zh.ts en.ts,新增要生成翻译文件zh.ts en.ts
2.生成翻译文件
选择:qt creator工具->外部->qt语言家->lupdate(或者手动执行lupdate + pro文件)
lupdate根据pro配置自动搜索生成需要翻译的文件: zh.ts en.ts (此时的文件都是未翻译的文件)
3.翻译
使用qt Linguist打开ts文件完成翻译并保存即可
打开的时候会让你选择源字符串语言类型和目标语言类型
zh.ts里面的源字符串翻译成中文
en.ts里面的源字符串翻译成英文
未翻译的字符串未undefined状态,可以手动文本方式打开ts文件查看
4、生成二进制翻译文件
选择:qt creator工具->外部->qt语言家->lrelease
生成二进制的zh.qm,en.qm文件
5.使用翻译文件
QTranslator的installTranslator函数装载翻译文件
#include <QTranslator>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTranslator translator;
translator.load("zh.qm");
translator.load("en.qm");//可以加载多个,翻译时先从最近加载的找,找到就返回
a.installTranslator(&translator);
return a.exec();
}
将翻译文件translationFile添加到要用于翻译的翻译文件列表。
可以安装多个翻译文件。
搜索翻译的顺序与它们的安装顺序相反,因此首先搜索最近安装的翻译文件,最后搜索安装的第一个翻译文件。
一旦找到包含匹配字符串的翻译,搜索就会停止。
并且其会生成一个LanguageChange事件(LanguageChange事件只会发给widget类型的对象)
QWidgetm默认没有处理QEvent::LanguageChange事件
bool QWidget::event(QEvent *event)
{
...
case QEvent::LanguageChange:
changeEvent(event);//调用changeEvent
{
QList<QObject*> childList = d->children;
for (int i = 0; i < childList.size(); ++i) {
QObject *o = childList.at(i);
if (o)
QCoreApplication::sendEvent(o, event);
}
}
update();
break;
...
}
//里面没有处理QEvent::LanguageChange,需要我们自己实现
void QWidget::changeEvent(QEvent * event)
{
switch(event->type()) {
case QEvent::EnabledChange: {
...
break;
}
case QEvent::FontChange:
case QEvent::StyleChange: {
...
break;
}
case QEvent::PaletteChange:
update();
break;
case QEvent::ThemeChange:
...
break;
default:
break;
}
}
从此应用程序使用的翻译文件列表中删除翻译文件translationFile。
(它不会从文件系统中删除翻译文件。)
函数成功返回true,失败返回false。
也会触发QEvent::LanguageChange事件
通过查询已安装的翻译文件,返回翻译文本。
context通常是一个类名(例如,“MyDialog”),
QObject::tr(“text123”)时context为"QObject",qApp->translate(“QObject”,“text123”);
QWidget::tr(“text123”)时context为"QWidget" ,qApp->translate(“QObject”,“text123”);
每个继承QObject并定义宏Q_OBJECT的类,元编译时都会自动生成静态的tr函数,
还可以看ts文件里面对应字符串节点下面的QObject节点的值就是context需要填写的值。
key就是翻译的原字符串,即代码里面tr(“str”),包含的字符串"str"
disambiguation是一个标识字符串,用于在相同上下文中以不同的角色使用相同的源文本。
语言切换就是先removeTranslator然后installTranslator新的翻译文件,触发重新翻译即可。
触发重新翻译:
void MyWidget::changeEvent(QEvent * event)
{
if(event->type() == QEvent::LanguageChange)
{
//重新获取翻译字符串
qDebug()<<qApp->translate("MyWidget","obj1");
}
QWidget::changeEvent(event);
}
为应用程序在主线程中接收的所有本机事件安装事件筛选器filterObj。
事件过滤器filterObj通过它的 nativeEventFilter()函数接收事件,
对于主线程中接收到的所有本机事件,都会调用该函数。
如果安装了多个事件筛选器,则首先激活最后安装的筛选器。
注意:这里设置的过滤函数接收本地消息,即MSG或XCB事件结构。
注意:当Qt::AA_PluginApplication属性被设置时,本机事件过滤器将在应用程序中被禁用。
由于其继承QObject所以其也有installEventFilter()函数。
void QCoreApplication::installNativeEventFilter(QAbstractNativeEventFilter *filterObj)
{
if (QCoreApplication::testAttribute(Qt::AA_PluginApplication)) {
qWarning("Native event filters are not applied when the Qt::AA_PluginApplication attribute is set");
return;
}
eventDispatcher->installNativeEventFilter(filterObj);
}
void QAbstractEventDispatcher::installNativeEventFilter(QAbstractNativeEventFilter *filterObj)
{
Q_D(QAbstractEventDispatcher);
// clean up unused items in the list
d->eventFilters.removeAll(0);
d->eventFilters.removeAll(filterObj);
d->eventFilters.prepend(filterObj);
}
bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
{
if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0))
{
//不过滤本地消息则将消息转话成qt事件派发
TranslateMessage(&msg);//将win或x11事件转换成QEvent事件
DispatchMessage(&msg);//派发消息
}
activateEventNotifiers();
}
bool QAbstractEventDispatcher::filterNativeEvent(const QByteArray &eventType, void *message, long *result)
{
Q_D(QAbstractEventDispatcher);
if (!d->eventFilters.isEmpty()) {
// Raise the loopLevel so that deleteLater() calls in or triggered
// by event_filter() will be processed from the main event loop.
QScopedScopeLevelCounter scopeLevelCounter(d->threadData);
for (int i = 0; i < d->eventFilters.size(); ++i) {
QAbstractNativeEventFilter *filter = d->eventFilters.at(i);
if (!filter)
continue;
if (filter->nativeEventFilter(eventType, message, result))
return true;
}
}
return false;
}
移除本机事件过滤器
void QAbstractEventDispatcher::removeNativeEventFilter(QAbstractNativeEventFilter *filter)
{
Q_D(QAbstractEventDispatcher);
for (int i = 0; i < d->eventFilters.count(); ++i) {
if (d->eventFilters.at(i) == filter) {
d->eventFilters[i] = 0;
break;
}
}
}
启动事件处理。
进入主事件循环并等待,直到exit()被调用。
返回传递给exit()的值(如果通过quit()调用exit(),该值为0)。
必须调用此函数来启动事件处理。
int QCoreApplication::exec()
{
if (!QCoreApplicationPrivate::checkInstance("exec"))
return -1;
QThreadData *threadData = self->d_func()->threadData;
if (threadData != QThreadData::current()) {
qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
return -1;
}
if (!threadData->eventLoops.isEmpty()) {
qWarning("QCoreApplication::exec: The event loop is already running");
return -1;
}
threadData->quitNow = false;
QEventLoop eventLoop;
self->d_func()->in_exec = true;
self->d_func()->aboutToQuitEmitted = false;
int returnCode = eventLoop.exec();//开启事件循环
threadData->quitNow = false;
if (self)
self->d_func()->execCleanup();
return returnCode;
}
int QEventLoop::exec(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
auto threadData = d->threadData.loadRelaxed();
if (threadData->quitNow)
return -1;
if (d->inExec) {
qWarning("QEventLoop::exec: instance %p has already called exec()", this);
return -1;
}
d->exit.storeRelease(false);//设置false
// remove posted quit events when entering a new event loop
QCoreApplication *app = QCoreApplication::instance();
if (app && app->thread() == thread())
QCoreApplication::removePostedEvents(app, QEvent::Quit);
//一直循环等待事件
while (!d->exit.loadAcquire())
processEvents(flags | WaitForMoreEvents | EventLoopExec);
ref.exceptionCaught = false;
return d->returnCode.loadRelaxed();
}
调用此函数后,应用程序离开主事件循环并从调用exec()返回。
注意,与同名的C库函数不同,这个函数返回给调用者并事件处理停止。
void QCoreApplication::exit(int returnCode)
{
if (!self)
return;
QThreadData *data = self->d_func()->threadData.loadRelaxed();
data->quitNow = true;
for (int i = 0; i < data->eventLoops.size(); ++i) {
QEventLoop *eventLoop = data->eventLoops.at(i);
eventLoop->exit(returnCode);
}
}
void QEventLoop::exit(int returnCode)
{
Q_D(QEventLoop);
auto threadData = d->threadData.loadAcquire();
if (!threadData->hasEventDispatcher())
return;
d->returnCode.storeRelaxed(returnCode);
d->exit.storeRelease(true);//设置true
threadData->eventDispatcher.loadRelaxed()->interrupt();
}
告诉应用程序退出并返回代码0(成功)。相当于调用QCoreApplication::exit(0)。
void QCoreApplication::quit()
{
exit(0);
}
此信号在应用程序即将退出主事件循环时发出
这可能发生在应用程序内部调用quit()之后,也可能发生在用户关闭整个桌面会话之后。
注意:这是一个私人信号。它可以用于信号连接,但不能由用户发出。
建议您将清理代码连接到aboutToQuit()信号,而不是将其放在应用程序的main()函数中,因为在某些平台上exec()调用可能不会返回。
void QCoreApplicationPrivate::execCleanup()
{
threadData.loadRelaxed()->quitNow = false;
in_exec = false;
if (!aboutToQuitEmitted)
emit q_func()->aboutToQuit(QCoreApplication::QPrivateSignal());
aboutToQuitEmitted = true;
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
}
exec()退出时发送此信号
QApplication a(argc, argv);
QObject::connect(&a,&QApplication::aboutToQuit,[](){
qDebug()<<"ewcv aboutToQuit signal " ;
});
bool QCoreApplication::event(QEvent *e)
{
if (e->type() == QEvent::Quit) {
quit();
return true;
}
return QObject::event(e);
}