#!python
# -*- coding: utf-8 -*-
"""Example of qdarkstyle use for Python and Qt applications.
This module a main window with every item that could be created with
Qt Design (common ones) in the basic states (enabled/disabled), and
(checked/unchecked) for those who has this attribute.
Requirements:
- Python 3
- QtPy
- PyQt5 or PyQt4 or PySide2 or PySide
- PyQtGraph or Qt.Py (if chosen)
To run this example using PyQt5, simple do
.. code-block:: python
python example.py
or
.. code-block:: python
python example.py --qt_from=pyqt5
Other options for qt_from are: pyqt5, pyside2, pyqt, pyside, qtpy, pyqtgraph, and qt.py.
Also, you can run the example without any theme (none), to check for problems.
.. code-block:: python
python example.py --qt_from=pyqt5 --palette=none
Note:
qdarkstyle does not have to be installed to run the example.
"""
# Standard library imports
import argparse
import logging
import os
import sys
import platform
import time
# Make the example runnable without the need to install and include ui
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + '/../..'))
sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + '/../ui'))
# Must be in this place, after setting path, to not need to install
import qdarkstyle # noqa: E402
from qdarkstyle.dark.palette import DarkPalette # noqa: E402
from qdarkstyle.light.palette import LightPalette # noqa: E402
# Set log for debug
logging.basicConfig(level=logging.INFO)
_logger = logging.getLogger(__name__)
here = os.path.abspath(os.path.dirname(__file__))
# Constants
SCREENSHOTS_PATH = qdarkstyle.IMAGES_PATH
[docs]def main():
"""Execute QDarkStyle example."""
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('--palette', default='dark', type=str,
choices=['dark', 'light', 'none'],
help="Palette to display. Using 'none' there is no style sheet applied, OS like.")
parser.add_argument('--qt_from', default='qtpy', type=str,
choices=['pyqt5', 'pyqt', 'pyside2', 'pyside', 'qtpy', 'pyqtgraph', 'qt.py'],
help="Choose which binding and/or abstraction is to be used to run the example. Default is 'qtpy'")
parser.add_argument('--test', action='store_true',
help="Auto close window after 2s.")
parser.add_argument('--screenshots', action='store_true',
help="Generate screenshots on images folder.")
parser.add_argument('--offscreen', action='store_true',
help="Do not try to show the screen (running on server).")
parser.add_argument('--reset', action='store_true',
help="Reset GUI settings (position, size) then opens.")
# Parsing arguments from command line
args = parser.parse_args()
# To avoid problems when testing without screen
if args.test or args.offscreen:
os.environ['QT_QPA_PLATFORM'] = 'offscreen'
# Set QT_API variable before importing QtPy
if args.qt_from in ['pyqt', 'pyqt5', 'pyside', 'pyside2']:
os.environ['QT_API'] = args.qt_from
elif args.qt_from == 'pyqtgraph':
os.environ['QT_API'] = os.environ['PYQTGRAPH_QT_LIB']
elif args.qt_from in ['qt.py', 'qt']:
try:
import Qt
except ImportError:
print('Could not import Qt (Qt.Py)')
else:
os.environ['QT_API'] = Qt.__binding__
# QtPy imports
from qtpy import API_NAME, QT_VERSION, PYQT_VERSION, PYSIDE_VERSION, uic
from qtpy import __version__ as QTPY_VERSION
from qtpy import QtCore, QtGui, QtWidgets
# Set API_VERSION variable
API_VERSION = ''
if PYQT_VERSION:
API_VERSION = PYQT_VERSION
elif PYSIDE_VERSION:
API_VERSION = PYSIDE_VERSION
else:
API_VERSION = 'Not found'
# create the application
app = QtWidgets.QApplication(sys.argv)
app.setOrganizationName('QDarkStyle')
app.setApplicationName('QDarkStyle Example')
style = ''
if args.palette == 'dark':
style = qdarkstyle.load_stylesheet(palette=DarkPalette)
elif args.palette == 'light':
style = qdarkstyle.load_stylesheet(palette=LightPalette)
app.setStyleSheet(style)
# create main window
window = QtWidgets.QMainWindow()
window.setObjectName('mainwindow')
uic.loadUi(os.path.join(here, 'ui/mw_menus.ui'), window)
title = ("QDarkStyle Example - ("
+ f"Palette={args.palette}, "
+ f"QDarkStyle=v{qdarkstyle.__version__}, "
+ f"QtPy=v{QTPY_VERSION}, "
+ f"{API_NAME}=v{API_VERSION}, "
+ f"Qt=v{QT_VERSION}, "
+ f"Python=v{platform.python_version()}, "
# Operating system info are maybe too much,
# but different OS add info in different places
+ f"System={platform.system()}, "
+ f"Release={platform.release()}, "
+ f"Version={platform.version()}, "
+ f"Platform={platform.platform()}"
+ ")")
_logger.info(title)
window.setWindowTitle(title)
# Create docks for buttons
dw_buttons = QtWidgets.QDockWidget()
dw_buttons.setObjectName('buttons')
uic.loadUi(os.path.join(here, 'ui/dw_buttons.ui'), dw_buttons)
window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dw_buttons)
# Set state indeterminate #275
dw_buttons.checkBoxTristate.stateChanged.connect(dw_buttons.checkBoxTristateDis.setCheckState)
dw_buttons.checkBoxTristate.setCheckState(QtCore.Qt.PartiallyChecked)
# Add actions on popup toolbuttons
menu = QtWidgets.QMenu()
for action in ['Action A', 'Action B', 'Action C']:
menu.addAction(action)
# Add menu in special tool buttons
dw_buttons.toolButtonDelayedPopup.setMenu(menu)
dw_buttons.toolButtonInstantPopup.setMenu(menu)
dw_buttons.toolButtonMenuButtonPopup.setMenu(menu)
# Add menu in toolbar #251
action_menu = QtWidgets.QAction(u'Menu action', window.toolBarMenus)
action_menu.setMenu(menu)
window.toolBarMenus.addAction(action_menu)
# Add color to tab title text #212
window.tabWidget.tabBar().setTabTextColor(3, QtGui.QColor('red'))
# Connect dialogs to buttons
window.toolButtonColorDialog.clicked.connect(lambda: QtWidgets.QColorDialog().exec())
window.toolButtonFileDialog.clicked.connect(lambda: QtWidgets.QFileDialog().exec())
window.toolButtonFileDialogStatic.clicked.connect(lambda: QtWidgets.QFileDialog.getOpenFileNames())
window.toolButtonFontDialog.clicked.connect(lambda: QtWidgets.QFontDialog().exec())
window.toolButtonInputDialog.clicked.connect(lambda: QtWidgets.QInputDialog().exec())
window.toolButtonMessageBox.clicked.connect(lambda: QtWidgets.QMessageBox().exec())
window.toolButtonMessageBoxStatic.clicked.connect(lambda: QtWidgets.QMessageBox.critical(window, "Critical title", "Critical message"))
window.toolButtonProgressDialog.clicked.connect(lambda: QtWidgets.QProgressDialog().exec())
# Create docks for buttons
dw_displays = QtWidgets.QDockWidget()
dw_displays.setObjectName('displays')
uic.loadUi(os.path.join(here, 'ui/dw_displays.ui'), dw_displays)
window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dw_displays)
# Create docks for inputs - no fields
dw_inputs_no_fields = QtWidgets.QDockWidget()
dw_inputs_no_fields.setObjectName('inputs_no_fields')
uic.loadUi(os.path.join(here, 'ui/dw_inputs_no_fields.ui'), dw_inputs_no_fields)
window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dw_inputs_no_fields)
# Create docks for inputs - fields
dw_inputs_fields = QtWidgets.QDockWidget()
dw_inputs_fields.setObjectName('inputs_fields')
uic.loadUi(os.path.join(here, 'ui/dw_inputs_fields.ui'), dw_inputs_fields)
window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dw_inputs_fields)
# Create docks for widgets
dw_widgets = QtWidgets.QDockWidget()
dw_widgets.setObjectName('widgets')
uic.loadUi(os.path.join(here, 'ui/dw_widgets.ui'), dw_widgets)
window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dw_widgets)
# Create docks for views
dw_views = QtWidgets.QDockWidget()
dw_views.setObjectName('views')
uic.loadUi(os.path.join(here, 'ui/dw_views.ui'), dw_views)
window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dw_views)
# Create docks for containers - no tabs
dw_containers_no_tabs = QtWidgets.QDockWidget()
dw_containers_no_tabs.setObjectName('containers_no_tabs')
uic.loadUi(os.path.join(here, 'ui/dw_containers_no_tabs.ui'), dw_containers_no_tabs)
window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dw_containers_no_tabs)
# Create docks for containters - tabs
dw_containers_tabs = QtWidgets.QDockWidget()
dw_containers_tabs.setObjectName('containers_tabs')
uic.loadUi(os.path.join(here, 'ui/dw_containers_tabs.ui'), dw_containers_tabs)
window.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dw_containers_tabs)
# Tabify right docks
window.tabifyDockWidget(dw_buttons, dw_displays)
window.tabifyDockWidget(dw_displays, dw_inputs_fields)
window.tabifyDockWidget(dw_inputs_fields, dw_inputs_no_fields)
# Tabify left docks
window.tabifyDockWidget(dw_containers_no_tabs, dw_containers_tabs)
window.tabifyDockWidget(dw_containers_tabs, dw_widgets)
window.tabifyDockWidget(dw_widgets, dw_views)
# Issues #9120, #9121 on Spyder
qstatusbar = QtWidgets.QStatusBar()
qstatusbar.addWidget(QtWidgets.QLabel('Issue Spyder #9120, #9121 - background not matching.'))
qstatusbar.addWidget(QtWidgets.QPushButton('OK'))
# Add info also in status bar for screenshots get it
qstatusbar.addWidget(QtWidgets.QLabel('INFO: ' + title))
window.setStatusBar(qstatusbar)
# Todo: add report info and other info in HELP graphical
# Auto quit after 2s when in test mode
if args.test:
QtCore.QTimer.singleShot(2000, app.exit)
# Save screenshots for different displays and quit
if args.screenshots:
window.showFullScreen()
create_screenshots(app, window, args)
# Do not read settings when taking screenshots - like reset
else:
_read_settings(window, args.reset, QtCore.QSettings)
window.showMaximized()
app.exec_()
_write_settings(window, QtCore.QSettings)
[docs]def _write_settings(window, QSettingsClass):
"""Get window settings and write it into a file."""
settings = QSettingsClass('QDarkStyle', 'QDarkStyle Example')
settings.setValue('pos', window.pos())
settings.setValue('size', window.size())
settings.setValue('state', window.saveState())
[docs]def _read_settings(window, reset, QSettingsClass):
"""Read and set window settings from a file."""
settings = QSettingsClass('QDarkStyle', 'QDarkStyle Example')
try:
pos = settings.value('pos', window.pos())
size = settings.value('size', window.size())
state = settings.value('state', window.saveState())
except Exception:
pos = settings.value('pos', window.pos(), type='QPoint')
size = settings.value('size', window.size(), type='QSize')
state = settings.value('state', window.saveState(), type='QByteArray')
if not reset:
window.restoreState(state)
window.resize(size)
window.move(pos)
[docs]def create_screenshots(app, window, args):
"""Save screenshots for different application views and quit."""
theme = args.palette
print('\nCreating {} screenshots'.format(theme))
docks = window.findChildren(QtWidgets.QDockWidget)
tabs = window.findChildren(QtWidgets.QTabWidget)
widget_data = {
'containers_no_tabs_buttons.png': [
'Containers - No Tabs',
'Buttons',
],
'containers_tabs_displays.png': [
'Containers - Tabs',
'Displays',
],
'widgets_inputs_fields.png': [
'Widgets',
'Inputs - Fields',
],
'views_inputs_no_fields.png': [
'Views',
'Inputs - No Fields',
]
}
# Central widget tabs of with examples, reset positions
tab = [tab for tab in tabs if tab.count() >= 12][0]
tab.setCurrentIndex(0)
QtCore.QCoreApplication.processEvents()
for fname_suffix, dw_titles in widget_data.items():
png_path = os.path.join(SCREENSHOTS_PATH, theme, fname_suffix)
print('\t' + png_path)
for dw in docks:
if dw.windowTitle() in dw_titles:
print('Evidencing : ', dw.windowTitle())
dw.raise_()
dw.show()
QtCore.QCoreApplication.processEvents()
# Attention: any change in update, processEvent and sleep calls
# make those screenshots not working, specially the first one.
# It seems that processEvents are not working properly
window.update()
window.showFullScreen()
QtCore.QCoreApplication.processEvents()
time.sleep(0.5)
QtCore.QCoreApplication.processEvents()
screen = QtGui.QGuiApplication.primaryScreen()
QtCore.QCoreApplication.processEvents()
pixmap = screen.grabWindow(window.winId())
# Yeah, this is duplicated to avoid screenshot problems
screen = QtGui.QGuiApplication.primaryScreen()
QtCore.QCoreApplication.processEvents()
pixmap = screen.grabWindow(window.winId())
img = pixmap.toImage()
img.save(png_path)
QtCore.QCoreApplication.processEvents()
QtCore.QCoreApplication.processEvents()
window.close()
print('\n')
app.exit(sys.exit())
if __name__ == "__main__":
sys.exit(main())