1############################################################################# 2## 3## Copyright (C) 2020 The Qt Company Ltd. 4## Contact: http://www.qt.io/licensing/ 5## 6## This file is part of the Qt for Python examples of the Qt Toolkit. 7## 8## $QT_BEGIN_LICENSE:BSD$ 9## You may use this file under the terms of the BSD license as follows: 10## 11## "Redistribution and use in source and binary forms, with or without 12## modification, are permitted provided that the following conditions are 13## met: 14## * Redistributions of source code must retain the above copyright 15## notice, this list of conditions and the following disclaimer. 16## * Redistributions in binary form must reproduce the above copyright 17## notice, this list of conditions and the following disclaimer in 18## the documentation and/or other materials provided with the 19## distribution. 20## * Neither the name of The Qt Company Ltd nor the names of its 21## contributors may be used to endorse or promote products derived 22## from this software without specific prior written permission. 23## 24## 25## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 36## 37## $QT_END_LICENSE$ 38## 39############################################################################# 40 41from PySide2.QtCore import Slot 42from PySide2.QtGui import QIcon 43from PySide2.QtWidgets import (QAction, QCheckBox, QComboBox, QDialog, 44 QGridLayout, QGroupBox, QHBoxLayout, QLabel, 45 QLineEdit, QMenu, QMessageBox, QPushButton, 46 QSpinBox, QStyle, QSystemTrayIcon, QTextEdit, 47 QVBoxLayout) 48 49import rc_systray 50 51 52class Window(QDialog): 53 def __init__(self, parent=None): 54 super(Window, self).__init__(parent) 55 56 self.iconGroupBox = QGroupBox() 57 self.iconLabel = QLabel() 58 self.iconComboBox = QComboBox() 59 self.showIconCheckBox = QCheckBox() 60 61 self.messageGroupBox = QGroupBox() 62 self.typeLabel = QLabel() 63 self.durationLabel = QLabel() 64 self.durationWarningLabel = QLabel() 65 self.titleLabel = QLabel() 66 self.bodyLabel = QLabel() 67 68 self.typeComboBox = QComboBox() 69 self.durationSpinBox = QSpinBox() 70 self.titleEdit = QLineEdit() 71 self.bodyEdit = QTextEdit() 72 self.showMessageButton = QPushButton() 73 74 self.minimizeAction = QAction() 75 self.maximizeAction = QAction() 76 self.restoreAction = QAction() 77 self.quitAction = QAction() 78 79 self.trayIcon = QSystemTrayIcon() 80 self.trayIconMenu = QMenu() 81 82 self.createIconGroupBox() 83 self.createMessageGroupBox() 84 85 self.iconLabel.setMinimumWidth(self.durationLabel.sizeHint().width()) 86 87 self.createActions() 88 self.createTrayIcon() 89 90 self.showMessageButton.clicked.connect(self.showMessage) 91 self.showIconCheckBox.toggled.connect(self.trayIcon.setVisible) 92 self.iconComboBox.currentIndexChanged.connect(self.setIcon) 93 self.trayIcon.messageClicked.connect(self.messageClicked) 94 self.trayIcon.activated.connect(self.iconActivated) 95 96 self.mainLayout = QVBoxLayout() 97 self.mainLayout.addWidget(self.iconGroupBox) 98 self.mainLayout.addWidget(self.messageGroupBox) 99 self.setLayout(self.mainLayout) 100 101 self.iconComboBox.setCurrentIndex(1) 102 self.trayIcon.show() 103 104 self.setWindowTitle("Systray") 105 self.resize(400, 300) 106 107 def setVisible(self, visible): 108 self.minimizeAction.setEnabled(visible) 109 self.maximizeAction.setEnabled(not self.isMaximized()) 110 self.restoreAction.setEnabled(self.isMaximized() or not visible) 111 super().setVisible(visible) 112 113 def closeEvent(self, event): 114 if not event.spontaneous() or not self.isVisible(): 115 return 116 if self.trayIcon.isVisible(): 117 QMessageBox.information(self, "Systray", 118 "The program will keep running in the system tray. " 119 "To terminate the program, choose <b>Quit</b> in the context " 120 "menu of the system tray entry.") 121 self.hide() 122 event.ignore() 123 124 @Slot(int) 125 def setIcon(self, index): 126 icon = self.iconComboBox.itemIcon(index) 127 self.trayIcon.setIcon(icon) 128 self.setWindowIcon(icon) 129 self.trayIcon.setToolTip(self.iconComboBox.itemText(index)) 130 131 @Slot(str) 132 def iconActivated(self, reason): 133 if reason == QSystemTrayIcon.Trigger: 134 pass 135 if reason == QSystemTrayIcon.DoubleClick: 136 self.iconComboBox.setCurrentIndex( 137 (self.iconComboBox.currentIndex() + 1) % self.iconComboBox.count() 138 ) 139 if reason == QSystemTrayIcon.MiddleClick: 140 self.showMessage() 141 142 @Slot() 143 def showMessage(self): 144 self.showIconCheckBox.setChecked(True) 145 selectedIcon = self.typeComboBox.itemData(self.typeComboBox.currentIndex()) 146 msgIcon = QSystemTrayIcon.MessageIcon(selectedIcon) 147 148 if selectedIcon == -1: # custom icon 149 icon = QIcon(self.iconComboBox.itemIcon(self.iconComboBox.currentIndex())) 150 self.trayIcon.showMessage( 151 self.titleEdit.text(), 152 self.bodyEdit.toPlainText(), 153 icon, 154 self.durationSpinBox.value() * 1000, 155 ) 156 else: 157 self.trayIcon.showMessage( 158 self.titleEdit.text(), 159 self.bodyEdit.toPlainText(), 160 msgIcon, 161 self.durationSpinBox.value() * 1000, 162 ) 163 164 @Slot() 165 def messageClicked(self): 166 QMessageBox.information(None, "Systray", 167 "Sorry, I already gave what help I could.\n" 168 "Maybe you should try asking a human?") 169 170 def createIconGroupBox(self): 171 self.iconGroupBox = QGroupBox("Tray Icon") 172 173 self.iconLabel = QLabel("Icon:") 174 175 self.iconComboBox = QComboBox() 176 self.iconComboBox.addItem(QIcon(":/images/bad.png"), "Bad") 177 self.iconComboBox.addItem(QIcon(":/images/heart.png"), "Heart") 178 self.iconComboBox.addItem(QIcon(":/images/trash.png"), "Trash") 179 180 self.showIconCheckBox = QCheckBox("Show icon") 181 self.showIconCheckBox.setChecked(True) 182 183 iconLayout = QHBoxLayout() 184 iconLayout.addWidget(self.iconLabel) 185 iconLayout.addWidget(self.iconComboBox) 186 iconLayout.addStretch() 187 iconLayout.addWidget(self.showIconCheckBox) 188 self.iconGroupBox.setLayout(iconLayout) 189 190 def createMessageGroupBox(self): 191 self.messageGroupBox = QGroupBox("Balloon Message") 192 193 self.typeLabel = QLabel("Type:") 194 195 self.typeComboBox = QComboBox() 196 self.typeComboBox.addItem("None", QSystemTrayIcon.NoIcon) 197 self.typeComboBox.addItem( 198 self.style().standardIcon(QStyle.SP_MessageBoxInformation), 199 "Information", 200 QSystemTrayIcon.Information, 201 ) 202 self.typeComboBox.addItem( 203 self.style().standardIcon(QStyle.SP_MessageBoxWarning), 204 "Warning", 205 QSystemTrayIcon.Warning, 206 ) 207 self.typeComboBox.addItem( 208 self.style().standardIcon(QStyle.SP_MessageBoxCritical), 209 "Critical", 210 QSystemTrayIcon.Critical, 211 ) 212 self.typeComboBox.addItem(QIcon(), "Custom icon", -1) 213 self.typeComboBox.setCurrentIndex(1) 214 215 self.durationLabel = QLabel("Duration:") 216 217 self.durationSpinBox = QSpinBox() 218 self.durationSpinBox.setRange(5, 60) 219 self.durationSpinBox.setSuffix(" s") 220 self.durationSpinBox.setValue(15) 221 222 self.durationWarningLabel = QLabel("(some systems might ignore this hint)") 223 self.durationWarningLabel.setIndent(10) 224 225 self.titleLabel = QLabel("Title:") 226 self.titleEdit = QLineEdit("Cannot connect to network") 227 self.bodyLabel = QLabel("Body:") 228 229 self.bodyEdit = QTextEdit() 230 self.bodyEdit.setPlainText("Don't believe me. Honestly, I don't have a clue." 231 "\nClick this balloon for details.") 232 233 self.showMessageButton = QPushButton("Show Message") 234 self.showMessageButton.setDefault(True) 235 236 messageLayout = QGridLayout() 237 messageLayout.addWidget(self.typeLabel, 0, 0) 238 messageLayout.addWidget(self.typeComboBox, 0, 1, 1, 2) 239 messageLayout.addWidget(self.durationLabel, 1, 0) 240 messageLayout.addWidget(self.durationSpinBox, 1, 1) 241 messageLayout.addWidget(self.durationWarningLabel, 1, 2, 1, 3) 242 messageLayout.addWidget(self.titleLabel, 2, 0) 243 messageLayout.addWidget(self.titleEdit, 2, 1, 1, 4) 244 messageLayout.addWidget(self.bodyLabel, 3, 0) 245 messageLayout.addWidget(self.bodyEdit, 3, 1, 2, 4) 246 messageLayout.addWidget(self.showMessageButton, 5, 4) 247 messageLayout.setColumnStretch(3, 1) 248 messageLayout.setRowStretch(4, 1) 249 self.messageGroupBox.setLayout(messageLayout) 250 251 def createActions(self): 252 self.minimizeAction = QAction("Minimize", self) 253 self.minimizeAction.triggered.connect(self.hide) 254 255 self.maximizeAction = QAction("Maximize", self) 256 self.maximizeAction.triggered.connect(self.showMaximized) 257 258 self.restoreAction = QAction("Restore", self) 259 self.restoreAction.triggered.connect(self.showNormal) 260 261 self.quitAction = QAction("Quit", self) 262 self.quitAction.triggered.connect(qApp.quit) 263 264 def createTrayIcon(self): 265 self.trayIconMenu = QMenu(self) 266 self.trayIconMenu.addAction(self.minimizeAction) 267 self.trayIconMenu.addAction(self.maximizeAction) 268 self.trayIconMenu.addAction(self.restoreAction) 269 self.trayIconMenu.addSeparator() 270 self.trayIconMenu.addAction(self.quitAction) 271 272 self.trayIcon = QSystemTrayIcon(self) 273 self.trayIcon.setContextMenu(self.trayIconMenu) 274