【03】Cockatrice應用入口與標準初始化流程

目錄

 

簡介

源碼分析

[1]Qt應用程序標準框架

[2]日誌管理模塊

[3]配置管理模塊

[4]主題管理模塊

[5]音頻引擎模塊

[6]數據庫引擎模塊

[7]翻譯(Qt國際化)模塊

[8]RNG_SFMT模塊(不知道幹啥的,以後慢慢分析)


簡介

一般源碼分析都是從main開始的,此次自然也不例外。我們來分析/Cockatrice/cockatrice/src/main.cpp。main()中主要實現了Qt應用程序的標準流程,並初始化了一些程序模塊。我們也得以管中窺豹,從中初步瞭解Cockatrice的模塊劃分與設計思路。

源碼分析

主要模塊如下所示:

[1]Qt應用程序標準框架

標準的Qt GUI應用程序寫法,很傳統但也很經典。main中主要實現了界面參數初始化,資源加載與功能模塊實例化。

QSystemTrayIcon *trayIcon;

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);---->在棧上創建QApplication實例

    QObject::connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));---->綁定lastWindowClosed()信號,保證最後一個窗口關閉時觸發quit()最終退出程序

    qInstallMessageHandler(CockatriceLogger);---->註冊日誌處理函數

#ifdef Q_OS_WIN
    app.addLibraryPath(app.applicationDirPath() + "/plugins");---->添加指定的函數庫加載路徑
#endif

    // These values are only used by the settings loader/saver
    // Wrong or outdated values are kept to not break things
    QCoreApplication::setOrganizationName("Cockatrice");---->設置組織,公司,應用,版本名稱
    QCoreApplication::setOrganizationDomain("cockatrice.de");
    QCoreApplication::setApplicationName("Cockatrice");
    QCoreApplication::setApplicationVersion(VERSION_STRING);

#ifdef Q_OS_MAC
    qApp->setAttribute(Qt::AA_DontShowIconsInMenus, true);---->設置是否在菜單中添加本應用
#endif

    。。。

    QCommandLineParser parser;---->用QCommandLineParser來設置並處理用戶傳參
    parser.setApplicationDescription("Cockatrice");---->設置應用描述
    parser.addHelpOption();---->添加幫助選項("-h" 或 "--help")
    parser.addVersionOption();---->添加版本選項("-v" 或 "--version") 

    parser.addOptions(
        {{{"c", "connect"}, QCoreApplication::translate("main", "Connect on startup"), "user:pass@host:port"},
         {{"d", "debug-output"}, QCoreApplication::translate("main", "Debug to file")}});---->添加用戶自定義選項

    parser.process(app);---->將以上所有解析選項添加到QApplication實例

    if (parser.isSet("debug-output")) {
        Logger::getInstance().logToFile(true);---->如果用戶輸入-d則啓用日誌
    }

    。。。

    QLocale::setDefault(QLocale::English);---->設置默認語言環境爲English

    qsrand(QDateTime::currentDateTime().toTime_t());---->調用系統當前時間生成隨機數種子
    qDebug("main(): starting main program");

    MainWindow ui;---->在棧上創建MainWindow實例
    if (parser.isSet("connect")) {
        ui.setConnectTo(parser.value("connect"));---->如果用戶輸入-c參數,將該參數傳入MainWindow實例
    }
    qDebug("main(): MainWindow constructor finished");

    ui.setWindowIcon(QPixmap("theme:cockatrice"));---->設置應用程序左上角顯示的圖標

    。。。

    ui.show();---->顯示MainWindow
    qDebug("main(): ui.show() finished");

    app.setAttribute(Qt::AA_UseHighDpiPixmaps);---->啓動針對高分辨率Retina的顯示支持
    app.exec();---->運行QApplication實例,開啓事件循環,程序阻塞在此處直到quit()

    qDebug("Event loop finished, terminating...");

    。。。

    PingPixmapGenerator::clear();---->
    CountryPixmapGenerator::clear();---->
    UserLevelPixmapGenerator::clear();---->

    return 0;
}

[2]日誌管理模塊

調用了Qt提供的logger handle來實現日誌功能。

