Qt 显示应用程序,如果当前正在运行 [英] Qt show application, if currently running

查看:107
本文介绍了Qt 显示应用程序,如果当前正在运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个单实例应用程序,它最小化到系统托盘,我想显示当前正在运行的实例,然后退出新的实例.如何创建此功能?

I'm creating a single instance app, which is minimised to system tray, I want to show the currently running instance, then quit the new one. How can I create this functionality?

main.cpp

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QIcon>
#include <QQuickWidget>
#include <QSystemTrayIcon>
#include <QQmlContext>
#include <QQmlEngine>
#include <QSystemSemaphore>
#include <QSharedMemory>

// Declare a user-defined data type to work with an icon in QML
Q_DECLARE_METATYPE(QSystemTrayIcon::ActivationReason)
Q_DECL_EXPORT int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QApplication app(argc, argv);

    QQmlApplicationEngine engine;

    QSystemSemaphore semaphore("deploy", 1);  // create semaphore
    semaphore.acquire(); // Raise the semaphore, barring other instances to work with shared memory

#ifndef Q_OS_WIN32
    // in linux / unix shared memory is not freed when the application terminates abnormally,
    // so you need to get rid of the garbage
    QSharedMemory nix_fix_shared_memory("deploy Shared Memory");
    if(nix_fix_shared_memory.attach()){
        nix_fix_shared_memory.detach();
    }
#endif

    QSharedMemory sharedMemory("deploy Shared Memory");  // Create a copy of the shared memory
    bool is_running;            // variable to test the already running application
    if (sharedMemory.attach()){ // We are trying to attach a copy of the shared memory
        // To an existing segment
        is_running = true;      // If successful, it determines that there is already a running instance
    }else{
        sharedMemory.create(1); // Otherwise allocate 1 byte of memory
        is_running = false;     // And determines that another instance is not running
    }
    semaphore.release();

    // If you already run one instance of the application, then we inform the user about it
    // and complete the current instance of the application
    if(is_running){
        return -1;
    }

    // Register QSystemTrayIcon in Qml
    qmlRegisterType<QSystemTrayIcon>("QSystemTrayIcon", 1, 0, "QSystemTrayIcon");
    // Register in QML the data type of click by tray icon
    qRegisterMetaType<QSystemTrayIcon::ActivationReason>("ActivationReason");
    // Set icon in the context of the engine
    engine.rootContext()->setContextProperty("iconTray", QIcon(":/deploy.png"));
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml

import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Controls 1.4 as Tray
import QtQuick.Dialogs 1.2
import QtQuick.Extras 1.2
import QtQuick.Window 2.0
import QSystemTrayIcon 1.0

Window {
    visible: true
    id: application
    width: 640
    height: 480
    title: qsTr("Test")

    // system tray

    QSystemTrayIcon {
        id: systemTray

        // Initial initialization of the system tray
        Component.onCompleted: {
            icon = iconTray             // Set icon
            toolTip = "Deploy App"
            show();
            if(application.visibility === Window.Hidden) {
                application.show()
            } else {
                application.hide()
            }
        }

        /* By clicking on the tray icon define the left or right mouse button click was.
         * If left, then hide or open the application window.
         * If right, then open the System Tray menu
        * */
        onActivated: {
            if(reason === 1){
                trayMenu.popup()
            } else {
                if(application.visibility === Window.Hidden) {
                    application.show()
                } else {
                    application.hide()
                }
            }
        }
    }

    // Menu system tray
    Tray.Menu {
        id: trayMenu

        Tray.MenuItem {
            text: qsTr("Show App")
            onTriggered: application.show()
        }

        Tray.MenuItem {
            text: qsTr("Quit")
            onTriggered: {
                systemTray.hide()
                Qt.quit()

            }
        }
    }
}

我尝试创建一个对象,并在我的 main.cpp 和我的 main.qml 中将其运行状态设置为 false 或 true 我检查了值并退出应用程序.

I have tried creating an object, and set its running status to false or true in my main.cpp and in my main.qml I check the value and quit the application.

QQmlApplicationEngine engine;

QQmlContext *context = engine.rootContext();
SingleInstance singleInstance;

context->setContextProperty("SingleInstance", &singleInstance);
if (is_running) {
    singleInstance.running(true);

在我的 main.qml 中,我检查应用程序是否正在运行.

In my main.qml I check if the application is running.

Connections {
    target: SingleInstance
}

Component.onCompleted: {
    if (SingleInstance.running) {
        if(application.visibility === Window.Hidden) {
            Qt.quit()
        }
    }
}

推荐答案

我们最终为单实例做的是使用 QLocalSocket 在 Windows 上是命名管道,在 Unix 上是本地域套接字,而不是 QSharedMemory 需要更多调整才能正确使用.基本上你做这样的事情来检查服务器是否正在运行(appName 必须是唯一的应用程序标识符,你可以使用例如 QCoreApplication::applicationName):

What we ended up doing for single instance is to use QLocalSocket which is named pipe on Windows and local domain socket on Unix instead of QSharedMemory which requires more tweaking to get it right. Basically you do something like this to check if the server is running (appName must be unique application identifier, you can use e.g. QCoreApplication::applicationName):

bool isSingleInstanceRunning(QString appName) {
    QLocalSocket socket;
    socket.connectToServer(m_appName);
    bool isOpen = socket.isOpen();
    socket.close();
    return isOpen;
}

如果您得到 false,您将创建自己的服务器(在应用程序的生命周期内保留此实例):

If you get false you will create your own server (keep this instance during lifetime of your application):

QLocalServer* startSingleInstanceServer(QString appName) {
    QLocalServer* server = new QLocalServer;
    server->setSocketOptions(QLocalServer::WorldAccessOption);
    server->listen(appName);
}

您还可以将命令行参数从启动应用程序传递到已经运行的实例 - 在应用程序的启动实例中打开套接字并发送命令行参数.在现有实例端只需挂钩 QLocalServer::newConnection 信号,打开套接字并钩住 QLocalSocket::readyRead 信号.

You can also pass command line arguments from starting application to the already running instance - in starting instance of your application open the socket and send the command line parameters. On existing instance side just hook to QLocalServer::newConnection signal, open the socket and hook to QLocalSocket::readyRead signal.

这篇关于Qt 显示应用程序,如果当前正在运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