Qt應用程序單實例化


在實際應用中,我們經常需要讓應用程序只有一個實例,再打開新的文檔或者頁面時,只是替換現在的窗口或者新打開一個標簽,而不是重新啟動一次應用程序。Qt中是否可以做到這樣呢,答案是肯定的,因為Qt本身可以直接調用系統API,肯定可以做到,但是我們希望找到一個跨平台的通用的解決方案。

      這就要用到Qt的QLocalSocket,QLocalServer類了,這兩個類從接口上看和網絡通信socket沒有區別,但是它並不是真正的網絡API,只是模仿了而已。這兩個類在Unix/Linux系統上采用Unix域socket實現,而在Windows上則采用有名管道(named pipe)來實現。

      既然是網絡API,那么思路就很簡單了,應用程序啟動時首先會去連一個服務器(這里通過應用程序的名字來標識,就像網絡端口一樣),如果連接失敗,那么則自己是第一個實例,就創建這么一個服務器,否則將啟動參數發送到服務器,然后自動退出,而服務器會在收到通知以后進行處理。

      這些動作我想最好是放在創建Application實例后,因為Qt本身有很多操作沒有Application實例是無法進行操作的(至少事件循環是在創立Application以后才能啟動吧),因此最好的位置就是通過繼承QApplicaiton或者QCoreApplication自定義一個YourOwnApplication,然后在構造函數中進行,下面是一個示意。

首先是YourOwnApplication構造函數:

 

QString serverName = QCoreApplication::applicationName();

    QLocalSocket socket;

    socket.connectToServer(serverName);

    if (socket.waitForConnected(500)) { //如果能夠連接得上的話,將參數發送到服務器,然后退出

        QTextStream stream(&socket);

        QStringList args = QCoreApplication::arguments();

        if (args.count() > 1)

            stream << args.last();

        else

            stream << QString();

        stream.flush();

        socket.waitForBytesWritten();

qApp->quit();

        return;

}

//運行到這里,說明沒有實例在運行,那么創建服務器。

    m_localServer = new QLocalServer(this);

    connect(m_localServer, SIGNAL(newConnection()),

            this, SLOT(newLocalSocketConnection())); //監聽新到來的連接

    if (!m_localServer->listen(serverName)) {

        if (m_localServer->serverError() == QAbstractSocket::AddressInUseError

            && QFile::exists(m_localServer->serverName())) { //確保能夠監聽成功

            QFile::remove(m_localServer->serverName());

            m_localServer->listen(serverName);

        }

    }

 

    這樣就保證了新啟動的程序在檢測到有其他實例在運行時就會自動退出,但是它發出的請求還沒有被處理,下面看一下處理函數,也就是前段代碼中的newLocalSocketConnection()。

    QLocalSocket *socket = m_localServer->nextPendingConnection();

    if (!socket)

        return;

    socket->waitForReadyRead(1000);

    QTextStream stream(socket);

   … … //其他處理

    delete socket;

    mainWindow()->raise();

    mainWindow()->activateWindow(); //記得激活窗口哦


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM