Qt 显示应用程序,如果当前正在运行 [英] Qt show application, if currently running
问题描述
我正在创建一个单实例应用程序,它最小化到系统托盘,我想显示当前正在运行的实例,然后退出新的实例.如何创建此功能?
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屋!