目錄
簡介
一般源碼分析都是從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端界面結構。