-
Notifications
You must be signed in to change notification settings - Fork 730
/
__main__.py
executable file
·386 lines (299 loc) · 13.7 KB
/
__main__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
#!/usr/bin/env python3
# -*- 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
- PyQt6 or PyQt5 or PyQt4 or PySide6 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: pyqt6, pyqt5, pyside6, 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
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='pyqt5', type=str,
choices=['pyqt6', 'pyqt5', 'pyqt', 'pyside6', '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', 'pyqt6', 'pyside', 'pyside2', 'pyside6']:
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)
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())
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)
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())