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