QT中实现应用程序的单例化

Wesley13
• 阅读 927

一介绍

通过编写一个QSingleApplication类,来实现Qt程序的单例化,原文的作者是在Windows Vista + Qt4.4 下实现的,不过应用在其他平台上是没问题的。(本文是我在http://www.qtcentre.org/wiki/index.php?title=SingleApplication上看到的)

二代码

方案一:使用Qt中的QSharedMemory,QLocalServer和QLocalSocket实现(不过需要在你的.pro里加上QT += network)

别的没翻译,就是大概说了一下,直接来代码吧:

// "single_application.h"

#ifndef SINGLE_APPLICATION_H
#define SINGLE_APPLICATION_H

#include <QApplication>
#include <QSharedMemory>
#include <QLocalServer>

class SingleApplication : public QApplication

{
    Q_OBJECT
public:

    SingleApplication(int &argc, char *argv[], const QString uniqueKey);
    bool isRunning();
    bool sendMessage(const QString &message);
public slots:
    void receiveMessage();
signals:
    void messageAvailable(QString message);
private:
    bool _isRunning;
    QString _uniqueKey;
    QSharedMemory sharedMemory;
    QLocalServer *localServer;
    static const int timeout = 1000;
};

#endif // SINGLE_APPLICATION_H

// "single_application.cpp"
#include <QLocalSocket>
#include "single_application.h"

SingleApplication::SingleApplication(int &argc, char *argv[], const QString uniqueKey) : QApplication(argc, argv), _uniqueKey(uniqueKey)

{
    sharedMemory.setKey(_uniqueKey);
    if (sharedMemory.attach())
        _isRunning = true;
    else
    {
        _isRunning = false;
        // create shared memory.
        if (!sharedMemory.create(1))
        {
            qDebug("Unable to create single instance.");
            return;
        }

        // create local server and listen to incomming messages from other instances.
        localServer = new QLocalServer(this);
        connect(localServer, SIGNAL(newConnection()), this, SLOT(receiveMessage()));
        localServer->listen(_uniqueKey);
    }
}

// public slots.
void SingleApplication::receiveMessage()
{
    QLocalSocket *localSocket = localServer->nextPendingConnection();
    if (!localSocket->waitForReadyRead(timeout))
    {
        qDebug(localSocket->errorString().toLatin1());
        return;
    }

    QByteArray byteArray = localSocket->readAll();
    QString message = QString::fromUtf8(byteArray.constData());
    emit messageAvailable(message);
    localSocket->disconnectFromServer();
}

// public functions.
bool SingleApplication::isRunning()
{
    return _isRunning;
}

bool SingleApplication::sendMessage(const QString &message)
{
    if (!_isRunning)
        return false;
    QLocalSocket localSocket(this);
    localSocket.connectToServer(_uniqueKey, QIODevice::WriteOnly);
    if (!localSocket.waitForConnected(timeout))
    {
        qDebug(localSocket.errorString().toLatin1());
        return false;
    }

    localSocket.write(message.toUtf8());
    if (!localSocket.waitForBytesWritten(timeout))
    {
        qDebug(localSocket.errorString().toLatin1());
        return false;
    }

    localSocket.disconnectFromServer();
    return true;

方案二:使用Qt中的QSharedMemory,和QTimert实现,别的也没翻译,还是直接来代码吧:

// "single_application.h"
#ifndef SINGLE_APPLICATION_H
#define SINGLE_APPLICATION_H

#include <QApplication>
#include <QSharedMemory>

class SingleApplication : public QApplication
{
    Q_OBJECT
public:
    SingleApplication(int &argc, char *argv[], const QString uniqueKey);
    bool isRunning();
    bool sendMessage(const QString &message);
public slots:
    void checkForMessage();
signals:
    void messageAvailable(QString message);
private:
    bool _isRunning;
    QSharedMemory sharedMemory;
};

#endif // SINGLE_APPLICATION_H

// "single_application.cpp"
#include <QTimer>
#include <QByteArray>
#include "single_application.h"

SingleApplication::SingleApplication(int &argc, char *argv[], const QString uniqueKey) : QApplication(argc, argv)
{
    sharedMemory.setKey(uniqueKey);
    if (sharedMemory.attach())
        _isRunning = true;
    else
    {
        _isRunning = false;
        // attach data to shared memory.
        QByteArray byteArray("0"); // default value to note that no message is available.
        if (!sharedMemory.create(byteArray.size()))
        {
            qDebug("Unable to create single instance.");
            return;
        }
        sharedMemory.lock();
        char *to = (char*)sharedMemory.data();
        const char *from = byteArray.data();
        memcpy(to, from, qMin(sharedMemory.size(), byteArray.size()));
        sharedMemory.unlock();

                // start checking for messages of other instances.
        QTimer *timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, SLOT(checkForMessage()));
        timer->start(1000);
    }
}

// public slots.
void SingleApplication::checkForMessage()
{
    sharedMemory.lock();
    QByteArray byteArray = QByteArray((char*)sharedMemory.constData(), sharedMemory.size());
    sharedMemory.unlock();
    if (byteArray.left(1) == "0")
        return;
    byteArray.remove(0, 1);
    QString message = QString::fromUtf8(byteArray.constData());
    emit messageAvailable(message);

        // remove message from shared memory.
    byteArray = "0";
    sharedMemory.lock();
    char *to = (char*)sharedMemory.data();
    const char *from = byteArray.data();
    memcpy(to, from, qMin(sharedMemory.size(), byteArray.size()));
    sharedMemory.unlock();
}

// public functions.
bool SingleApplication::isRunning()
{
    return _isRunning;
}

bool SingleApplication::sendMessage(const QString &message)
{
    if (!_isRunning)
        return false;

    QByteArray byteArray("1");
    byteArray.append(message.toUtf8());
    byteArray.append('/0'); // < should be as char here, not a string!
    sharedMemory.lock();
    char *to = (char*)sharedMemory.data();
    const char *from = byteArray.data();
    memcpy(to, from, qMin(sharedMemory.size(), byteArray.size()));
    sharedMemory.unlock();
    return true;
}

三使用

// "main.cpp"
#include "single_application.h"
int main(int argc, char *argv[])
{
    SingleApplication app(argc, argv, "some unique key string");
    if (app.isRunning())
    {
        app.sendMessage("message from other instance.");
        return 0;
    }

    MainWindow *mainWindow = new MainWindow();

        // connect message queue to the main window.
    QObject::connect(&app, SIGNAL(messageAvailable(QString)), mainWindow, SLOT(receiveMessage(QString)));

        // show mainwindow.
    mainWindow->show();
    return app.exec();

}
我想代码都应该能看得懂吧,这个挺不错的~
点赞
收藏
评论区
推荐文章
3A网络 3A网络
2年前
Golang 常见设计模式之单例模式
之前我们已经看过了Golang常见设计模式中的装饰和选项模式,今天要看的是Golang设计模式里最简单的单例模式。单例模式的作用是确保无论对象被实例化多少次,全局都只有一个实例存在。根据这一特性,我们可以将其应用到全局唯一性配置、数据库连接对象、文件访问对象等。Go语言实现单例模式的方法有很多种,下面我们就一起来看一下。饿汉式饿汉式实现单例模式非
Wesley13 Wesley13
3年前
java设计模式1
1:单例模式简介  单例模式是一种常用的软件设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供唯一的实例。总而言之就是在系统中只会存在一个对象,其中的数据是共享的  特点:    单例类只能有一个实例,所以一般会用static进行修释。    单例类必须自己创建自己的唯一实例。也就是在类中要new一个自己。    单例类必
Wesley13 Wesley13
3年前
java 23种设计模式(五、单例模式)
作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。单例模式的结构  单例模式的特点:单例类只能有一个实例。单例类必须自己创建自己的唯一实例。单例类必须给所有其他对象提供这一实例。  饿汉式单例类publicclassEagerSingleton
疯震震 疯震震
3年前
【单例深思】饿汉式
1、抛出问题1.为什么饿汉式单例是线程安全的?2.为什么饿汉式单例没有延迟加载(LazyLoading)?2、JVM类加载机制饿汉式单例的实现:javapublicclassSingletonprivatestaticSingletonsingletonnewSingleton();privateS
Stella981 Stella981
3年前
Spring 必知概念(二)
13、Spring框架中的单例Beans是线程安全的么?Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Springbean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多
Wesley13 Wesley13
3年前
JAVA设计模式之单例设计模式
    单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。  在JAVA中实现单例,必须了解JAVA内存机制,JAVA中实例对象存在于堆内存中,若要实现单例,必须满足两个条件:  1.限制类实例化对象。即只能产生一个对象。
Wesley13 Wesley13
3年前
Java单例模式
什么是单例模式  单例模式是在程序中,一个类保证只有一个实例,并提供统一的访问入口。为什么要用单例模式节省内存节省计算如对象实例中的一样的,那就不用每次都创建一个对象方便管理因为单例提供一个统一的访问入口,不需要创建N多个对象,很多工具类都用了单例实现,如日志、字符串工具类
Wesley13 Wesley13
3年前
PHP单例模式(精讲)
首先我们要明确单例模式这个概念,那么什么是单例模式呢?单例模式顾名思义,就是只有一个实例。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类我们称之为单例类。单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例
Wesley13 Wesley13
3年前
(面试常问)4种单例设计模式的总结(内含代码以及分析)
单例设计模式:  单例模式,是一种常见的软件设计模式.在它的核心结构中只包含了一个被称为单例的特殊类.通过单例模式可以保证系统中只有该类的一个实例对象.优点:  实例控制:单例模式会阻止其它对象实例化其自己的单例对象的副本,从而确保所有对象都访问的是唯一的实例   灵活性:因为类控制了实例化过程,所以类可以很灵活的更改实
Java单元测试及常用语句 | 京东物流技术团队
编写Java单元测试用例,即把一段复杂的代码拆解成一系列简单的单元测试用例,并且无需启动服务,在短时间内测试代码中的处理逻辑。写好Java单元测试用例,其实就是把“复杂问题简单化,建单问题深入化“。在编写的过程中,我们也可以对自己的代码进行一个二次检查。