後續單獨分析Qt的日誌管理。

static void CockatriceLogger(QtMsgType type, const QMessageLogContext &ctx, const QString &message)
{
    Logger::getInstance().log(type, ctx, message);
}

int main(int argc, char *argv[])
{
    。。。

    qInstallMessageHandler(CockatriceLogger);

    。。。
}

[3]配置管理模塊

SettingCache作爲一個獨立的功能模塊,後續單獨分析。

這裏用設備MAC地址生成了hash摘要作爲用戶ID,也是很經典的寫法。

SettingsCache *settingsCache;

QString const generateClientID()
{
    QString macList;
    foreach (QNetworkInterface interface, QNetworkInterface::allInterfaces()) {
        if (interface.hardwareAddress() != "")
            if (interface.hardwareAddress() != "00:00:00:00:00:00:00:E0")
                macList += interface.hardwareAddress() + ".";
    }
    QString strClientID = QCryptographicHash::hash(macList.toUtf8(), QCryptographicHash::Sha1).toHex().right(15);
    return strClientID;
}

int main(int argc, char *argv[])
{
    。。。

    settingsCache = new SettingsCache;

    。。。

    settingsCache->setClientID(generateClientID());

    。。。

    app.exec();

    。。。
    
    delete settingsCache;

    。。。
}

[4]主題管理模塊

ThemeManager作爲一個獨立的功能模塊,後續單獨分析。

ThemeManager *themeManager;

int main(int argc, char *argv[])
{
    。。。

    themeManager = new ThemeManager;

    。。。

    app.exec();

    。。。

    delete themeManager;

    。。。
}

[5]音頻引擎模塊

SoundEngine作爲一個獨立的功能模塊,後續單獨分析。

SoundEngine *soundEngine;

int main(int argc, char *argv[])
{
    。。。

    soundEngine = new SoundEngine;

    。。。

    app.exec();

    。。。

    delete soundEngine;

    。。。
}

[6]數據庫引擎模塊

CardDatabase作爲一個獨立的功能模塊,後續單獨分析。

SpoilerBackgroundUpdater用來幹什麼呢?後續再分析。

CardDatabase *db;

int main(int argc, char *argv[])
{
    。。。

    db = new CardDatabase;

    。。。

    // If spoiler mode is enabled, we will download the spoilers
    // then reload the DB. otherwise just reload the DB
    SpoilerBackgroundUpdater spoilerBackgroundUpdater;    

    。。。

    app.exec();

    。。。

    delete db;

    。。。
}

[7]翻譯(Qt國際化)模塊

調用了Qt提供的QTranslator來實現I18N,後續另起一篇博客單獨分析Qt國際化。

這裏qApp是指向當前QApplication的指針,只有QApplication程序可以調用qApp。

QTranslator *translator, *qtTranslator;
const QString translationPrefix = "cockatrice";
QString translationPath;

void installNewTranslator()
{
    QString lang = settingsCache->getLang();

    qtTranslator->load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
    qApp->installTranslator(qtTranslator);
    translator->load(translationPrefix + "_" + lang, translationPath);
    qApp->installTranslator(translator);
    qDebug() << "Language changed:" << lang;
}

int main(int argc, char *argv[])
{
    。。。

#ifdef Q_OS_MAC
    translationPath = qApp->applicationDirPath() + "/../Resources/translations";---->設置翻譯文件加載路徑
#elif defined(Q_OS_WIN)
    translationPath = qApp->applicationDirPath() + "/translations";
#else // linux
    translationPath = qApp->applicationDirPath() + "/../share/cockatrice/translations";
#endif

    。。。

    qtTranslator = new QTranslator;
    translator = new QTranslator;
    installNewTranslator();

    。。。

    app.exec();

    。。。

    delete qtTranslator;
    delete translator;

    。。。
}

[8]RNG_SFMT模塊(不知道幹啥的,以後慢慢分析)

RNG_Abstract *rng;

int main(int argc, char *argv[])
{
    。。。

    rng = new RNG_SFMT;

    。。。

    app.exec();

    。。。

    delete rng;

    。。。
}

下一篇我們來分析Cockatrice的Client端界面結構。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章