merge inp

This commit is contained in:
Guillaume Poulin 2013-09-05 00:28:03 +08:00
commit c02e6184ef
23 changed files with 362 additions and 140 deletions

View File

@ -12,6 +12,7 @@ Contributors:
Christian Gavin Christian Gavin
Michael Cristopher Hogg Michael Cristopher Hogg
Ulrich Leutner Ulrich Leutner
Felix Schill
Requirements: Requirements:
PyQt 4.7+ or PySide PyQt 4.7+ or PySide

View File

@ -130,8 +130,13 @@ def update():
if ui.rawRadio.isChecked(): if ui.rawRadio.isChecked():
ui.rawImg.setImage(data[ptr%data.shape[0]], lut=useLut, levels=useScale) ui.rawImg.setImage(data[ptr%data.shape[0]], lut=useLut, levels=useScale)
ui.stack.setCurrentIndex(1)
elif ui.rawGLRadio.isChecked():
ui.rawGLImg.setImage(data[ptr%data.shape[0]], lut=useLut, levels=useScale)
ui.stack.setCurrentIndex(2)
else: else:
img.setImage(data[ptr%data.shape[0]], autoLevels=False, levels=useScale, lut=useLut) img.setImage(data[ptr%data.shape[0]], autoLevels=False, levels=useScale, lut=useLut)
ui.stack.setCurrentIndex(0)
#img.setImage(data[ptr%data.shape[0]], autoRange=False) #img.setImage(data[ptr%data.shape[0]], autoRange=False)
ptr += 1 ptr += 1

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>985</width> <width>695</width>
<height>674</height> <height>798</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -17,6 +17,37 @@
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0" colspan="4"> <item row="1" column="0" colspan="4">
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QRadioButton" name="rawRadio">
<property name="text">
<string>RawImageWidget</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="gfxRadio">
<property name="text">
<string>GraphicsView + ImageItem</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QStackedWidget" name="stack">
<property name="currentIndex">
<number>2</number>
</property>
<widget class="QWidget" name="page">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="GraphicsView" name="graphicsView"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0"> <item row="0" column="0">
<widget class="RawImageWidget" name="rawImg" native="true"> <widget class="RawImageWidget" name="rawImg" native="true">
<property name="sizePolicy"> <property name="sizePolicy">
@ -27,23 +58,21 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> </layout>
<widget class="GraphicsView" name="graphicsView"/> </widget>
<widget class="QWidget" name="page_3">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="RawImageGLWidget" name="rawGLImg" native="true"/>
</item> </item>
<item row="1" column="0"> </layout>
<widget class="QRadioButton" name="rawRadio"> </widget>
<property name="text">
<string>RawImageWidget (unscaled; faster)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="4" column="0">
<widget class="QRadioButton" name="gfxRadio"> <widget class="QRadioButton" name="rawGLRadio">
<property name="text"> <property name="text">
<string>GraphicsView + ImageItem (scaled; slower)</string> <string>RawGLImageWidget</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -250,6 +279,12 @@
<extends>QDoubleSpinBox</extends> <extends>QDoubleSpinBox</extends>
<header>pyqtgraph</header> <header>pyqtgraph</header>
</customwidget> </customwidget>
<customwidget>
<class>RawImageGLWidget</class>
<extends>QWidget</extends>
<header>pyqtgraph.widgets.RawImageWidget</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file './examples/VideoTemplate.ui' # Form implementation generated from reading ui file './VideoTemplate.ui'
# #
# Created: Sun Nov 4 18:24:20 2012 # Created: Tue Jul 9 23:38:17 2013
# by: PyQt4 UI code generator 4.9.1 # by: PyQt4 UI code generator 4.9.3
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -17,31 +17,55 @@ except AttributeError:
class Ui_MainWindow(object): class Ui_MainWindow(object):
def setupUi(self, MainWindow): def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow")) MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(985, 674) MainWindow.resize(695, 798)
self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget")) self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.gridLayout_2 = QtGui.QGridLayout(self.centralwidget) self.gridLayout_2 = QtGui.QGridLayout(self.centralwidget)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.gridLayout = QtGui.QGridLayout() self.gridLayout = QtGui.QGridLayout()
self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.rawImg = RawImageWidget(self.centralwidget) self.rawRadio = QtGui.QRadioButton(self.centralwidget)
self.rawRadio.setChecked(True)
self.rawRadio.setObjectName(_fromUtf8("rawRadio"))
self.gridLayout.addWidget(self.rawRadio, 3, 0, 1, 1)
self.gfxRadio = QtGui.QRadioButton(self.centralwidget)
self.gfxRadio.setObjectName(_fromUtf8("gfxRadio"))
self.gridLayout.addWidget(self.gfxRadio, 2, 0, 1, 1)
self.stack = QtGui.QStackedWidget(self.centralwidget)
self.stack.setObjectName(_fromUtf8("stack"))
self.page = QtGui.QWidget()
self.page.setObjectName(_fromUtf8("page"))
self.gridLayout_3 = QtGui.QGridLayout(self.page)
self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3"))
self.graphicsView = GraphicsView(self.page)
self.graphicsView.setObjectName(_fromUtf8("graphicsView"))
self.gridLayout_3.addWidget(self.graphicsView, 0, 0, 1, 1)
self.stack.addWidget(self.page)
self.page_2 = QtGui.QWidget()
self.page_2.setObjectName(_fromUtf8("page_2"))
self.gridLayout_4 = QtGui.QGridLayout(self.page_2)
self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4"))
self.rawImg = RawImageWidget(self.page_2)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.rawImg.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.rawImg.sizePolicy().hasHeightForWidth())
self.rawImg.setSizePolicy(sizePolicy) self.rawImg.setSizePolicy(sizePolicy)
self.rawImg.setObjectName(_fromUtf8("rawImg")) self.rawImg.setObjectName(_fromUtf8("rawImg"))
self.gridLayout.addWidget(self.rawImg, 0, 0, 1, 1) self.gridLayout_4.addWidget(self.rawImg, 0, 0, 1, 1)
self.graphicsView = GraphicsView(self.centralwidget) self.stack.addWidget(self.page_2)
self.graphicsView.setObjectName(_fromUtf8("graphicsView")) self.page_3 = QtGui.QWidget()
self.gridLayout.addWidget(self.graphicsView, 0, 1, 1, 1) self.page_3.setObjectName(_fromUtf8("page_3"))
self.rawRadio = QtGui.QRadioButton(self.centralwidget) self.gridLayout_5 = QtGui.QGridLayout(self.page_3)
self.rawRadio.setChecked(True) self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5"))
self.rawRadio.setObjectName(_fromUtf8("rawRadio")) self.rawGLImg = RawImageGLWidget(self.page_3)
self.gridLayout.addWidget(self.rawRadio, 1, 0, 1, 1) self.rawGLImg.setObjectName(_fromUtf8("rawGLImg"))
self.gfxRadio = QtGui.QRadioButton(self.centralwidget) self.gridLayout_5.addWidget(self.rawGLImg, 0, 0, 1, 1)
self.gfxRadio.setObjectName(_fromUtf8("gfxRadio")) self.stack.addWidget(self.page_3)
self.gridLayout.addWidget(self.gfxRadio, 1, 1, 1, 1) self.gridLayout.addWidget(self.stack, 0, 0, 1, 1)
self.rawGLRadio = QtGui.QRadioButton(self.centralwidget)
self.rawGLRadio.setObjectName(_fromUtf8("rawGLRadio"))
self.gridLayout.addWidget(self.rawGLRadio, 4, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 1, 0, 1, 4) self.gridLayout_2.addLayout(self.gridLayout, 1, 0, 1, 4)
self.label = QtGui.QLabel(self.centralwidget) self.label = QtGui.QLabel(self.centralwidget)
self.label.setObjectName(_fromUtf8("label")) self.label.setObjectName(_fromUtf8("label"))
@ -130,12 +154,14 @@ class Ui_MainWindow(object):
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow) self.retranslateUi(MainWindow)
self.stack.setCurrentIndex(2)
QtCore.QMetaObject.connectSlotsByName(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow): def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
self.rawRadio.setText(QtGui.QApplication.translate("MainWindow", "RawImageWidget (unscaled; faster)", None, QtGui.QApplication.UnicodeUTF8)) self.rawRadio.setText(QtGui.QApplication.translate("MainWindow", "RawImageWidget", None, QtGui.QApplication.UnicodeUTF8))
self.gfxRadio.setText(QtGui.QApplication.translate("MainWindow", "GraphicsView + ImageItem (scaled; slower)", None, QtGui.QApplication.UnicodeUTF8)) self.gfxRadio.setText(QtGui.QApplication.translate("MainWindow", "GraphicsView + ImageItem", None, QtGui.QApplication.UnicodeUTF8))
self.rawGLRadio.setText(QtGui.QApplication.translate("MainWindow", "RawGLImageWidget", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("MainWindow", "Data type", None, QtGui.QApplication.UnicodeUTF8)) self.label.setText(QtGui.QApplication.translate("MainWindow", "Data type", None, QtGui.QApplication.UnicodeUTF8))
self.dtypeCombo.setItemText(0, QtGui.QApplication.translate("MainWindow", "uint8", None, QtGui.QApplication.UnicodeUTF8)) self.dtypeCombo.setItemText(0, QtGui.QApplication.translate("MainWindow", "uint8", None, QtGui.QApplication.UnicodeUTF8))
self.dtypeCombo.setItemText(1, QtGui.QApplication.translate("MainWindow", "uint16", None, QtGui.QApplication.UnicodeUTF8)) self.dtypeCombo.setItemText(1, QtGui.QApplication.translate("MainWindow", "uint16", None, QtGui.QApplication.UnicodeUTF8))
@ -150,4 +176,5 @@ class Ui_MainWindow(object):
self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8)) self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8))
self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8)) self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
from pyqtgraph import SpinBox, GradientWidget, GraphicsView, RawImageWidget from pyqtgraph.widgets.RawImageWidget import RawImageGLWidget
from pyqtgraph import GradientWidget, SpinBox, GraphicsView, RawImageWidget

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file './examples/VideoTemplate.ui' # Form implementation generated from reading ui file './VideoTemplate.ui'
# #
# Created: Sun Nov 4 18:24:21 2012 # Created: Tue Jul 9 23:38:19 2013
# by: pyside-uic 0.2.13 running on PySide 1.1.0 # by: pyside-uic 0.2.13 running on PySide 1.1.2
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@ -12,31 +12,55 @@ from PySide import QtCore, QtGui
class Ui_MainWindow(object): class Ui_MainWindow(object):
def setupUi(self, MainWindow): def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow") MainWindow.setObjectName("MainWindow")
MainWindow.resize(985, 674) MainWindow.resize(695, 798)
self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget") self.centralwidget.setObjectName("centralwidget")
self.gridLayout_2 = QtGui.QGridLayout(self.centralwidget) self.gridLayout_2 = QtGui.QGridLayout(self.centralwidget)
self.gridLayout_2.setObjectName("gridLayout_2") self.gridLayout_2.setObjectName("gridLayout_2")
self.gridLayout = QtGui.QGridLayout() self.gridLayout = QtGui.QGridLayout()
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.rawImg = RawImageWidget(self.centralwidget) self.rawRadio = QtGui.QRadioButton(self.centralwidget)
self.rawRadio.setChecked(True)
self.rawRadio.setObjectName("rawRadio")
self.gridLayout.addWidget(self.rawRadio, 3, 0, 1, 1)
self.gfxRadio = QtGui.QRadioButton(self.centralwidget)
self.gfxRadio.setObjectName("gfxRadio")
self.gridLayout.addWidget(self.gfxRadio, 2, 0, 1, 1)
self.stack = QtGui.QStackedWidget(self.centralwidget)
self.stack.setObjectName("stack")
self.page = QtGui.QWidget()
self.page.setObjectName("page")
self.gridLayout_3 = QtGui.QGridLayout(self.page)
self.gridLayout_3.setObjectName("gridLayout_3")
self.graphicsView = GraphicsView(self.page)
self.graphicsView.setObjectName("graphicsView")
self.gridLayout_3.addWidget(self.graphicsView, 0, 0, 1, 1)
self.stack.addWidget(self.page)
self.page_2 = QtGui.QWidget()
self.page_2.setObjectName("page_2")
self.gridLayout_4 = QtGui.QGridLayout(self.page_2)
self.gridLayout_4.setObjectName("gridLayout_4")
self.rawImg = RawImageWidget(self.page_2)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.rawImg.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.rawImg.sizePolicy().hasHeightForWidth())
self.rawImg.setSizePolicy(sizePolicy) self.rawImg.setSizePolicy(sizePolicy)
self.rawImg.setObjectName("rawImg") self.rawImg.setObjectName("rawImg")
self.gridLayout.addWidget(self.rawImg, 0, 0, 1, 1) self.gridLayout_4.addWidget(self.rawImg, 0, 0, 1, 1)
self.graphicsView = GraphicsView(self.centralwidget) self.stack.addWidget(self.page_2)
self.graphicsView.setObjectName("graphicsView") self.page_3 = QtGui.QWidget()
self.gridLayout.addWidget(self.graphicsView, 0, 1, 1, 1) self.page_3.setObjectName("page_3")
self.rawRadio = QtGui.QRadioButton(self.centralwidget) self.gridLayout_5 = QtGui.QGridLayout(self.page_3)
self.rawRadio.setChecked(True) self.gridLayout_5.setObjectName("gridLayout_5")
self.rawRadio.setObjectName("rawRadio") self.rawGLImg = RawImageGLWidget(self.page_3)
self.gridLayout.addWidget(self.rawRadio, 1, 0, 1, 1) self.rawGLImg.setObjectName("rawGLImg")
self.gfxRadio = QtGui.QRadioButton(self.centralwidget) self.gridLayout_5.addWidget(self.rawGLImg, 0, 0, 1, 1)
self.gfxRadio.setObjectName("gfxRadio") self.stack.addWidget(self.page_3)
self.gridLayout.addWidget(self.gfxRadio, 1, 1, 1, 1) self.gridLayout.addWidget(self.stack, 0, 0, 1, 1)
self.rawGLRadio = QtGui.QRadioButton(self.centralwidget)
self.rawGLRadio.setObjectName("rawGLRadio")
self.gridLayout.addWidget(self.rawGLRadio, 4, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 1, 0, 1, 4) self.gridLayout_2.addLayout(self.gridLayout, 1, 0, 1, 4)
self.label = QtGui.QLabel(self.centralwidget) self.label = QtGui.QLabel(self.centralwidget)
self.label.setObjectName("label") self.label.setObjectName("label")
@ -125,12 +149,14 @@ class Ui_MainWindow(object):
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow) self.retranslateUi(MainWindow)
self.stack.setCurrentIndex(2)
QtCore.QMetaObject.connectSlotsByName(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow): def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
self.rawRadio.setText(QtGui.QApplication.translate("MainWindow", "RawImageWidget (unscaled; faster)", None, QtGui.QApplication.UnicodeUTF8)) self.rawRadio.setText(QtGui.QApplication.translate("MainWindow", "RawImageWidget", None, QtGui.QApplication.UnicodeUTF8))
self.gfxRadio.setText(QtGui.QApplication.translate("MainWindow", "GraphicsView + ImageItem (scaled; slower)", None, QtGui.QApplication.UnicodeUTF8)) self.gfxRadio.setText(QtGui.QApplication.translate("MainWindow", "GraphicsView + ImageItem", None, QtGui.QApplication.UnicodeUTF8))
self.rawGLRadio.setText(QtGui.QApplication.translate("MainWindow", "RawGLImageWidget", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("MainWindow", "Data type", None, QtGui.QApplication.UnicodeUTF8)) self.label.setText(QtGui.QApplication.translate("MainWindow", "Data type", None, QtGui.QApplication.UnicodeUTF8))
self.dtypeCombo.setItemText(0, QtGui.QApplication.translate("MainWindow", "uint8", None, QtGui.QApplication.UnicodeUTF8)) self.dtypeCombo.setItemText(0, QtGui.QApplication.translate("MainWindow", "uint8", None, QtGui.QApplication.UnicodeUTF8))
self.dtypeCombo.setItemText(1, QtGui.QApplication.translate("MainWindow", "uint16", None, QtGui.QApplication.UnicodeUTF8)) self.dtypeCombo.setItemText(1, QtGui.QApplication.translate("MainWindow", "uint16", None, QtGui.QApplication.UnicodeUTF8))
@ -145,4 +171,5 @@ class Ui_MainWindow(object):
self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8)) self.fpsLabel.setText(QtGui.QApplication.translate("MainWindow", "FPS", None, QtGui.QApplication.UnicodeUTF8))
self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8)) self.rgbCheck.setText(QtGui.QApplication.translate("MainWindow", "RGB", None, QtGui.QApplication.UnicodeUTF8))
from pyqtgraph import SpinBox, GradientWidget, GraphicsView, RawImageWidget from pyqtgraph.widgets.RawImageWidget import RawImageGLWidget
from pyqtgraph import GradientWidget, SpinBox, GraphicsView, RawImageWidget

