diff --git a/doc/source/how_to_use.rst b/doc/source/how_to_use.rst index 7c775d47..1c8880d0 100644 --- a/doc/source/how_to_use.rst +++ b/doc/source/how_to_use.rst @@ -54,6 +54,28 @@ For the serious application developer, all of the functionality in pyqtgraph is See the designer documentation for more information on promoting widgets. The "VideoSpeedTest" and "ScatterPlotSpeedTest" examples both demonstrate the use of .ui files that are compiled to .py modules using pyuic5 or pyside-uic. The "designerExample" example demonstrates dynamically generating python classes from .ui files (no pyuic5 / pyside-uic needed). +HiDPI Displays +-------------- + +PyQtGraph has a method :func:`mkQApp ` that by default sets what we have tested to be the best combination of options to support hidpi displays, when in combination with non-hidpi secondary displays. For your application, you may have instantiated ``QApplication`` yourself, in which case we advise setting these options *before* runing ``QApplication.exec_()``. + +For Qt6 bindings, this functionally "just works" without having to set any attributes. + +On Versions of Qt >= 5.14 and < 6; you can get ideal behavior with the following lines:: + + os.environ["QT_ENABLE_HIDPI_SCALING"] = "1" + QApplication.setHighDpiScaleFactorRoundingPolicy(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough) + +If you are on Qt >= 5.6 and < 5.14; you can get near ideal behavior with the following lines:: + + QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) + QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) + +With the later, ideal behavior was not achieved. + +.. autofunction:: pyqtgraph.Qt.mkQApp + + PyQt and PySide --------------- @@ -63,8 +85,9 @@ pyqtgraph is first imported, it automatically determines which library to use by #. If PyQt5 is already imported, use that #. Else, if PySide2 is already imported, use that -#. Else, attempt to import PyQt5 -#. If that import fails, attempt to import PySide2. +#. Else, if PySide6 is already imported, use that +#. Else, if PyQt6 is already imported, use that +#. Else, attempt to import PyQt5, PySide2, PySide6, PyQt6, in that order. If you have both libraries installed on your system and you wish to force pyqtgraph to use one or the other, simply make sure it is imported before pyqtgraph:: diff --git a/examples/Arrow.py b/examples/Arrow.py index 2a707fec..bd0b6b07 100644 --- a/examples/Arrow.py +++ b/examples/Arrow.py @@ -15,7 +15,7 @@ from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("Arrow Example") w = QtGui.QMainWindow() cw = pg.GraphicsLayoutWidget() diff --git a/examples/ColorButton.py b/examples/ColorButton.py index 321ee735..e9df9750 100644 --- a/examples/ColorButton.py +++ b/examples/ColorButton.py @@ -11,7 +11,7 @@ import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("ColorButton Example") win = QtGui.QMainWindow() btn = pg.ColorButton() win.setCentralWidget(btn) diff --git a/examples/DataSlicing.py b/examples/DataSlicing.py index d766e7e3..8bd1e04d 100644 --- a/examples/DataSlicing.py +++ b/examples/DataSlicing.py @@ -14,7 +14,7 @@ import numpy as np from pyqtgraph.Qt import QtCore, QtGui import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("Data Slicing Example") ## Create window with two ImageView widgets win = QtGui.QMainWindow() diff --git a/examples/DataTreeWidget.py b/examples/DataTreeWidget.py index 70ac49bd..47a5f32b 100644 --- a/examples/DataTreeWidget.py +++ b/examples/DataTreeWidget.py @@ -22,7 +22,7 @@ def some_func2(): return sys.exc_info()[2] -app = QtGui.QApplication([]) +app = pg.mkQApp("DataTreeWidget Example") d = { 'a list': [1,2,3,4,5,6, {'nested1': 'aaaaa', 'nested2': 'bbbbb'}, "seven"], 'a dict': { diff --git a/examples/DateAxisItem.py b/examples/DateAxisItem.py index 7bbaafff..d789308d 100644 --- a/examples/DateAxisItem.py +++ b/examples/DateAxisItem.py @@ -12,7 +12,7 @@ import numpy as np import pyqtgraph as pg from pyqtgraph.Qt import QtGui -app = QtGui.QApplication([]) +app = pg.mkQApp("DateAxisItem Example") # Create a plot with a date-time axis w = pg.PlotWidget(axisItems = {'bottom': pg.DateAxisItem()}) diff --git a/examples/DiffTreeWidget.py b/examples/DiffTreeWidget.py index fa57a356..780e1eaf 100644 --- a/examples/DiffTreeWidget.py +++ b/examples/DiffTreeWidget.py @@ -12,7 +12,7 @@ from pyqtgraph.Qt import QtCore, QtGui import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("DiffTreeWidget Example") A = { 'a list': [1,2,2,4,5,6, {'nested1': 'aaaa', 'nested2': 'bbbbb'}, "seven"], 'a dict': { diff --git a/examples/Draw.py b/examples/Draw.py index cc137db3..1401c398 100644 --- a/examples/Draw.py +++ b/examples/Draw.py @@ -12,7 +12,7 @@ from pyqtgraph.Qt import QtCore, QtGui import numpy as np import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("Draw Example") ## Create window with GraphicsView widget w = pg.GraphicsView() diff --git a/examples/Flowchart.py b/examples/Flowchart.py index b911cec8..45e833ce 100644 --- a/examples/Flowchart.py +++ b/examples/Flowchart.py @@ -19,7 +19,7 @@ import pyqtgraph as pg import numpy as np import pyqtgraph.metaarray as metaarray -app = QtGui.QApplication([]) +app = pg.mkQApp("Flowchart Example") ## Create main window with grid layout win = QtGui.QMainWindow() diff --git a/examples/FlowchartCustomNode.py b/examples/FlowchartCustomNode.py index 2b0819ab..dc1fd55f 100644 --- a/examples/FlowchartCustomNode.py +++ b/examples/FlowchartCustomNode.py @@ -13,7 +13,7 @@ from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("Flowchart Custom Node Example") ## Create main window with a grid layout inside win = QtGui.QMainWindow() diff --git a/examples/GLBarGraphItem.py b/examples/GLBarGraphItem.py index d14eba87..e593d54a 100644 --- a/examples/GLBarGraphItem.py +++ b/examples/GLBarGraphItem.py @@ -11,7 +11,7 @@ import pyqtgraph.opengl as gl import pyqtgraph as pg import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("GLBarGraphItem Example") w = gl.GLViewWidget() w.opts['distance'] = 40 w.show() diff --git a/examples/GLImageItem.py b/examples/GLImageItem.py index 70bf5306..6a31c09a 100644 --- a/examples/GLImageItem.py +++ b/examples/GLImageItem.py @@ -13,7 +13,7 @@ import pyqtgraph.opengl as gl import pyqtgraph as pg import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("GLImageItem Example") w = gl.GLViewWidget() w.opts['distance'] = 200 w.show() diff --git a/examples/GLIsosurface.py b/examples/GLIsosurface.py index a9403ffb..0beeea66 100644 --- a/examples/GLIsosurface.py +++ b/examples/GLIsosurface.py @@ -11,7 +11,7 @@ from pyqtgraph.Qt import QtCore, QtGui import pyqtgraph as pg import pyqtgraph.opengl as gl -app = QtGui.QApplication([]) +app = pg.mkQApp("GLIsosurface Example") w = gl.GLViewWidget() w.show() w.setWindowTitle('pyqtgraph example: GLIsosurface') diff --git a/examples/GLLinePlotItem.py b/examples/GLLinePlotItem.py index 1de07cff..0d07b153 100644 --- a/examples/GLLinePlotItem.py +++ b/examples/GLLinePlotItem.py @@ -11,7 +11,7 @@ import pyqtgraph.opengl as gl import pyqtgraph as pg import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("GLLinePlotItem Example") w = gl.GLViewWidget() w.opts['distance'] = 40 w.show() diff --git a/examples/GLMeshItem.py b/examples/GLMeshItem.py index 1caa3490..692f8f8f 100644 --- a/examples/GLMeshItem.py +++ b/examples/GLMeshItem.py @@ -11,7 +11,7 @@ from pyqtgraph.Qt import QtCore, QtGui import pyqtgraph as pg import pyqtgraph.opengl as gl -app = QtGui.QApplication([]) +app = pg.mkQApp("GLMeshItem Example") w = gl.GLViewWidget() w.show() w.setWindowTitle('pyqtgraph example: GLMeshItem') diff --git a/examples/GLScatterPlotItem.py b/examples/GLScatterPlotItem.py index 53a9a752..b52e17b5 100644 --- a/examples/GLScatterPlotItem.py +++ b/examples/GLScatterPlotItem.py @@ -7,11 +7,12 @@ Demonstrates use of GLScatterPlotItem with rapidly-updating plots. ## Add path to library (just for examples; you do not need this) import initExample +import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui import pyqtgraph.opengl as gl import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("GLScatterPlotItem Example") w = gl.GLViewWidget() w.opts['distance'] = 20 w.show() diff --git a/examples/GLSurfacePlot.py b/examples/GLSurfacePlot.py index e9896e07..cac8d5fe 100644 --- a/examples/GLSurfacePlot.py +++ b/examples/GLSurfacePlot.py @@ -13,7 +13,7 @@ import pyqtgraph.opengl as gl import numpy as np ## Create a GL View widget to display data -app = QtGui.QApplication([]) +app = pg.mkQApp("GLSurfacePlot Example") w = gl.GLViewWidget() w.show() w.setWindowTitle('pyqtgraph example: GLSurfacePlot') diff --git a/examples/GLViewWidget.py b/examples/GLViewWidget.py index a5207838..d06a6ed8 100644 --- a/examples/GLViewWidget.py +++ b/examples/GLViewWidget.py @@ -6,10 +6,10 @@ Very basic 3D graphics example; create a view widget and add a few items. ## Add path to library (just for examples; you do not need this) import initExample -from pyqtgraph.Qt import QtCore, QtGui +from pyqtgraph.Qt import QtCore, QtGui, mkQApp import pyqtgraph.opengl as gl -app = QtGui.QApplication([]) +app = mkQApp("GLViewWidget Example") w = gl.GLViewWidget() w.opts['distance'] = 20 w.show() diff --git a/examples/GLVolumeItem.py b/examples/GLVolumeItem.py index ca20b127..628ee971 100644 --- a/examples/GLVolumeItem.py +++ b/examples/GLVolumeItem.py @@ -7,10 +7,11 @@ Demonstrates GLVolumeItem for displaying volumetric data. ## Add path to library (just for examples; you do not need this) import initExample +import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui import pyqtgraph.opengl as gl -app = QtGui.QApplication([]) +app = pg.mkQApp("GLVolumeItem Example") w = gl.GLViewWidget() w.opts['distance'] = 200 w.show() diff --git a/examples/GLshaders.py b/examples/GLshaders.py index ce00fc7a..86719c6d 100644 --- a/examples/GLshaders.py +++ b/examples/GLshaders.py @@ -13,7 +13,7 @@ from pyqtgraph.Qt import QtCore, QtGui import pyqtgraph as pg import pyqtgraph.opengl as gl -app = QtGui.QApplication([]) +app = pg.mkQApp("GLShaders Example") w = gl.GLViewWidget() w.show() w.setWindowTitle('pyqtgraph example: GL Shaders') diff --git a/examples/GradientEditor.py b/examples/GradientEditor.py index 1bba4af1..ad8c8eee 100644 --- a/examples/GradientEditor.py +++ b/examples/GradientEditor.py @@ -7,7 +7,7 @@ from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("Gradiant Editor Example") mw = pg.GraphicsView() mw.resize(800,800) mw.show() diff --git a/examples/GradientWidget.py b/examples/GradientWidget.py index d4ad22b8..623171b2 100644 --- a/examples/GradientWidget.py +++ b/examples/GradientWidget.py @@ -12,7 +12,7 @@ import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("Gradiant Widget Example") w = QtGui.QMainWindow() w.show() w.setWindowTitle('pyqtgraph example: GradientWidget') diff --git a/examples/GraphicsLayout.py b/examples/GraphicsLayout.py index 70da7e5c..74d61c10 100644 --- a/examples/GraphicsLayout.py +++ b/examples/GraphicsLayout.py @@ -12,7 +12,7 @@ from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("Gradiant Layout Example") view = pg.GraphicsView() l = pg.GraphicsLayout(border=(100,100,100)) view.setCentralItem(l) diff --git a/examples/GraphicsScene.py b/examples/GraphicsScene.py index c8931444..69be5b53 100644 --- a/examples/GraphicsScene.py +++ b/examples/GraphicsScene.py @@ -6,7 +6,7 @@ from pyqtgraph.Qt import QtCore, QtGui import pyqtgraph as pg from pyqtgraph.GraphicsScene import GraphicsScene -app = QtGui.QApplication([]) +app = pg.mkQApp("GraphicsScene Example") win = pg.GraphicsView() win.show() diff --git a/examples/HistogramLUT.py b/examples/HistogramLUT.py index 082a963c..4c9ef4cf 100644 --- a/examples/HistogramLUT.py +++ b/examples/HistogramLUT.py @@ -11,7 +11,7 @@ from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("Histogram Lookup Table Example") win = QtGui.QMainWindow() win.resize(800,600) win.show() diff --git a/examples/ImageItem.py b/examples/ImageItem.py index a2dc7af3..9982d65c 100644 --- a/examples/ImageItem.py +++ b/examples/ImageItem.py @@ -11,7 +11,7 @@ import numpy as np import pyqtgraph as pg import pyqtgraph.ptime as ptime -app = QtGui.QApplication([]) +app = pg.mkQApp("ImageItem Example") ## Create window with GraphicsView widget win = pg.GraphicsLayoutWidget() diff --git a/examples/ImageView.py b/examples/ImageView.py index 3412f348..d2c3ebc0 100644 --- a/examples/ImageView.py +++ b/examples/ImageView.py @@ -20,7 +20,7 @@ import pyqtgraph as pg # Interpret image data as row-major instead of col-major pg.setConfigOptions(imageAxisOrder='row-major') -app = QtGui.QApplication([]) +app = pg.mkQApp("ImageView Example") ## Create window with ImageView widget win = QtGui.QMainWindow() diff --git a/examples/InfiniteLine.py b/examples/InfiniteLine.py index 55020776..d90ae143 100644 --- a/examples/InfiniteLine.py +++ b/examples/InfiniteLine.py @@ -9,7 +9,7 @@ import numpy as np import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("InfiniteLine Example") win = pg.GraphicsLayoutWidget(show=True, title="Plotting items examples") win.resize(1000,600) diff --git a/examples/JoystickButton.py b/examples/JoystickButton.py index 03c79706..c6965900 100644 --- a/examples/JoystickButton.py +++ b/examples/JoystickButton.py @@ -12,7 +12,7 @@ from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("Joystick Button Example") mw = QtGui.QMainWindow() mw.resize(300,50) mw.setWindowTitle('pyqtgraph example: JoystickButton') diff --git a/examples/LogPlotTest.py b/examples/LogPlotTest.py index 5ae9d17e..1e6bf669 100644 --- a/examples/LogPlotTest.py +++ b/examples/LogPlotTest.py @@ -10,7 +10,7 @@ from pyqtgraph.Qt import QtGui, QtCore import numpy as np import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("Log Plot Example") win = pg.GraphicsLayoutWidget(show=True, title="Basic plotting examples") win.resize(1000,600) diff --git a/examples/MultiPlotSpeedTest.py b/examples/MultiPlotSpeedTest.py index f4295687..e8f7ee85 100644 --- a/examples/MultiPlotSpeedTest.py +++ b/examples/MultiPlotSpeedTest.py @@ -12,7 +12,7 @@ from pyqtgraph.Qt import QtGui, QtCore import numpy as np import pyqtgraph as pg from pyqtgraph.ptime import time -app = QtGui.QApplication([]) +app = pg.mkQApp("MultiPlot Speed Test") plot = pg.plot() plot.setWindowTitle('pyqtgraph example: MultiPlotSpeedTest') diff --git a/examples/MultiPlotWidget.py b/examples/MultiPlotWidget.py index 2800ee44..4802a046 100644 --- a/examples/MultiPlotWidget.py +++ b/examples/MultiPlotWidget.py @@ -14,7 +14,7 @@ except: print("MultiPlot is only used with MetaArray for now (and you do not have the metaarray package)") exit() -app = QtGui.QApplication([]) +app = pg.mkQApp("MultiPlot Widget Example") mw = QtGui.QMainWindow() mw.resize(800,800) pw = MultiPlotWidget() diff --git a/examples/NonUniformImage.py b/examples/NonUniformImage.py index 1c9625ba..9d13cc0b 100644 --- a/examples/NonUniformImage.py +++ b/examples/NonUniformImage.py @@ -41,7 +41,7 @@ P_loss[P_mech > 1.5e5] = np.NaN # green - orange - red Gradients['gor'] = {'ticks': [(0.0, (74, 158, 71)), (0.5, (255, 230, 0)), (1, (191, 79, 76))], 'mode': 'rgb'} -app = QtGui.QApplication([]) +app = pg.mkQApp("NonUniform Image Example") win = QtGui.QMainWindow() cw = pg.GraphicsLayoutWidget() diff --git a/examples/PColorMeshItem.py b/examples/PColorMeshItem.py index 29e89db5..1e5f4e85 100644 --- a/examples/PColorMeshItem.py +++ b/examples/PColorMeshItem.py @@ -11,7 +11,7 @@ import numpy as np import pyqtgraph as pg import pyqtgraph.ptime as ptime -app = QtGui.QApplication([]) +app = pg.mkQApp("PColorMesh Example") ## Create window with GraphicsView widget win = pg.GraphicsLayoutWidget() diff --git a/examples/PlotAutoRange.py b/examples/PlotAutoRange.py index 0e3cd422..35ff72b6 100644 --- a/examples/PlotAutoRange.py +++ b/examples/PlotAutoRange.py @@ -12,7 +12,7 @@ import numpy as np import pyqtgraph as pg #QtGui.QApplication.setGraphicsSystem('raster') -app = QtGui.QApplication([]) +app = pg.mkQApp("Plot Auto Range Example") #mw = QtGui.QMainWindow() #mw.resize(800,800) diff --git a/examples/PlotSpeedTest.py b/examples/PlotSpeedTest.py index 03c9537f..f5d630b4 100644 --- a/examples/PlotSpeedTest.py +++ b/examples/PlotSpeedTest.py @@ -12,7 +12,7 @@ from pyqtgraph.Qt import QtGui, QtCore import numpy as np import pyqtgraph as pg from pyqtgraph.ptime import time -app = QtGui.QApplication([]) +app = pg.mkQApp("Plot Speed Test") p = pg.plot() p.setWindowTitle('pyqtgraph example: PlotSpeedTest') diff --git a/examples/Plotting.py b/examples/Plotting.py index 130698a4..c3cf8b37 100644 --- a/examples/Plotting.py +++ b/examples/Plotting.py @@ -13,7 +13,7 @@ import numpy as np import pyqtgraph as pg #QtGui.QApplication.setGraphicsSystem('raster') -app = QtGui.QApplication([]) +app = pg.mkQApp("Plotting Example") #mw = QtGui.QMainWindow() #mw.resize(800,800) diff --git a/examples/ProgressDialog.py b/examples/ProgressDialog.py index 141d2bb4..0fa9aa34 100644 --- a/examples/ProgressDialog.py +++ b/examples/ProgressDialog.py @@ -9,7 +9,7 @@ import time import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui -app = QtGui.QApplication([]) +app = pg.mkQApp("Progress Dialog Example") def runStage(i): diff --git a/examples/ROIExamples.py b/examples/ROIExamples.py index fe3e4db8..17e55e98 100644 --- a/examples/ROIExamples.py +++ b/examples/ROIExamples.py @@ -32,7 +32,7 @@ arr[8:13, 44:46] = 10 ## create GUI -app = QtGui.QApplication([]) +app = pg.mkQApp("ROI Examples") w = pg.GraphicsLayoutWidget(show=True, size=(1000,800), border=True) w.setWindowTitle('pyqtgraph example: ROI Examples') diff --git a/examples/ROItypes.py b/examples/ROItypes.py index 4352f888..20a83dcb 100644 --- a/examples/ROItypes.py +++ b/examples/ROItypes.py @@ -11,7 +11,7 @@ import pyqtgraph as pg pg.setConfigOptions(imageAxisOrder='row-major') ## create GUI -app = QtGui.QApplication([]) +app = pg.mkQApp("ROI Types Examples") w = pg.GraphicsLayoutWidget(show=True, size=(800,800), border=True) v = w.addViewBox(colspan=2) diff --git a/examples/ScatterPlot.py b/examples/ScatterPlot.py index 295f76e9..070f21c5 100644 --- a/examples/ScatterPlot.py +++ b/examples/ScatterPlot.py @@ -14,7 +14,7 @@ import numpy as np from collections import namedtuple from itertools import chain -app = QtGui.QApplication([]) +app = pg.mkQApp("Scatter Plot Item Example") mw = QtGui.QMainWindow() mw.resize(800,800) view = pg.GraphicsLayoutWidget() ## GraphicsView with GraphicsLayout inserted by default diff --git a/examples/ScatterPlotSpeedTest.py b/examples/ScatterPlotSpeedTest.py index c0381686..cadc16a3 100644 --- a/examples/ScatterPlotSpeedTest.py +++ b/examples/ScatterPlotSpeedTest.py @@ -17,7 +17,7 @@ import numpy as np import pyqtgraph as pg from pyqtgraph.ptime import time #QtGui.QApplication.setGraphicsSystem('raster') -app = QtGui.QApplication([]) +app = pg.mkQApp("Scatter Plot Speed Test") #mw = QtGui.QMainWindow() #mw.resize(800,800) import importlib diff --git a/examples/SpinBox.py b/examples/SpinBox.py index ae8f30bf..74695879 100644 --- a/examples/SpinBox.py +++ b/examples/SpinBox.py @@ -15,7 +15,7 @@ from pyqtgraph.Qt import QtCore, QtGui import numpy as np import ast -app = QtGui.QApplication([]) +app = pg.mkQApp("SpinBox Example") spins = [ diff --git a/examples/Symbols.py b/examples/Symbols.py index a0c57f75..3a683e6d 100755 --- a/examples/Symbols.py +++ b/examples/Symbols.py @@ -10,7 +10,7 @@ import initExample ## Add path to library (just for examples; you do not need th from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("Symbols Examples") win = pg.GraphicsLayoutWidget(show=True, title="Scatter Plot Symbols") win.resize(1000,600) diff --git a/examples/TableWidget.py b/examples/TableWidget.py index cfeac399..0fb1aae4 100644 --- a/examples/TableWidget.py +++ b/examples/TableWidget.py @@ -9,7 +9,7 @@ import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("Table Widget Example") w = pg.TableWidget() w.show() diff --git a/examples/TreeWidget.py b/examples/TreeWidget.py index b1ad3847..56940316 100644 --- a/examples/TreeWidget.py +++ b/examples/TreeWidget.py @@ -10,7 +10,7 @@ from pyqtgraph.Qt import QtCore, QtGui import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("TreeWidget Example") w = pg.TreeWidget() w.setColumnCount(2) diff --git a/examples/VideoSpeedTest.py b/examples/VideoSpeedTest.py index bbc7b6a1..9f7d5c7e 100644 --- a/examples/VideoSpeedTest.py +++ b/examples/VideoSpeedTest.py @@ -38,7 +38,7 @@ parser.add_argument('--size', default='512x512', type=lambda s: tuple([int(x) fo args = parser.parse_args(sys.argv[1:]) #QtGui.QApplication.setGraphicsSystem('raster') -app = QtGui.QApplication([]) +app = pg.mkQApp("Video Speed Test Example") win = QtGui.QMainWindow() win.setWindowTitle('pyqtgraph example: VideoSpeedTest') diff --git a/examples/ViewBox.py b/examples/ViewBox.py index 2ba2094c..f9dbac43 100644 --- a/examples/ViewBox.py +++ b/examples/ViewBox.py @@ -18,7 +18,7 @@ import numpy as np from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("ViewBox Example") mw = QtGui.QMainWindow() mw.setWindowTitle('pyqtgraph example: ViewBox') mw.show() diff --git a/examples/crosshair.py b/examples/crosshair.py index 584eced8..150ed53d 100644 --- a/examples/crosshair.py +++ b/examples/crosshair.py @@ -12,7 +12,7 @@ from pyqtgraph.Qt import QtGui, QtCore from pyqtgraph.Point import Point #generate layout -app = QtGui.QApplication([]) +app = pg.mkQApp("Crosshair Example") win = pg.GraphicsLayoutWidget(show=True) win.setWindowTitle('pyqtgraph example: crosshair') label = pg.LabelItem(justify='right') diff --git a/examples/dockarea.py b/examples/dockarea.py index 9cc79f1b..f87a8da3 100644 --- a/examples/dockarea.py +++ b/examples/dockarea.py @@ -24,7 +24,7 @@ import numpy as np from pyqtgraph.dockarea import * -app = QtGui.QApplication([]) +app = pg.mkQApp("DockArea Example") win = QtGui.QMainWindow() area = DockArea() win.setCentralWidget(area) diff --git a/examples/fractal.py b/examples/fractal.py index d91133a5..3f008141 100644 --- a/examples/fractal.py +++ b/examples/fractal.py @@ -9,7 +9,7 @@ import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui import numpy as np -app = QtGui.QApplication([]) +app = pg.mkQApp("Fractal Example") # Set up UI widgets win = pg.QtGui.QWidget() diff --git a/examples/infiniteline_performance.py b/examples/infiniteline_performance.py index 86264142..9682080e 100644 --- a/examples/infiniteline_performance.py +++ b/examples/infiniteline_performance.py @@ -5,7 +5,7 @@ from pyqtgraph.Qt import QtGui, QtCore import numpy as np import pyqtgraph as pg from pyqtgraph.ptime import time -app = QtGui.QApplication([]) +app = pg.mkQApp("Infinite Line Performance") p = pg.plot() p.setWindowTitle('pyqtgraph performance: InfiniteLine') diff --git a/examples/isocurve.py b/examples/isocurve.py index 63b1699e..1ed30591 100644 --- a/examples/isocurve.py +++ b/examples/isocurve.py @@ -11,7 +11,7 @@ from pyqtgraph.Qt import QtGui, QtCore import numpy as np import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("Isocurve Example") ## make pretty looping data frames = 200 diff --git a/examples/linkedViews.py b/examples/linkedViews.py index 34f2b698..49d68b6e 100644 --- a/examples/linkedViews.py +++ b/examples/linkedViews.py @@ -13,7 +13,7 @@ import numpy as np import pyqtgraph as pg #QtGui.QApplication.setGraphicsSystem('raster') -app = QtGui.QApplication([]) +app = pg.mkQApp("Linked Views Example") #mw = QtGui.QMainWindow() #mw.resize(800,800) diff --git a/examples/logAxis.py b/examples/logAxis.py index 3b30c50b..9a66f114 100644 --- a/examples/logAxis.py +++ b/examples/logAxis.py @@ -9,7 +9,7 @@ from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg -app = QtGui.QApplication([]) +app = pg.mkQApp("Log Axis Example") w = pg.GraphicsLayoutWidget(show=True) w.setWindowTitle('pyqtgraph example: logAxis') diff --git a/examples/multiprocess.py b/examples/multiprocess.py index ba550f7f..2e32b041 100644 --- a/examples/multiprocess.py +++ b/examples/multiprocess.py @@ -40,7 +40,7 @@ print( "process finished") import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui -app = pg.QtGui.QApplication([]) +app = pg.mkQApp("Multiprocess Example") print( "\n=================\nStart QtProcess") import sys diff --git a/examples/optics_demos.py b/examples/optics_demos.py index b2ac5c8a..1f173621 100644 --- a/examples/optics_demos.py +++ b/examples/optics_demos.py @@ -15,7 +15,7 @@ import pyqtgraph as pg import numpy as np from pyqtgraph import Point -app = pg.QtGui.QApplication([]) +app = pg.mkQApp("Optics Demo") w = pg.GraphicsLayoutWidget(show=True, border=0.5) w.resize(1000, 900) diff --git a/examples/parametertree.py b/examples/parametertree.py index acfeac4d..c093eade 100644 --- a/examples/parametertree.py +++ b/examples/parametertree.py @@ -14,7 +14,7 @@ import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui -app = QtGui.QApplication([]) +app = pg.mkQApp("Parameter Tree Example") import pyqtgraph.parametertree.parameterTypes as pTypes from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType diff --git a/examples/template.py b/examples/template.py index 6b5e1f75..d39c6fb8 100644 --- a/examples/template.py +++ b/examples/template.py @@ -8,10 +8,10 @@ Description of example import initExample ## Add path to library (just for examples; you do not need this) import pyqtgraph as pg -from pyqtgraph.Qt import QtCore, QtGui +from pyqtgraph.Qt import QtCore, QtGui, mkQApp import numpy as np -app = QtGui.QApplication([]) +app = mkQApp() # win.setWindowTitle('pyqtgraph example: ____') diff --git a/pyqtgraph/Qt.py b/pyqtgraph/Qt.py index 5323c46c..9709a482 100644 --- a/pyqtgraph/Qt.py +++ b/pyqtgraph/Qt.py @@ -457,8 +457,8 @@ USE_PYQT4 = QT_LIB == PYQT4 USE_PYQT5 = QT_LIB == PYQT5 -## Make sure we have Qt >= 4.7 -versionReq = [4, 7] +## Make sure we have Qt >= 5.12 +versionReq = [5, 12] m = re.match(r'(\d+)\.(\d+).*', QtVersion) if m is not None and list(map(int, m.groups())) < versionReq: print(list(map(int, m.groups()))) @@ -482,7 +482,6 @@ class App(QtGui.QApplication): color = palette.base().color().name() self.dark_mode = color.lower() != "#ffffff" - QAPP = None def mkQApp(name=None): """ @@ -494,8 +493,20 @@ def mkQApp(name=None): ============== ======================================================== """ global QAPP + QAPP = QtGui.QApplication.instance() if QAPP is None: + # hidpi handling + qtVersionCompare = tuple(map(int, QtVersion.split("."))) + if qtVersionCompare > (6, 0): + # Qt6 seems to support hidpi without needing to do anything so continue + pass + elif qtVersionCompare > (5, 14): + os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1" + QtGui.QApplication.setHighDpiScaleFactorRoundingPolicy(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough) + else: # qt 5.12 and 5.13 + QtGui.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) + QtGui.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) QAPP = App(sys.argv or ["pyqtgraph"]) if name is not None: diff --git a/pyqtgraph/SRTTransform.py b/pyqtgraph/SRTTransform.py index b1aea297..934c6247 100644 --- a/pyqtgraph/SRTTransform.py +++ b/pyqtgraph/SRTTransform.py @@ -172,7 +172,7 @@ if __name__ == '__main__': from . import widgets import GraphicsView from .functions import * - app = QtGui.QApplication([]) + app = pg.mkQApp() win = QtGui.QMainWindow() win.show() cw = GraphicsView.GraphicsView() diff --git a/pyqtgraph/SRTTransform3D.py b/pyqtgraph/SRTTransform3D.py index aedb200b..7d458edd 100644 --- a/pyqtgraph/SRTTransform3D.py +++ b/pyqtgraph/SRTTransform3D.py @@ -227,7 +227,7 @@ if __name__ == '__main__': from . import widgets import GraphicsView from .functions import * - app = QtGui.QApplication([]) + app = pg.mkQApp() win = QtGui.QMainWindow() win.show() cw = GraphicsView.GraphicsView() diff --git a/pyqtgraph/graphicsItems/DateAxisItem.py b/pyqtgraph/graphicsItems/DateAxisItem.py index 3d705e9e..406c28d4 100644 --- a/pyqtgraph/graphicsItems/DateAxisItem.py +++ b/pyqtgraph/graphicsItems/DateAxisItem.py @@ -269,10 +269,10 @@ class DateAxisItem(AxisItem): # Size in pixels a specific tick label will take if self.orientation in ['bottom', 'top']: def sizeOf(text): - return self.fontMetrics.boundingRect(text).width() + padding*self.fontScaleFactor + return self.fontMetrics.boundingRect(text).width() + padding else: def sizeOf(text): - return self.fontMetrics.boundingRect(text).height() + padding*self.fontScaleFactor + return self.fontMetrics.boundingRect(text).height() + padding # Fallback zoom level: Years/Months self.zoomLevel = YEAR_MONTH_ZOOM_LEVEL @@ -314,6 +314,5 @@ class DateAxisItem(AxisItem): self.fontMetrics = p.fontMetrics() # Get font scale factor by current window resolution - self.fontScaleFactor = p.device().logicalDpiX() / 96 return super(DateAxisItem, self).generateDrawSpecs(p) diff --git a/pyqtgraph/multiprocess/processes.py b/pyqtgraph/multiprocess/processes.py index 7f40be2c..24fdebf2 100644 --- a/pyqtgraph/multiprocess/processes.py +++ b/pyqtgraph/multiprocess/processes.py @@ -6,7 +6,7 @@ except ImportError: import pickle from .remoteproxy import RemoteEventHandler, ClosedError, NoResultError, LocalObjectProxy, ObjectProxy -from ..Qt import QT_LIB +from ..Qt import QT_LIB, mkQApp from ..util import cprint # color printing for debugging @@ -451,7 +451,7 @@ def startQtEventLoop(name, port, authkey, ppid, debug=False): app = QtGui.QApplication.instance() #print app if app is None: - app = QtGui.QApplication([]) + app = mkQApp() app.setQuitOnLastWindowClosed(False) ## generally we want the event loop to stay open ## until it is explicitly closed by the parent process. diff --git a/pyqtgraph/opengl/GLViewWidget.py b/pyqtgraph/opengl/GLViewWidget.py index 1426a424..d0761d57 100644 --- a/pyqtgraph/opengl/GLViewWidget.py +++ b/pyqtgraph/opengl/GLViewWidget.py @@ -56,9 +56,41 @@ class GLViewWidget(QtWidgets.QOpenGLWidget): self.keysPressed = {} self.keyTimer = QtCore.QTimer() self.keyTimer.timeout.connect(self.evalKeyState) - self.makeCurrent() + + + @property + def _dpiRatio(self): + return self.devicePixelRatioF() or 1 + + def _updateScreen(self, screen): + self._updatePixelRatio() + if screen is not None: + screen.physicalDotsPerInchChanged.connect(self._updatePixelRatio) + screen.logicalDotsPerInchChanged.connect(self._updatePixelRatio) + + def _updatePixelRatio(self): + event = QtGui.QResizeEvent(self.size(), self.size()) + self.resizeEvent(event) + + def showEvent(self, event): + window = self.window().windowHandle() + window.screenChanged.connect(self._updateScreen) + self._updateScreen(window.screen()) + def width(self): + if self._dpiRatio.is_integer(): + return super().width() + else: + return int(super().width() * self._dpiRatio) + + def height(self): + if self._dpiRatio.is_integer(): + return super().height() + else: + return int(super().height() * self._dpiRatio) + + def reset(self): """ Initialize the widget state or reset the current state to the original state.