View File

@ -67,7 +67,7 @@ params = [
{'name': 'Float', 'type': 'float', 'value': 10.5, 'step': 0.1}, {'name': 'Float', 'type': 'float', 'value': 10.5, 'step': 0.1},
{'name': 'String', 'type': 'str', 'value': "hi"}, {'name': 'String', 'type': 'str', 'value': "hi"},
{'name': 'List', 'type': 'list', 'values': [1,2,3], 'value': 2}, {'name': 'List', 'type': 'list', 'values': [1,2,3], 'value': 2},
{'name': 'Named List', 'type': 'list', 'values': {"one": 1, "two": 2, "three": 3}, 'value': 2}, {'name': 'Named List', 'type': 'list', 'values': {"one": 1, "two": "twosies", "three": [3,3,3]}, 'value': 2},
{'name': 'Boolean', 'type': 'bool', 'value': True, 'tip': "This is a checkbox"}, {'name': 'Boolean', 'type': 'bool', 'value': True, 'tip': "This is a checkbox"},
{'name': 'Color', 'type': 'color', 'value': "FF0", 'tip': "This is a color button"}, {'name': 'Color', 'type': 'color', 'value': "FF0", 'tip': "This is a color button"},
{'name': 'Gradient', 'type': 'colormap'}, {'name': 'Gradient', 'type': 'colormap'},
@ -139,13 +139,18 @@ p.param('Save/Restore functionality', 'Restore State').sigActivated.connect(rest
## Create two ParameterTree widgets, both accessing the same data ## Create two ParameterTree widgets, both accessing the same data
t = ParameterTree() t = ParameterTree()
t.setParameters(p, showTop=False) t.setParameters(p, showTop=False)
t.show()
t.setWindowTitle('pyqtgraph example: Parameter Tree') t.setWindowTitle('pyqtgraph example: Parameter Tree')
t.resize(400,800)
t2 = ParameterTree() t2 = ParameterTree()
t2.setParameters(p, showTop=False) t2.setParameters(p, showTop=False)
t2.show()
t2.resize(400,800) win = QtGui.QWidget()
layout = QtGui.QGridLayout()
win.setLayout(layout)
layout.addWidget(QtGui.QLabel("These are two views of the same data. They should always display the same values."), 0, 0, 1, 2)
layout.addWidget(t, 1, 0, 1, 1)
layout.addWidget(t2, 1, 1, 1, 1)
win.show()
win.resize(800,800)
## test save/restore ## test save/restore
s = p.saveState() s = p.saveState()

View File

@ -255,7 +255,7 @@ def exit():
## close file handles ## close file handles
os.closerange(3, 4096) ## just guessing on the maximum descriptor count.. os.closerange(3, 4096) ## just guessing on the maximum descriptor count..
os._exit(os.EX_OK) os._exit(0)
@ -281,7 +281,7 @@ def plot(*args, **kargs):
#if len(args)+len(kargs) > 0: #if len(args)+len(kargs) > 0:
#w.plot(*args, **kargs) #w.plot(*args, **kargs)
pwArgList = ['title', 'labels', 'name', 'left', 'right', 'top', 'bottom'] pwArgList = ['title', 'labels', 'name', 'left', 'right', 'top', 'bottom', 'background']
pwArgs = {} pwArgs = {}
dataArgs = {} dataArgs = {}
for k in kargs: for k in kargs:

View File

@ -119,7 +119,7 @@ class Exporter(object):
else: else:
childs = root.childItems() childs = root.childItems()
rootItem = [root] rootItem = [root]
childs.sort(lambda a,b: cmp(a.zValue(), b.zValue())) childs.sort(key=lambda a: a.zValue())
while len(childs) > 0: while len(childs) > 0:
ch = childs.pop(0) ch = childs.pop(0)
tree = self.getPaintItems(ch) tree = self.getPaintItems(ch)

View File

@ -1,6 +1,6 @@
from .Exporter import Exporter from .Exporter import Exporter
from pyqtgraph.parametertree import Parameter from pyqtgraph.parametertree import Parameter
from pyqtgraph.Qt import QtGui, QtCore, QtSvg from pyqtgraph.Qt import QtGui, QtCore, QtSvg, USE_PYSIDE
import pyqtgraph as pg import pyqtgraph as pg
import numpy as np import numpy as np
@ -17,7 +17,11 @@ class ImageExporter(Exporter):
scene = item.scene() scene = item.scene()
else: else:
scene = item scene = item
bg = scene.views()[0].backgroundBrush().color() bgbrush = scene.views()[0].backgroundBrush()
bg = bgbrush.color()
if bgbrush.style() == QtCore.Qt.NoBrush:
bg.setAlpha(0)
self.params = Parameter(name='params', type='group', children=[ self.params = Parameter(name='params', type='group', children=[
{'name': 'width', 'type': 'int', 'value': tr.width(), 'limits': (0, None)}, {'name': 'width', 'type': 'int', 'value': tr.width(), 'limits': (0, None)},
{'name': 'height', 'type': 'int', 'value': tr.height(), 'limits': (0, None)}, {'name': 'height', 'type': 'int', 'value': tr.height(), 'limits': (0, None)},
@ -42,7 +46,10 @@ class ImageExporter(Exporter):
def export(self, fileName=None, toBytes=False, copy=False): def export(self, fileName=None, toBytes=False, copy=False):
if fileName is None and not toBytes and not copy: if fileName is None and not toBytes and not copy:
if USE_PYSIDE:
filter = ["*."+str(f) for f in QtGui.QImageWriter.supportedImageFormats()] filter = ["*."+str(f) for f in QtGui.QImageWriter.supportedImageFormats()]
else:
filter = ["*."+bytes(f).decode('utf-8') for f in QtGui.QImageWriter.supportedImageFormats()]
preferred = ['*.png', '*.tif', '*.jpg'] preferred = ['*.png', '*.tif', '*.jpg']
for p in preferred[::-1]: for p in preferred[::-1]:
if p in filter: if p in filter:

View File

@ -376,10 +376,10 @@ class Flowchart(Node):
#tdeps[t] = lastNode #tdeps[t] = lastNode
if lastInd is not None: if lastInd is not None:
dels.append((lastInd+1, t)) dels.append((lastInd+1, t))
dels.sort(lambda a,b: cmp(b[0], a[0])) #dels.sort(lambda a,b: cmp(b[0], a[0]))
dels.sort(key=lambda a: a[0], reverse=True)
for i, t in dels: for i, t in dels:
ops.insert(i, ('d', t)) ops.insert(i, ('d', t))
return ops return ops
@ -491,7 +491,8 @@ class Flowchart(Node):
self.clear() self.clear()
Node.restoreState(self, state) Node.restoreState(self, state)
nodes = state['nodes'] nodes = state['nodes']
nodes.sort(lambda a, b: cmp(a['pos'][0], b['pos'][0])) #nodes.sort(lambda a, b: cmp(a['pos'][0], b['pos'][0]))
nodes.sort(key=lambda a: a['pos'][0])
for n in nodes: for n in nodes:
if n['name'] in self._nodes: if n['name'] in self._nodes:
#self._nodes[n['name']].graphicsItem().moveBy(*n['pos']) #self._nodes[n['name']].graphicsItem().moveBy(*n['pos'])

View File

@ -261,6 +261,9 @@ class PlotCurveItem(GraphicsObject):
by :func:`mkBrush <pyqtgraph.mkBrush>` is allowed. by :func:`mkBrush <pyqtgraph.mkBrush>` is allowed.
antialias (bool) Whether to use antialiasing when drawing. This antialias (bool) Whether to use antialiasing when drawing. This
is disabled by default because it decreases performance. is disabled by default because it decreases performance.
stepMode If True, two orthogonal lines are drawn for each sample
as steps. This is commonly used when drawing histograms.
Note that in this case, len(x) == len(y) + 1
============== ======================================================== ============== ========================================================
If non-keyword arguments are used, they will be interpreted as If non-keyword arguments are used, they will be interpreted as

View File

@ -475,7 +475,7 @@ class PlotDataItem(GraphicsObject):
if self.xClean is None: if self.xClean is None:
nanMask = np.isnan(self.xData) | np.isnan(self.yData) | np.isinf(self.xData) | np.isinf(self.yData) nanMask = np.isnan(self.xData) | np.isnan(self.yData) | np.isinf(self.xData) | np.isinf(self.yData)
if any(nanMask): if nanMask.any():
self.dataMask = ~nanMask self.dataMask = ~nanMask
self.xClean = self.xData[self.dataMask] self.xClean = self.xData[self.dataMask]
self.yClean = self.yData[self.dataMask] self.yClean = self.yData[self.dataMask]
@ -495,10 +495,7 @@ class PlotDataItem(GraphicsObject):
##y = resample(y[:len(x)*ds], len(x)) ## scipy.signal.resample causes nasty ringing ##y = resample(y[:len(x)*ds], len(x)) ## scipy.signal.resample causes nasty ringing
#y = y[::ds] #y = y[::ds]
if self.opts['fftMode']: if self.opts['fftMode']:
f = np.fft.fft(y) / len(y) x,y = self._fourierTransform(x, y)
y = abs(f[1:len(f)/2])
dt = x[-1] - x[0]
x = np.linspace(0, 0.5*len(x)/dt, len(y))
if self.opts['logMode'][0]: if self.opts['logMode'][0]:
x = np.log10(x) x = np.log10(x)
if self.opts['logMode'][1]: if self.opts['logMode'][1]:
@ -666,8 +663,21 @@ class PlotDataItem(GraphicsObject):
self.xDisp = self.yDisp = None self.xDisp = self.yDisp = None
self.updateItems() self.updateItems()
def _fourierTransform(self, x, y):
## Perform fourier transform. If x values are not sampled uniformly,
## then use interpolate.griddata to resample before taking fft.
dx = np.diff(x)
uniform = not np.any(np.abs(dx-dx[0]) > (abs(dx[0]) / 1000.))
if not uniform:
import scipy.interpolate as interp
x2 = np.linspace(x[0], x[-1], len(x))
y = interp.griddata(x, y, x2, method='linear')
x = x2
f = np.fft.fft(y) / len(y)
y = abs(f[1:len(f)/2])
dt = x[-1] - x[0]
x = np.linspace(0, 0.5*len(x)/dt, len(y))
return x, y
def dataType(obj): def dataType(obj):
if hasattr(obj, '__len__') and len(obj) == 0: if hasattr(obj, '__len__') and len(obj) == 0:

View File

@ -49,7 +49,13 @@ class ROI(GraphicsObject):
sigRegionChanged Emitted any time the position of the ROI changes, sigRegionChanged Emitted any time the position of the ROI changes,
including while it is being dragged by the user. including while it is being dragged by the user.
sigHoverEvent Emitted when the mouse hovers over the ROI. sigHoverEvent Emitted when the mouse hovers over the ROI.
sigClicked Emitted when the user clicks on the ROI sigClicked Emitted when the user clicks on the ROI.
Note that clicking is disabled by default to prevent
stealing clicks from objects behind the ROI. To
enable clicking, call
roi.setAcceptedMouseButtons(QtCore.Qt.LeftButton).
See QtGui.QGraphicsItem documentation for more
details.
sigRemoveRequested Emitted when the user selects 'remove' from the sigRemoveRequested Emitted when the user selects 'remove' from the
ROI's context menu (if available). ROI's context menu (if available).
----------------------- ---------------------------------------------------- ----------------------- ----------------------------------------------------

View File

@ -139,6 +139,7 @@ class ViewBox(GraphicsWidget):
self.rbScaleBox = QtGui.QGraphicsRectItem(0, 0, 1, 1) self.rbScaleBox = QtGui.QGraphicsRectItem(0, 0, 1, 1)
self.rbScaleBox.setPen(fn.mkPen((255,255,100), width=1)) self.rbScaleBox.setPen(fn.mkPen((255,255,100), width=1))
self.rbScaleBox.setBrush(fn.mkBrush(255,255,0,100)) self.rbScaleBox.setBrush(fn.mkBrush(255,255,0,100))
self.rbScaleBox.setZValue(1e9)
self.rbScaleBox.hide() self.rbScaleBox.hide()
self.addItem(self.rbScaleBox, ignoreBounds=True) self.addItem(self.rbScaleBox, ignoreBounds=True)
@ -797,7 +798,10 @@ class ViewBox(GraphicsWidget):
y2 = vr.bottom() y2 = vr.bottom()
else: ## views overlap; line them up else: ## views overlap; line them up
upp = float(vr.height()) / vg.height() upp = float(vr.height()) / vg.height()
y2 = vr.bottom() - (sg.y()-vg.y()) * upp if self.yInverted():
y2 = vr.bottom() + (sg.bottom()-vg.bottom()) * upp
else:
y2 = vr.bottom() + (sg.top()-vg.top()) * upp
y1 = y2 - sg.height() * upp y1 = y2 - sg.height() * upp
self.enableAutoRange(ViewBox.YAxis, False) self.enableAutoRange(ViewBox.YAxis, False)
self.setYRange(y1, y2, padding=0) self.setYRange(y1, y2, padding=0)

View File

@ -325,7 +325,8 @@ class QtProcess(Process):
GUI. GUI.
- A QTimer is also started on the parent process which polls for requests - A QTimer is also started on the parent process which polls for requests
from the child process. This allows Qt signals emitted within the child from the child process. This allows Qt signals emitted within the child
process to invoke slots on the parent process and vice-versa. process to invoke slots on the parent process and vice-versa. This can
be disabled using processRequests=False in the constructor.
Example:: Example::
@ -342,17 +343,28 @@ class QtProcess(Process):
def __init__(self, **kwds): def __init__(self, **kwds):
if 'target' not in kwds: if 'target' not in kwds:
kwds['target'] = startQtEventLoop kwds['target'] = startQtEventLoop
self._processRequests = kwds.pop('processRequests', True)
Process.__init__(self, **kwds) Process.__init__(self, **kwds)
self.startEventTimer() self.startEventTimer()
def startEventTimer(self): def startEventTimer(self):
from pyqtgraph.Qt import QtGui, QtCore ## avoid module-level import to keep bootstrap snappy. from pyqtgraph.Qt import QtGui, QtCore ## avoid module-level import to keep bootstrap snappy.
self.timer = QtCore.QTimer() self.timer = QtCore.QTimer()
if self._processRequests:
app = QtGui.QApplication.instance() app = QtGui.QApplication.instance()
if app is None: if app is None:
raise Exception("Must create QApplication before starting QtProcess") raise Exception("Must create QApplication before starting QtProcess, or use QtProcess(processRequests=False)")
self.startRequestProcessing()
def startRequestProcessing(self, interval=0.01):
"""Start listening for requests coming from the child process.
This allows signals to be connected from the child process to the parent.
"""
self.timer.timeout.connect(self.processRequests) self.timer.timeout.connect(self.processRequests)
self.timer.start(10) self.timer.start(interval*1000)
def stopRequestProcessing(self):
self.timer.stop()
def processRequests(self): def processRequests(self):
try: try:

View File

@ -167,7 +167,7 @@ class GLViewWidget(QtOpenGL.QGLWidget):
else: else:
items = item.childItems() items = item.childItems()
items.append(item) items.append(item)
items.sort(key=lambda x: x.depthValue()) items.sort(key=lambda a: a.depthValue())
for i in items: for i in items:
if not i.visible(): if not i.visible():
continue continue

View File

@ -30,8 +30,9 @@ class GLLinePlotItem(GLGraphicsItem):
Arguments: Arguments:
------------------------------------------------------------------------ ------------------------------------------------------------------------
pos (N,3) array of floats specifying point locations. pos (N,3) array of floats specifying point locations.
color tuple of floats (0.0-1.0) specifying color (N,4) array of floats (0.0-1.0) or
a color for the entire item. tuple of floats specifying
a single color for the entire item.
width float specifying line width width float specifying line width
antialias enables smooth line drawing antialias enables smooth line drawing
==================== ================================================== ==================== ==================================================
@ -71,8 +72,17 @@ class GLLinePlotItem(GLGraphicsItem):
self.setupGLState() self.setupGLState()
glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_VERTEX_ARRAY)
try: try:
glVertexPointerf(self.pos) glVertexPointerf(self.pos)
if isinstance(self.color, np.ndarray):
glEnableClientState(GL_COLOR_ARRAY)
glColorPointerf(self.color)
else:
if isinstance(self.color, QtGui.QColor):
glColor4f(*fn.glColor(self.color))
else:
glColor4f(*self.color) glColor4f(*self.color)
glLineWidth(self.width) glLineWidth(self.width)
#glPointSize(self.width) #glPointSize(self.width)
@ -85,6 +95,7 @@ class GLLinePlotItem(GLGraphicsItem):
glDrawArrays(GL_LINE_STRIP, 0, int(self.pos.size / self.pos.shape[-1])) glDrawArrays(GL_LINE_STRIP, 0, int(self.pos.size / self.pos.shape[-1]))
finally: finally:
glDisableClientState(GL_COLOR_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_VERTEX_ARRAY)

View File

@ -1,3 +1,4 @@
import OpenGL
from OpenGL.GL import * from OpenGL.GL import *
from OpenGL.GL import shaders from OpenGL.GL import shaders
import re import re
@ -218,6 +219,8 @@ class Shader(object):
if self.compiled is None: if self.compiled is None:
try: try:
self.compiled = shaders.compileShader(self.code, self.shaderType) self.compiled = shaders.compileShader(self.code, self.shaderType)
except OpenGL.NullFunctionError:
raise Exception("This OpenGL implementation does not support shader programs; many features on pyqtgraph will not work.")
except RuntimeError as exc: except RuntimeError as exc:
## Format compile errors a bit more nicely ## Format compile errors a bit more nicely
if len(exc.args) == 3: if len(exc.args) == 3:

View File

@ -1,6 +1,7 @@
from pyqtgraph.Qt import QtCore, QtGui from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.widgets.TreeWidget import TreeWidget from pyqtgraph.widgets.TreeWidget import TreeWidget
import os, weakref, re import os, weakref, re
from .ParameterItem import ParameterItem
#import functions as fn #import functions as fn
@ -103,7 +104,7 @@ class ParameterTree(TreeWidget):
sel = self.selectedItems() sel = self.selectedItems()
if len(sel) != 1: if len(sel) != 1:
sel = None sel = None
if self.lastSel is not None: if self.lastSel is not None and isinstance(self.lastSel, ParameterItem):
self.lastSel.selected(False) self.lastSel.selected(False)
if sel is None: if sel is None:
self.lastSel = None self.lastSel = None

View File

@ -476,32 +476,16 @@ class ListParameterItem(WidgetParameterItem):
return w return w
def value(self): def value(self):
#vals = self.param.opts['limits']
key = asUnicode(self.widget.currentText()) key = asUnicode(self.widget.currentText())
#if isinstance(vals, dict):
#return vals[key]
#else:
#return key
#print key, self.forward
return self.forward.get(key, None) return self.forward.get(key, None)
def setValue(self, val): def setValue(self, val):
#vals = self.param.opts['limits']
#if isinstance(vals, dict):
#key = None
#for k,v in vals.iteritems():
#if v == val:
#key = k
#if key is None:
#raise Exception("Value '%s' not allowed." % val)
#else:
#key = unicode(val)
self.targetValue = val self.targetValue = val
if val not in self.reverse: if val not in self.reverse[0]:
self.widget.setCurrentIndex(0) self.widget.setCurrentIndex(0)
else: else:
key = self.reverse[val] key = self.reverse[1][self.reverse[0].index(val)]
ind = self.widget.findText(key) ind = self.widget.findText(key)
self.widget.setCurrentIndex(ind) self.widget.setCurrentIndex(ind)
@ -531,8 +515,8 @@ class ListParameter(Parameter):
itemClass = ListParameterItem itemClass = ListParameterItem
def __init__(self, **opts): def __init__(self, **opts):
self.forward = OrderedDict() ## name: value self.forward = OrderedDict() ## {name: value, ...}
self.reverse = OrderedDict() ## value: name self.reverse = ([], []) ## ([value, ...], [name, ...])
## Parameter uses 'limits' option to define the set of allowed values ## Parameter uses 'limits' option to define the set of allowed values
if 'values' in opts: if 'values' in opts:
@ -547,23 +531,40 @@ class ListParameter(Parameter):
Parameter.setLimits(self, limits) Parameter.setLimits(self, limits)
#print self.name(), self.value(), limits #print self.name(), self.value(), limits
if self.value() not in self.reverse and len(self.reverse) > 0: if len(self.reverse) > 0 and self.value() not in self.reverse[0]:
self.setValue(list(self.reverse.keys())[0]) self.setValue(self.reverse[0][0])
#def addItem(self, name, value=None):
#if name in self.forward:
#raise Exception("Name '%s' is already in use for this parameter" % name)
#limits = self.opts['limits']
#if isinstance(limits, dict):
#limits = limits.copy()
#limits[name] = value
#self.setLimits(limits)
#else:
#if value is not None:
#raise Exception ## raise exception or convert to dict?
#limits = limits[:]
#limits.append(name)
## what if limits == None?
@staticmethod @staticmethod
def mapping(limits): def mapping(limits):
## Return forward and reverse mapping dictionaries given a limit specification ## Return forward and reverse mapping objects given a limit specification
forward = OrderedDict() ## name: value forward = OrderedDict() ## {name: value, ...}
reverse = OrderedDict() ## value: name reverse = ([], []) ## ([value, ...], [name, ...])
if isinstance(limits, dict): if isinstance(limits, dict):
for k, v in limits.items(): for k, v in limits.items():
forward[k] = v forward[k] = v
reverse[v] = k reverse[0].append(v)
reverse[1].append(k)
else: else:
for v in limits: for v in limits:
n = asUnicode(v) n = asUnicode(v)
forward[n] = v forward[n] = v
reverse[v] = n reverse[0].append(v)
reverse[1].append(n)
return forward, reverse return forward, reverse
registerParameterType('list', ListParameter, override=True) registerParameterType('list', ListParameter, override=True)
@ -615,13 +616,20 @@ registerParameterType('action', ActionParameter, override=True)
class TextParameterItem(WidgetParameterItem): class TextParameterItem(WidgetParameterItem):
def __init__(self, param, depth): def __init__(self, param, depth):
WidgetParameterItem.__init__(self, param, depth) WidgetParameterItem.__init__(self, param, depth)
self.hideWidget = False
self.subItem = QtGui.QTreeWidgetItem() self.subItem = QtGui.QTreeWidgetItem()
self.addChild(self.subItem) self.addChild(self.subItem)
def treeWidgetChanged(self): def treeWidgetChanged(self):
## TODO: fix so that superclass method can be called
## (WidgetParameter should just natively support this style)
#WidgetParameterItem.treeWidgetChanged(self)
self.treeWidget().setFirstItemColumnSpanned(self.subItem, True) self.treeWidget().setFirstItemColumnSpanned(self.subItem, True)
self.treeWidget().setItemWidget(self.subItem, 0, self.textBox) self.treeWidget().setItemWidget(self.subItem, 0, self.textBox)
self.setExpanded(True)
# for now, these are copied from ParameterItem.treeWidgetChanged
self.setHidden(not self.param.opts.get('visible', True))
self.setExpanded(self.param.opts.get('expanded', True))
def makeWidget(self): def makeWidget(self):
self.textBox = QtGui.QTextEdit() self.textBox = QtGui.QTextEdit()

View File

@ -82,6 +82,7 @@ class GraphicsView(QtGui.QGraphicsView):
## This might help, but it's probably dangerous in the general case.. ## This might help, but it's probably dangerous in the general case..
#self.setOptimizationFlag(self.DontSavePainterState, True) #self.setOptimizationFlag(self.DontSavePainterState, True)
self.setBackgroundRole(QtGui.QPalette.NoRole)
self.setBackground(background) self.setBackground(background)
self.setFocusPolicy(QtCore.Qt.StrongFocus) self.setFocusPolicy(QtCore.Qt.StrongFocus)
@ -138,9 +139,6 @@ class GraphicsView(QtGui.QGraphicsView):
self._background = background self._background = background
if background == 'default': if background == 'default':
background = pyqtgraph.getConfigOption('background') background = pyqtgraph.getConfigOption('background')
if background is None:
self.setBackgroundRole(QtGui.QPalette.NoRole)
else:
brush = fn.mkBrush(background) brush = fn.mkBrush(background)
self.setBackgroundBrush(brush) self.setBackgroundBrush(brush)

View File

@ -40,10 +40,12 @@ class PlotWidget(GraphicsView):
For all For all
other methods, use :func:`getPlotItem <pyqtgraph.PlotWidget.getPlotItem>`. other methods, use :func:`getPlotItem <pyqtgraph.PlotWidget.getPlotItem>`.
""" """
def __init__(self, parent=None, **kargs): def __init__(self, parent=None, background='default', **kargs):
"""When initializing PlotWidget, all keyword arguments except *parent* are passed """When initializing PlotWidget, *parent* and *background* are passed to
:func:`GraphicsWidget.__init__() <pyqtgraph.GraphicsWidget.__init__>`
and all others are passed
to :func:`PlotItem.__init__() <pyqtgraph.PlotItem.__init__>`.""" to :func:`PlotItem.__init__() <pyqtgraph.PlotItem.__init__>`."""
GraphicsView.__init__(self, parent) GraphicsView.__init__(self, parent, background=background)
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
self.enableMouse(False) self.enableMouse(False)
self.plotItem = PlotItem(**kargs) self.plotItem = PlotItem(**kargs)

View File

@ -11,8 +11,8 @@ import numpy as np
class RawImageWidget(QtGui.QWidget): class RawImageWidget(QtGui.QWidget):
""" """
Widget optimized for very fast video display. Widget optimized for very fast video display.
Generally using an ImageItem inside GraphicsView is fast enough, Generally using an ImageItem inside GraphicsView is fast enough.
but if you need even more performance, this widget is about as fast as it gets (but only in unscaled mode). On some systems this may provide faster video. See the VideoSpeedTest example for benchmarking.
""" """
def __init__(self, parent=None, scaled=False): def __init__(self, parent=None, scaled=False):
""" """
@ -59,26 +59,82 @@ class RawImageWidget(QtGui.QWidget):
p.end() p.end()
if HAVE_OPENGL: if HAVE_OPENGL:
from OpenGL.GL import *
class RawImageGLWidget(QtOpenGL.QGLWidget): class RawImageGLWidget(QtOpenGL.QGLWidget):
""" """
Similar to RawImageWidget, but uses a GL widget to do all drawing. Similar to RawImageWidget, but uses a GL widget to do all drawing.
Generally this will be about as fast as using GraphicsView + ImageItem, Perfomance varies between platforms; see examples/VideoSpeedTest for benchmarking.
but performance may vary on some platforms.
""" """
def __init__(self, parent=None, scaled=False): def __init__(self, parent=None, scaled=False):
QtOpenGL.QGLWidget.__init__(self, parent=None) QtOpenGL.QGLWidget.__init__(self, parent=None)
self.scaled = scaled self.scaled = scaled
self.image = None self.image = None
self.uploaded = False
self.smooth = False
self.opts = None
def setImage(self, img): def setImage(self, img, *args, **kargs):
self.image = fn.makeQImage(img) """
img must be ndarray of shape (x,y), (x,y,3), or (x,y,4).
Extra arguments are sent to functions.makeARGB
"""
self.opts = (img, args, kargs)
self.image = None
self.uploaded = False
self.update() self.update()
def paintEvent(self, ev): def initializeGL(self):
self.texture = glGenTextures(1)
def uploadTexture(self):
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, self.texture)
if self.smooth:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
else:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER)
#glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER)
shape = self.image.shape
### Test texture dimensions first
#glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, shape[0], shape[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
#if glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH) == 0:
#raise Exception("OpenGL failed to create 2D texture (%dx%d); too large for this hardware." % shape[:2])
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shape[0], shape[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, self.image.transpose((1,0,2)))
glDisable(GL_TEXTURE_2D)
def paintGL(self):
if self.image is None: if self.image is None:
if self.opts is None:
return return
p = QtGui.QPainter(self) img, args, kwds = self.opts
p.drawImage(self.rect(), self.image) kwds['useRGBA'] = True
p.end() self.image, alpha = fn.makeARGB(img, *args, **kwds)
if not self.uploaded:
self.uploadTexture()
glViewport(0, 0, self.width(), self.height())
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, self.texture)
glColor4f(1,1,1,1)
glBegin(GL_QUADS)
glTexCoord2f(0,0)
glVertex3f(-1,-1,0)
glTexCoord2f(1,0)
glVertex3f(1, -1, 0)
glTexCoord2f(1,1)
glVertex3f(1, 1, 0)
glTexCoord2f(0,1)
glVertex3f(-1, 1, 0)
glEnd()
glDisable(GL_TEXTURE_3D)