diff options
Diffstat (limited to 'examples')
164 files changed, 1972 insertions, 385 deletions
diff --git a/examples/3d/3d.pyproject b/examples/3d/3d.pyproject new file mode 100644 index 000000000..4c85ba5a4 --- /dev/null +++ b/examples/3d/3d.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["simple3d.py"] +} diff --git a/examples/3d/simple3d.py b/examples/3d/simple3d.py index 2fad3c403..cea662a95 100644 --- a/examples/3d/simple3d.py +++ b/examples/3d/simple3d.py @@ -42,10 +42,9 @@ """PySide2 port of the qt3d/simple-cpp example from Qt v5.x""" import sys -from PySide2.QtCore import(Property, QObject, QPropertyAnimation, Signal, Slot) -from PySide2.QtGui import (QGuiApplication, QMatrix4x4, QQuaternion, QVector3D, QWindow) +from PySide2.QtCore import(Property, QObject, QPropertyAnimation, Signal) +from PySide2.QtGui import (QGuiApplication, QMatrix4x4, QQuaternion, QVector3D) from PySide2.Qt3DCore import (Qt3DCore) -from PySide2.Qt3DRender import (Qt3DRender) from PySide2.Qt3DExtras import (Qt3DExtras) class OrbitTransformController(QObject): diff --git a/examples/axcontainer/axcontainer.pyproject b/examples/axcontainer/axcontainer.pyproject new file mode 100644 index 000000000..b054d6f18 --- /dev/null +++ b/examples/axcontainer/axcontainer.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["axviewer.py"] +} diff --git a/examples/axcontainer/axviewer.py b/examples/axcontainer/axviewer.py index 539c31787..e9083d8f4 100644 --- a/examples/axcontainer/axviewer.py +++ b/examples/axcontainer/axviewer.py @@ -43,9 +43,8 @@ import sys from PySide2.QtAxContainer import QAxSelect, QAxWidget -from PySide2.QtGui import QKeySequence -from PySide2.QtWidgets import (QAction, qApp, QApplication, QDialog, QFileDialog, - QMainWindow, QMenu, QMenuBar, QMessageBox, QToolBar) +from PySide2.QtWidgets import (QAction, QApplication, QDialog, + QMainWindow, QMessageBox, QToolBar) class MainWindow(QMainWindow): diff --git a/examples/charts/audio.py b/examples/charts/audio.py index 256fe3a96..f899ac4c8 100644 --- a/examples/charts/audio.py +++ b/examples/charts/audio.py @@ -41,11 +41,10 @@ """PySide2 port of the charts/audio example from Qt v5.x""" -import os import sys from PySide2.QtCharts import QtCharts -from PySide2.QtCore import QPointF, QRect, QSize -from PySide2.QtMultimedia import (QAudio, QAudioDeviceInfo, QAudioFormat, +from PySide2.QtCore import QPointF +from PySide2.QtMultimedia import (QAudioDeviceInfo, QAudioFormat, QAudioInput) from PySide2.QtWidgets import QApplication, QMainWindow, QMessageBox diff --git a/examples/charts/callout.py b/examples/charts/callout.py index a7aff6282..54e8eaf24 100644 --- a/examples/charts/callout.py +++ b/examples/charts/callout.py @@ -42,7 +42,7 @@ """PySide2 port of the Callout example from Qt v5.x""" import sys -from PySide2.QtWidgets import (QApplication, QWidget, QGraphicsScene, +from PySide2.QtWidgets import (QApplication, QGraphicsScene, QGraphicsView, QGraphicsSimpleTextItem, QGraphicsItem) from PySide2.QtCore import Qt, QPointF, QRectF, QRect from PySide2.QtCharts import QtCharts @@ -192,7 +192,7 @@ class View(QGraphicsView): self._coordX = QGraphicsSimpleTextItem(self._chart) self._coordX.setPos( self._chart.size().width()/2 - 50, self._chart.size().height()) - self._coordX.setText("X: "); + self._coordX.setText("X: ") self._coordY = QGraphicsSimpleTextItem(self._chart) self._coordY.setPos( self._chart.size().width()/2 + 50, self._chart.size().height()) @@ -232,7 +232,7 @@ class View(QGraphicsView): QGraphicsView.mouseMoveEvent(self, event) def keepCallout(self): - self._callouts.append(self._tooltip); + self._callouts.append(self._tooltip) self._tooltip = Callout(self._chart) def tooltip(self, point, state): diff --git a/examples/charts/charts.pyproject b/examples/charts/charts.pyproject new file mode 100644 index 000000000..a4e6c01c1 --- /dev/null +++ b/examples/charts/charts.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["percentbarchart.py", "donutbreakdown.py", "legend.py", "nesteddonuts.py", "modeldata.py", "lineandbar.py", "memoryusage.py", "callout.py", "audio.py"] +} diff --git a/examples/charts/chartthemes/chartthemes.pyproject b/examples/charts/chartthemes/chartthemes.pyproject new file mode 100644 index 000000000..4a0b38795 --- /dev/null +++ b/examples/charts/chartthemes/chartthemes.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "README.md", "themewidget.ui"] +} diff --git a/examples/charts/chartthemes/main.py b/examples/charts/chartthemes/main.py index 1ba725b7d..e18e92cf2 100644 --- a/examples/charts/chartthemes/main.py +++ b/examples/charts/chartthemes/main.py @@ -41,7 +41,7 @@ """PySide2 port of the Chart Themes example from Qt v5.x""" import sys -from PySide2.QtCore import qApp, QPointF, Qt +from PySide2.QtCore import QPointF, Qt from PySide2.QtGui import QColor, QPainter, QPalette from PySide2.QtWidgets import (QApplication, QMainWindow, QSizePolicy, QWidget) diff --git a/examples/charts/chartthemes/ui_themewidget.py b/examples/charts/chartthemes/ui_themewidget.py index aa673eea9..bf6703963 100644 --- a/examples/charts/chartthemes/ui_themewidget.py +++ b/examples/charts/chartthemes/ui_themewidget.py @@ -18,59 +18,59 @@ class Ui_ThemeWidgetForm(object): if ThemeWidgetForm.objectName(): ThemeWidgetForm.setObjectName(u"ThemeWidgetForm") ThemeWidgetForm.resize(900, 600) - self.gridLayout = QGridLayout(ThemeWidgetForm); + self.gridLayout = QGridLayout(ThemeWidgetForm) self.gridLayout.setObjectName(u"gridLayout") - self.horizontalLayout = QHBoxLayout(); + self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName(u"horizontalLayout") self.themeLabel = QLabel(ThemeWidgetForm) self.themeLabel.setObjectName(u"themeLabel") - self.horizontalLayout.addWidget(self.themeLabel); + self.horizontalLayout.addWidget(self.themeLabel) self.themeComboBox = QComboBox(ThemeWidgetForm) self.themeComboBox.setObjectName(u"themeComboBox") - self.horizontalLayout.addWidget(self.themeComboBox); + self.horizontalLayout.addWidget(self.themeComboBox) self.animatedLabel = QLabel(ThemeWidgetForm) self.animatedLabel.setObjectName(u"animatedLabel") - self.horizontalLayout.addWidget(self.animatedLabel); + self.horizontalLayout.addWidget(self.animatedLabel) self.animatedComboBox = QComboBox(ThemeWidgetForm) self.animatedComboBox.setObjectName(u"animatedComboBox") - self.horizontalLayout.addWidget(self.animatedComboBox); + self.horizontalLayout.addWidget(self.animatedComboBox) self.legendLabel = QLabel(ThemeWidgetForm) self.legendLabel.setObjectName(u"legendLabel") - self.horizontalLayout.addWidget(self.legendLabel); + self.horizontalLayout.addWidget(self.legendLabel) self.legendComboBox = QComboBox(ThemeWidgetForm) self.legendComboBox.setObjectName(u"legendComboBox") - self.horizontalLayout.addWidget(self.legendComboBox); + self.horizontalLayout.addWidget(self.legendComboBox) self.antialiasCheckBox = QCheckBox(ThemeWidgetForm) self.antialiasCheckBox.setObjectName(u"antialiasCheckBox") self.antialiasCheckBox.setChecked(False) - self.horizontalLayout.addWidget(self.antialiasCheckBox); + self.horizontalLayout.addWidget(self.antialiasCheckBox) - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum); + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - self.horizontalLayout.addItem(self.horizontalSpacer); + self.horizontalLayout.addItem(self.horizontalSpacer) - self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 3); + self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 3) self.retranslateUi(ThemeWidgetForm) - self.themeComboBox.currentIndexChanged.connect(ThemeWidgetForm.updateUI); - self.antialiasCheckBox.toggled.connect(ThemeWidgetForm.updateUI); - self.legendComboBox.currentIndexChanged.connect(ThemeWidgetForm.updateUI); - self.animatedComboBox.currentIndexChanged.connect(ThemeWidgetForm.updateUI); + self.themeComboBox.currentIndexChanged.connect(ThemeWidgetForm.updateUI) + self.antialiasCheckBox.toggled.connect(ThemeWidgetForm.updateUI) + self.legendComboBox.currentIndexChanged.connect(ThemeWidgetForm.updateUI) + self.animatedComboBox.currentIndexChanged.connect(ThemeWidgetForm.updateUI) QMetaObject.connectSlotsByName(ThemeWidgetForm) # setupUi diff --git a/examples/charts/donutbreakdown.py b/examples/charts/donutbreakdown.py index 28a48b8ac..712bea577 100644 --- a/examples/charts/donutbreakdown.py +++ b/examples/charts/donutbreakdown.py @@ -114,7 +114,7 @@ class DonutBreakdownChart(QtCharts.QChart): def recalculate_angles(self): angle = 0 - slices = self.main_series.slices(); + slices = self.main_series.slices() for pie_slice in slices: breakdown_series = pie_slice.get_breakdown_series() breakdown_series.setPieStartAngle(angle) diff --git a/examples/charts/memoryusage.py b/examples/charts/memoryusage.py index b6f665b3d..4954b9cd7 100644 --- a/examples/charts/memoryusage.py +++ b/examples/charts/memoryusage.py @@ -43,7 +43,7 @@ import os import sys -from PySide2.QtCore import QRect, QSize, QProcess +from PySide2.QtCore import QProcess from PySide2.QtWidgets import QApplication, QMainWindow from PySide2.QtCharts import QtCharts @@ -105,13 +105,13 @@ class MainWindow(QMainWindow): self.series = QtCharts.QPieSeries() for item in memoryUsage: - self.series.append(item[0], item[1]); + self.series.append(item[0], item[1]) slice = self.series.slices()[0] - slice.setExploded(); - slice.setLabelVisible(); + slice.setExploded() + slice.setLabelVisible() self.chart = QtCharts.QChart() - self.chart.addSeries(self.series); + self.chart.addSeries(self.series) self.chartView = QtCharts.QChartView(self.chart) self.setCentralWidget(self.chartView) diff --git a/examples/charts/modeldata.py b/examples/charts/modeldata.py index be63cf3d2..aa53e74ba 100644 --- a/examples/charts/modeldata.py +++ b/examples/charts/modeldata.py @@ -95,7 +95,7 @@ class CustomTableModel(QAbstractTableModel): if rect.contains(index.column(), index.row()): return QColor(color) # cell not mapped return white color - return QColor(Qt.white); + return QColor(Qt.white) return None def setData(self, index, value, role=Qt.EditRole): @@ -159,7 +159,7 @@ class TableWidget(QWidget): # get the color of the series and use it for showing the mapped area seriesColorHex = "{}".format(self.series.pen().color().name()) - self.model.add_mapping(seriesColorHex, QRect(2, 0, 2, self.model.rowCount())); + self.model.add_mapping(seriesColorHex, QRect(2, 0, 2, self.model.rowCount())) self.chart.createDefaultAxes() self.chart_view = QtCharts.QChartView(self.chart) diff --git a/examples/corelib/threads/threads.pyproject b/examples/corelib/threads/threads.pyproject new file mode 100644 index 000000000..254aabec0 --- /dev/null +++ b/examples/corelib/threads/threads.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["mandelbrot.py"] +} diff --git a/examples/corelib/tools/codecs/codecs.py b/examples/corelib/tools/codecs/codecs.py index 5139bb6db..a3c063c04 100644 --- a/examples/corelib/tools/codecs/codecs.py +++ b/examples/corelib/tools/codecs/codecs.py @@ -42,7 +42,7 @@ """PySide2 port of the widgets/tools/codecs example from Qt v5.x""" -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets def codec_name(codec): @@ -164,7 +164,7 @@ class MainWindow(QtWidgets.QMainWindow): self.aboutAct = QtWidgets.QAction("&About", self, triggered=self.about) self.aboutQtAct = QtWidgets.QAction("About &Qt", self, - triggered=QtWidgets.qApp.aboutQt) + triggered=qApp.aboutQt) def createMenus(self): self.saveAsMenu = QtWidgets.QMenu("&Save As", self) diff --git a/examples/corelib/tools/codecs/codecs.pyproject b/examples/corelib/tools/codecs/codecs.pyproject new file mode 100644 index 000000000..72237d60b --- /dev/null +++ b/examples/corelib/tools/codecs/codecs.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["codecs.py"] +} diff --git a/examples/corelib/tools/settingseditor/settingseditor.py b/examples/corelib/tools/settingseditor/settingseditor.py index 9d691046f..4cd262568 100644 --- a/examples/corelib/tools/settingseditor/settingseditor.py +++ b/examples/corelib/tools/settingseditor/settingseditor.py @@ -146,7 +146,7 @@ class MainWindow(QtWidgets.QMainWindow): self.aboutAct = QtWidgets.QAction("&About", self, triggered=self.about) self.aboutQtAct = QtWidgets.QAction("About &Qt", self, - triggered=QtWidgets.qApp.aboutQt) + triggered=qApp.aboutQt) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") diff --git a/examples/corelib/tools/settingseditor/settingseditor.pyproject b/examples/corelib/tools/settingseditor/settingseditor.pyproject new file mode 100644 index 000000000..9eb637af2 --- /dev/null +++ b/examples/corelib/tools/settingseditor/settingseditor.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["settingseditor.py"] +} diff --git a/examples/corelib/tools/tools.pyproject b/examples/corelib/tools/tools.pyproject new file mode 100644 index 000000000..63f9c6198 --- /dev/null +++ b/examples/corelib/tools/tools.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["regexp.py"] +} diff --git a/examples/datavisualization/bars3d.py b/examples/datavisualization/bars3d.py index 36043b82c..d0a69a802 100644 --- a/examples/datavisualization/bars3d.py +++ b/examples/datavisualization/bars3d.py @@ -41,10 +41,9 @@ """PySide2 QtDataVisualization example""" -import os import sys -from PySide2.QtCore import QRect, QSize, QProcess, Qt -from PySide2.QtGui import QGuiApplication, QScreen, QWindow +from PySide2.QtCore import Qt +from PySide2.QtGui import QGuiApplication from PySide2.QtWidgets import QApplication, QSizePolicy, QMainWindow, QWidget from PySide2.QtDataVisualization import QtDataVisualization diff --git a/examples/datavisualization/datavisualization.pyproject b/examples/datavisualization/datavisualization.pyproject new file mode 100644 index 000000000..415133f09 --- /dev/null +++ b/examples/datavisualization/datavisualization.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["bars3d.py"] +} diff --git a/examples/declarative/declarative.pyproject b/examples/declarative/declarative.pyproject new file mode 100644 index 000000000..e64c1d934 --- /dev/null +++ b/examples/declarative/declarative.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["view.qml", "scrolling.py", "usingmodel.py"] +} diff --git a/examples/declarative/extending/chapter1-basics/basics.py b/examples/declarative/extending/chapter1-basics/basics.py index edb612739..95ee36362 100644 --- a/examples/declarative/extending/chapter1-basics/basics.py +++ b/examples/declarative/extending/chapter1-basics/basics.py @@ -59,9 +59,9 @@ class PieChart (QQuickPaintedItem): def paint(self, painter): pen = QPen(self.color, 2) - painter.setPen(pen); - painter.setRenderHints(QPainter.Antialiasing, True); - painter.drawPie(self.boundingRect().adjusted(1,1,-1,-1), 90 * 16, 290 * 16); + painter.setPen(pen) + painter.setRenderHints(QPainter.Antialiasing, True) + painter.drawPie(self.boundingRect().adjusted(1,1,-1,-1), 90 * 16, 290 * 16) def getColor(self): return self._color @@ -83,7 +83,7 @@ class PieChart (QQuickPaintedItem): if __name__ == '__main__': app = QGuiApplication(sys.argv) - qmlRegisterType(PieChart, 'Charts', 1, 0, 'PieChart'); + qmlRegisterType(PieChart, 'Charts', 1, 0, 'PieChart') view = QQuickView() view.setResizeMode(QQuickView.SizeRootObjectToView) diff --git a/examples/declarative/extending/chapter1-basics/chapter1-basics.pyproject b/examples/declarative/extending/chapter1-basics/chapter1-basics.pyproject new file mode 100644 index 000000000..869556bb8 --- /dev/null +++ b/examples/declarative/extending/chapter1-basics/chapter1-basics.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["basics.py", "app.qml"] +} diff --git a/examples/declarative/extending/chapter2-methods/chapter2-methods.pyproject b/examples/declarative/extending/chapter2-methods/chapter2-methods.pyproject new file mode 100644 index 000000000..cdf33be7f --- /dev/null +++ b/examples/declarative/extending/chapter2-methods/chapter2-methods.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["methods.py", "app.qml"] +} diff --git a/examples/declarative/extending/chapter2-methods/methods.py b/examples/declarative/extending/chapter2-methods/methods.py index 44e248f07..1d02628cd 100644 --- a/examples/declarative/extending/chapter2-methods/methods.py +++ b/examples/declarative/extending/chapter2-methods/methods.py @@ -59,9 +59,9 @@ class PieChart (QQuickPaintedItem): def paint(self, painter): pen = QPen(self.color, 2) - painter.setPen(pen); - painter.setRenderHints(QPainter.Antialiasing, True); - painter.drawPie(self.boundingRect().adjusted(1,1,-1,-1), 90 * 16, 290 * 16); + painter.setPen(pen) + painter.setRenderHints(QPainter.Antialiasing, True) + painter.drawPie(self.boundingRect().adjusted(1,1,-1,-1), 90 * 16, 290 * 16) def getColor(self): return self._color @@ -88,7 +88,7 @@ class PieChart (QQuickPaintedItem): if __name__ == '__main__': app = QGuiApplication(sys.argv) - qmlRegisterType(PieChart, 'Charts', 1, 0, 'PieChart'); + qmlRegisterType(PieChart, 'Charts', 1, 0, 'PieChart') view = QQuickView() view.setResizeMode(QQuickView.SizeRootObjectToView) diff --git a/examples/declarative/extending/chapter3-bindings/bindings.py b/examples/declarative/extending/chapter3-bindings/bindings.py index 4c3895538..f20fc0bcc 100644 --- a/examples/declarative/extending/chapter3-bindings/bindings.py +++ b/examples/declarative/extending/chapter3-bindings/bindings.py @@ -60,9 +60,9 @@ class PieChart (QQuickPaintedItem): def paint(self, painter): pen = QPen(self._color, 2) - painter.setPen(pen); - painter.setRenderHints(QPainter.Antialiasing, True); - painter.drawPie(self.boundingRect().adjusted(1,1,-1,-1), 90 * 16, 290 * 16); + painter.setPen(pen) + painter.setRenderHints(QPainter.Antialiasing, True) + painter.drawPie(self.boundingRect().adjusted(1,1,-1,-1), 90 * 16, 290 * 16) def getColor(self): return self._color @@ -93,7 +93,7 @@ class PieChart (QQuickPaintedItem): if __name__ == '__main__': app = QGuiApplication(sys.argv) - qmlRegisterType(PieChart, 'Charts', 1, 0, 'PieChart'); + qmlRegisterType(PieChart, 'Charts', 1, 0, 'PieChart') view = QQuickView() view.setResizeMode(QQuickView.SizeRootObjectToView) diff --git a/examples/declarative/extending/chapter3-bindings/chapter3-bindings.pyproject b/examples/declarative/extending/chapter3-bindings/chapter3-bindings.pyproject new file mode 100644 index 000000000..6e21f86f9 --- /dev/null +++ b/examples/declarative/extending/chapter3-bindings/chapter3-bindings.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["app.qml", "bindings.py"] +} diff --git a/examples/declarative/extending/chapter4-customPropertyTypes/chapter4-customPropertyTypes.pyproject b/examples/declarative/extending/chapter4-customPropertyTypes/chapter4-customPropertyTypes.pyproject new file mode 100644 index 000000000..af1cfefb7 --- /dev/null +++ b/examples/declarative/extending/chapter4-customPropertyTypes/chapter4-customPropertyTypes.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["app.qml", "customPropertyTypes.py"] +} diff --git a/examples/declarative/extending/chapter4-customPropertyTypes/customPropertyTypes.py b/examples/declarative/extending/chapter4-customPropertyTypes/customPropertyTypes.py index 7dee9d2a6..66e4dea7c 100644 --- a/examples/declarative/extending/chapter4-customPropertyTypes/customPropertyTypes.py +++ b/examples/declarative/extending/chapter4-customPropertyTypes/customPropertyTypes.py @@ -98,8 +98,8 @@ class PieChart (QQuickItem): if __name__ == '__main__': app = QGuiApplication(sys.argv) - qmlRegisterType(PieChart, 'Charts', 1, 0, 'PieChart'); - qmlRegisterType(PieSlice, "Charts", 1, 0, "PieSlice"); + qmlRegisterType(PieChart, 'Charts', 1, 0, 'PieChart') + qmlRegisterType(PieSlice, "Charts", 1, 0, "PieSlice") view = QQuickView() view.setResizeMode(QQuickView.SizeRootObjectToView) diff --git a/examples/declarative/extending/chapter5-listproperties/chapter5-listproperties.pyproject b/examples/declarative/extending/chapter5-listproperties/chapter5-listproperties.pyproject new file mode 100644 index 000000000..a3f89d575 --- /dev/null +++ b/examples/declarative/extending/chapter5-listproperties/chapter5-listproperties.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["app.qml", "listproperties.py"] +} diff --git a/examples/declarative/scrolling.py b/examples/declarative/scrolling.py index 085cb17e2..b4a0ee270 100644 --- a/examples/declarative/scrolling.py +++ b/examples/declarative/scrolling.py @@ -45,7 +45,6 @@ import os import sys from PySide2.QtCore import QUrl from PySide2.QtGui import QGuiApplication -import PySide2.QtQml from PySide2.QtQuick import QQuickView # This example uses a QML file to show a scrolling list containing diff --git a/examples/declarative/signals/pytoqml1/main.py b/examples/declarative/signals/pytoqml1/main.py index 769dd0e1c..218d885a0 100644 --- a/examples/declarative/signals/pytoqml1/main.py +++ b/examples/declarative/signals/pytoqml1/main.py @@ -45,7 +45,6 @@ import os import sys from PySide2.QtCore import QTimer, QUrl from PySide2.QtGui import QGuiApplication -import PySide2.QtQml from PySide2.QtQuick import QQuickView if __name__ == '__main__': diff --git a/examples/declarative/signals/pytoqml1/pytoqml1.pyproject b/examples/declarative/signals/pytoqml1/pytoqml1.pyproject new file mode 100644 index 000000000..e6f087cce --- /dev/null +++ b/examples/declarative/signals/pytoqml1/pytoqml1.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "view.qml"] +} diff --git a/examples/declarative/signals/qmltopy1/main.py b/examples/declarative/signals/qmltopy1/main.py index 4c993b452..1342dbadb 100644 --- a/examples/declarative/signals/qmltopy1/main.py +++ b/examples/declarative/signals/qmltopy1/main.py @@ -45,7 +45,6 @@ import os import sys from PySide2.QtCore import QObject, QUrl, Slot from PySide2.QtGui import QGuiApplication -import PySide2.QtQml from PySide2.QtQuick import QQuickView class Console(QObject): diff --git a/examples/declarative/signals/qmltopy1/qmltopy1.pyproject b/examples/declarative/signals/qmltopy1/qmltopy1.pyproject new file mode 100644 index 000000000..e6f087cce --- /dev/null +++ b/examples/declarative/signals/qmltopy1/qmltopy1.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "view.qml"] +} diff --git a/examples/declarative/signals/qmltopy2/main.py b/examples/declarative/signals/qmltopy2/main.py index 10cbd8870..9b0aca815 100644 --- a/examples/declarative/signals/qmltopy2/main.py +++ b/examples/declarative/signals/qmltopy2/main.py @@ -45,7 +45,6 @@ import os import sys from PySide2.QtCore import QObject, QUrl, Slot from PySide2.QtGui import QGuiApplication -import PySide2.QtQml from PySide2.QtQuick import QQuickView class RotateValue(QObject): diff --git a/examples/declarative/signals/qmltopy2/qmltopy2.pyproject b/examples/declarative/signals/qmltopy2/qmltopy2.pyproject new file mode 100644 index 000000000..e6f087cce --- /dev/null +++ b/examples/declarative/signals/qmltopy2/qmltopy2.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "view.qml"] +} diff --git a/examples/declarative/signals/qmltopy3/main.py b/examples/declarative/signals/qmltopy3/main.py index 8de1eacee..485dd62f5 100644 --- a/examples/declarative/signals/qmltopy3/main.py +++ b/examples/declarative/signals/qmltopy3/main.py @@ -43,9 +43,8 @@ from __future__ import print_function import os import sys -from PySide2.QtCore import QObject, QUrl +from PySide2.QtCore import QUrl from PySide2.QtGui import QGuiApplication -import PySide2.QtQml from PySide2.QtQuick import QQuickView def sayThis(s): diff --git a/examples/declarative/signals/qmltopy3/qmltopy3.pyproject b/examples/declarative/signals/qmltopy3/qmltopy3.pyproject new file mode 100644 index 000000000..e6f087cce --- /dev/null +++ b/examples/declarative/signals/qmltopy3/qmltopy3.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "view.qml"] +} diff --git a/examples/declarative/signals/qmltopy4/main.py b/examples/declarative/signals/qmltopy4/main.py index a6cc3580f..d165e61f3 100644 --- a/examples/declarative/signals/qmltopy4/main.py +++ b/examples/declarative/signals/qmltopy4/main.py @@ -45,7 +45,6 @@ import os import sys from PySide2.QtCore import QObject, QUrl from PySide2.QtGui import QGuiApplication -import PySide2.QtQml from PySide2.QtQuick import QQuickView def sayThis(s): diff --git a/examples/declarative/signals/qmltopy4/qmltopy4.pyproject b/examples/declarative/signals/qmltopy4/qmltopy4.pyproject new file mode 100644 index 000000000..e6f087cce --- /dev/null +++ b/examples/declarative/signals/qmltopy4/qmltopy4.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "view.qml"] +} diff --git a/examples/declarative/textproperties/textproperties.pyproject b/examples/declarative/textproperties/textproperties.pyproject new file mode 100644 index 000000000..e6f087cce --- /dev/null +++ b/examples/declarative/textproperties/textproperties.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "view.qml"] +} diff --git a/examples/declarative/usingmodel.py b/examples/declarative/usingmodel.py index 2629cf35f..9b67bd0d4 100644 --- a/examples/declarative/usingmodel.py +++ b/examples/declarative/usingmodel.py @@ -43,7 +43,6 @@ from __future__ import print_function import os import sys -import PySide2.QtQml from PySide2.QtCore import QAbstractListModel, Qt, QUrl, QByteArray from PySide2.QtGui import QGuiApplication from PySide2.QtQuick import QQuickView diff --git a/examples/examples.pyproject b/examples/examples.pyproject index 559989f9f..330884f05 100644 --- a/examples/examples.pyproject +++ b/examples/examples.pyproject @@ -16,7 +16,7 @@ "declarative/signals/qmltopy3/main.py", "declarative/signals/qmltopy4/main.py", "declarative/usingmodel.py", - "installer_test/hello.py" + "installer_test/hello.py", "macextras/macpasteboardmime.py", "multimedia/audiooutput.py", "multimedia/camera.py", diff --git a/examples/external/matplotlib/requirements.txt b/examples/external/matplotlib/requirements.txt new file mode 100644 index 000000000..6ccafc3f9 --- /dev/null +++ b/examples/external/matplotlib/requirements.txt @@ -0,0 +1 @@ +matplotlib diff --git a/examples/external/matplotlib/widget_3dplot.py b/examples/external/matplotlib/widget_3dplot.py new file mode 100644 index 000000000..b96405661 --- /dev/null +++ b/examples/external/matplotlib/widget_3dplot.py @@ -0,0 +1,242 @@ +############################################################################# +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +import sys + +import numpy as np +from matplotlib.backends.backend_qt5agg import FigureCanvas +from matplotlib.figure import Figure +from mpl_toolkits.mplot3d import axes3d +from PySide2.QtCore import Qt, Slot +from PySide2.QtGui import QKeySequence +from PySide2.QtWidgets import (QAction, QApplication, QComboBox, QHBoxLayout, + QHeaderView, QLabel, QMainWindow, QSlider, + QTableWidget, QTableWidgetItem, QVBoxLayout, + QWidget) + + +"""This example implements the interaction between Qt Widgets and a 3D +matplotlib plot""" + + +class ApplicationWindow(QMainWindow): + def __init__(self, parent=None): + QMainWindow.__init__(self, parent) + + self.column_names = ["Column A", "Column B", "Column C"] + + # Central widget + self._main = QWidget() + self.setCentralWidget(self._main) + + # Main menu bar + self.menu = self.menuBar() + self.menu_file = self.menu.addMenu("File") + exit = QAction("Exit", self, triggered=qApp.quit) + self.menu_file.addAction(exit) + + self.menu_about = self.menu.addMenu("&About") + about = QAction("About Qt", self, shortcut=QKeySequence(QKeySequence.HelpContents), + triggered=qApp.aboutQt) + self.menu_about.addAction(about) + + # Figure (Left) + self.fig = Figure(figsize=(5, 3)) + self.canvas = FigureCanvas(self.fig) + + # Sliders (Left) + self.slider_azim = QSlider(minimum=0, maximum=360, orientation=Qt.Horizontal) + self.slider_elev = QSlider(minimum=0, maximum=360, orientation=Qt.Horizontal) + + self.slider_azim_layout = QHBoxLayout() + self.slider_azim_layout.addWidget(QLabel("{}".format(self.slider_azim.minimum()))) + self.slider_azim_layout.addWidget(self.slider_azim) + self.slider_azim_layout.addWidget(QLabel("{}".format(self.slider_azim.maximum()))) + + self.slider_elev_layout = QHBoxLayout() + self.slider_elev_layout.addWidget(QLabel("{}".format(self.slider_elev.minimum()))) + self.slider_elev_layout.addWidget(self.slider_elev) + self.slider_elev_layout.addWidget(QLabel("{}".format(self.slider_elev.maximum()))) + + # Table (Right) + self.table = QTableWidget() + header = self.table.horizontalHeader() + header.setSectionResizeMode(QHeaderView.Stretch) + + # ComboBox (Right) + self.combo = QComboBox() + self.combo.addItems(["Wired", "Surface", "Triangular Surface", "Sphere"]) + + # Right layout + rlayout = QVBoxLayout() + rlayout.setContentsMargins(1, 1, 1, 1) + rlayout.addWidget(QLabel("Plot type:")) + rlayout.addWidget(self.combo) + rlayout.addWidget(self.table) + + # Left layout + llayout = QVBoxLayout() + rlayout.setContentsMargins(1, 1, 1, 1) + llayout.addWidget(self.canvas, 88) + llayout.addWidget(QLabel("Azimuth:"), 1) + llayout.addLayout(self.slider_azim_layout, 5) + llayout.addWidget(QLabel("Elevation:"), 1) + llayout.addLayout(self.slider_elev_layout, 5) + + # Main layout + layout = QHBoxLayout(self._main) + layout.addLayout(llayout, 70) + layout.addLayout(rlayout, 30) + + # Signal and Slots connections + self.combo.currentTextChanged.connect(self.combo_option) + self.slider_azim.valueChanged.connect(self.rotate_azim) + self.slider_elev.valueChanged.connect(self.rotate_elev) + + # Initial setup + self.plot_wire() + self._ax.view_init(30, 30) + self.slider_azim.setValue(30) + self.slider_elev.setValue(30) + self.fig.canvas.mpl_connect("button_release_event", self.on_click) + + # Matplotlib slot method + def on_click(self, event): + azim, elev = self._ax.azim, self._ax.elev + self.slider_azim.setValue(azim + 180) + self.slider_elev.setValue(elev + 180) + + # Utils methods + + def set_table_data(self, X, Y, Z): + for i in range(len(X)): + self.table.setItem(i, 0, QTableWidgetItem("{:.2f}".format(X[i]))) + self.table.setItem(i, 1, QTableWidgetItem("{:.2f}".format(Y[i]))) + self.table.setItem(i, 2, QTableWidgetItem("{:.2f}".format(Z[i]))) + + def set_canvas_table_configuration(self, row_count, data): + self.fig.set_canvas(self.canvas) + self._ax = self.canvas.figure.add_subplot(projection="3d") + + self._ax.set_xlabel(self.column_names[0]) + self._ax.set_ylabel(self.column_names[1]) + self._ax.set_zlabel(self.column_names[2]) + + self.table.setRowCount(row_count) + self.table.setColumnCount(3) + self.table.setHorizontalHeaderLabels(self.column_names) + self.set_table_data(data[0], data[1], data[2]) + + # Plot methods + + def plot_wire(self): + # Data + self.X, self.Y, self.Z = axes3d.get_test_data(0.03) + + self.set_canvas_table_configuration(len(self.X[0]), (self.X[0], self.Y[0], self.Z[0])) + self._ax.plot_wireframe(self.X, self.Y, self.Z, rstride=10, cstride=10, cmap="viridis") + self.canvas.draw() + + def plot_surface(self): + # Data + self.X, self.Y = np.meshgrid(np.linspace(-6, 6, 30), np.linspace(-6, 6, 30)) + self.Z = np.sin(np.sqrt(self.X ** 2 + self.Y ** 2)) + + self.set_canvas_table_configuration(len(self.X[0]), (self.X[0], self.Y[0], self.Z[0])) + self._ax.plot_surface(self.X, self.Y, self.Z, + rstride=1, cstride=1, cmap="viridis", edgecolor="none") + self.canvas.draw() + + def plot_triangular_surface(self): + # Data + radii = np.linspace(0.125, 1.0, 8) + angles = np.linspace(0, 2 * np.pi, 36, endpoint=False)[..., np.newaxis] + self.X = np.append(0, (radii * np.cos(angles)).flatten()) + self.Y = np.append(0, (radii * np.sin(angles)).flatten()) + self.Z = np.sin(-self.X * self.Y) + + self.set_canvas_table_configuration(len(self.X), (self.X, self.Y, self.Z)) + self._ax.plot_trisurf(self.X, self.Y, self.Z, linewidth=0.2, antialiased=True) + self.canvas.draw() + + def plot_sphere(self): + # Data + u = np.linspace(0, 2 * np.pi, 100) + v = np.linspace(0, np.pi, 100) + self.X = 10 * np.outer(np.cos(u), np.sin(v)) + self.Y = 10 * np.outer(np.sin(u), np.sin(v)) + self.Z = 9 * np.outer(np.ones(np.size(u)), np.cos(v)) + + self.set_canvas_table_configuration(len(self.X), (self.X[0], self.Y[0], self.Z[0])) + self._ax.plot_surface(self.X, self.Y, self.Z) + self.canvas.draw() + + # Slots + + @Slot() + def combo_option(self, text): + if text == "Wired": + self.plot_wire() + elif text == "Surface": + self.plot_surface() + elif text == "Triangular Surface": + self.plot_triangular_surface() + elif text == "Sphere": + self.plot_sphere() + + @Slot() + def rotate_azim(self, value): + self._ax.view_init(self._ax.elev, value) + self.fig.set_canvas(self.canvas) + self.canvas.draw() + + @Slot() + def rotate_elev(self, value): + self._ax.view_init(value, self._ax.azim) + self.fig.set_canvas(self.canvas) + self.canvas.draw() + + +if __name__ == "__main__": + app = QApplication(sys.argv) + w = ApplicationWindow() + w.setFixedSize(1280, 720) + w.show() + app.exec_() diff --git a/examples/external/opencv/requirements.txt b/examples/external/opencv/requirements.txt new file mode 100644 index 000000000..0dd006bbc --- /dev/null +++ b/examples/external/opencv/requirements.txt @@ -0,0 +1 @@ +opencv-python diff --git a/examples/external/opencv/webcam_pattern_detection.py b/examples/external/opencv/webcam_pattern_detection.py new file mode 100644 index 000000000..553261615 --- /dev/null +++ b/examples/external/opencv/webcam_pattern_detection.py @@ -0,0 +1,207 @@ +############################################################################# +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +import os +import sys +import time + +import cv2 +from PySide2.QtCore import Qt, QThread, Signal, Slot +from PySide2.QtGui import QImage, QKeySequence, QPixmap +from PySide2.QtWidgets import (QAction, QApplication, QComboBox, QGroupBox, + QHBoxLayout, QLabel, QMainWindow, QPushButton, + QSizePolicy, QVBoxLayout, QWidget) + + +"""This example uses the video from a webcam to apply pattern +detection from the OpenCV module. e.g.: face, eyes, body, etc.""" + + +class Thread(QThread): + updateFrame = Signal(QImage) + + def __init__(self, parent=None): + QThread.__init__(self, parent) + self.trained_file = None + self.status = True + self.cap = True + + def set_file(self, fname): + # The data comes with the 'opencv-python' module + self.trained_file = os.path.join(cv2.data.haarcascades, fname) + + def run(self): + self.cap = cv2.VideoCapture(0) + while self.status: + cascade = cv2.CascadeClassifier(self.trained_file) + ret, frame = self.cap.read() + if not ret: + continue + + # Reading frame in gray scale to process the pattern + gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + + detections = cascade.detectMultiScale(gray_frame, scaleFactor=1.1, + minNeighbors=5, minSize=(30, 30)) + + # Drawing green rectangle around the pattern + for (x, y, w, h) in detections: + pos_ori = (x, y) + pos_end = (x + w, y + h) + color = (0, 255, 0) + cv2.rectangle(frame, pos_ori, pos_end, color, 2) + + # Reading the image in RGB to display it + color_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + + # Creating and scaling QImage + h, w, ch = color_frame.shape + img = QImage(color_frame.data, w, h, ch * w, QImage.Format_RGB888) + scaled_img = img.scaled(640, 480, Qt.KeepAspectRatio) + + # Emit signal + self.updateFrame.emit(scaled_img) + sys.exit(-1) + + +class Window(QMainWindow): + def __init__(self): + QMainWindow.__init__(self) + # Title and dimensions + self.setWindowTitle("Patterns detection") + self.setGeometry(0, 0, 800, 500) + + # Main menu bar + self.menu = self.menuBar() + self.menu_file = self.menu.addMenu("File") + exit = QAction("Exit", self, triggered=qApp.quit) + self.menu_file.addAction(exit) + + self.menu_about = self.menu.addMenu("&About") + about = QAction("About Qt", self, shortcut=QKeySequence(QKeySequence.HelpContents), + triggered=qApp.aboutQt) + self.menu_about.addAction(about) + + # Create a label for the display camera + self.label = QLabel(self) + self.label.setFixedSize(640, 480) + + # Thread in charge of updating the image + self.th = Thread(self) + self.th.finished.connect(self.close) + self.th.updateFrame.connect(self.setImage) + + # Model group + self.group_model = QGroupBox("Trained model") + self.group_model.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) + model_layout = QHBoxLayout() + + self.combobox = QComboBox() + for xml_file in os.listdir(cv2.data.haarcascades): + if xml_file.endswith(".xml"): + self.combobox.addItem(xml_file) + + model_layout.addWidget(QLabel("File:"), 10) + model_layout.addWidget(self.combobox, 90) + self.group_model.setLayout(model_layout) + + # Buttons layout + buttons_layout = QHBoxLayout() + self.button1 = QPushButton("Start") + self.button2 = QPushButton("Stop/Close") + self.button1.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) + self.button2.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) + buttons_layout.addWidget(self.button2) + buttons_layout.addWidget(self.button1) + + right_layout = QHBoxLayout() + right_layout.addWidget(self.group_model, 1) + right_layout.addLayout(buttons_layout, 1) + + # Main layout + layout = QVBoxLayout() + layout.addWidget(self.label) + layout.addLayout(right_layout) + + # Central widget + widget = QWidget(self) + widget.setLayout(layout) + self.setCentralWidget(widget) + + # Connections + self.button1.clicked.connect(self.start) + self.button2.clicked.connect(self.kill_thread) + self.button2.setEnabled(False) + self.combobox.currentTextChanged.connect(self.set_model) + + @Slot() + def set_model(self, text): + self.th.set_file(text) + + @Slot() + def kill_thread(self): + print("Finishing...") + self.button2.setEnabled(False) + self.button1.setEnabled(True) + self.th.cap.release() + cv2.destroyAllWindows() + self.status = False + self.th.terminate() + # Give time for the thread to finish + time.sleep(1) + + @Slot() + def start(self): + print("Starting...") + self.button2.setEnabled(True) + self.button1.setEnabled(False) + self.th.set_file(self.combobox.currentText()) + self.th.start() + + @Slot(QImage) + def setImage(self, image): + self.label.setPixmap(QPixmap.fromImage(image)) + + +if __name__ == "__main__": + app = QApplication() + w = Window() + w.show() + sys.exit(app.exec_()) diff --git a/examples/external/scikit/requirements.txt b/examples/external/scikit/requirements.txt new file mode 100644 index 000000000..391ca2f08 --- /dev/null +++ b/examples/external/scikit/requirements.txt @@ -0,0 +1 @@ +scikit-image diff --git a/examples/external/scikit/staining_colors_separation.py b/examples/external/scikit/staining_colors_separation.py new file mode 100644 index 000000000..051b2bc25 --- /dev/null +++ b/examples/external/scikit/staining_colors_separation.py @@ -0,0 +1,184 @@ +############################################################################# +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +import sys + +import numpy as np +from matplotlib.backends.backend_qt5agg import FigureCanvas +from matplotlib.colors import LinearSegmentedColormap +from matplotlib.figure import Figure +from PySide2.QtCore import Qt, Slot +from PySide2.QtGui import QKeySequence +from PySide2.QtWidgets import (QAction, QApplication, QHBoxLayout, QLabel, + QMainWindow, QPushButton, QSizePolicy, + QVBoxLayout, QWidget) +from skimage import data +from skimage.color import rgb2hed +from skimage.exposure import rescale_intensity + + +class ApplicationWindow(QMainWindow): + """ + Example based on the example by 'scikit-image' gallery: + "Immunohistochemical staining colors separation" + https://scikit-image.org/docs/stable/auto_examples/color_exposure/plot_ihc_color_separation.html + """ + + def __init__(self, parent=None): + QMainWindow.__init__(self, parent) + self._main = QWidget() + self.setCentralWidget(self._main) + + # Main menu bar + self.menu = self.menuBar() + self.menu_file = self.menu.addMenu("File") + exit = QAction("Exit", self, triggered=qApp.quit) + self.menu_file.addAction(exit) + + self.menu_about = self.menu.addMenu("&About") + about = QAction("About Qt", self, shortcut=QKeySequence(QKeySequence.HelpContents), + triggered=qApp.aboutQt) + self.menu_about.addAction(about) + + # Create an artificial color close to the original one + self.ihc_rgb = data.immunohistochemistry() + self.ihc_hed = rgb2hed(self.ihc_rgb) + + main_layout = QVBoxLayout(self._main) + plot_layout = QHBoxLayout() + button_layout = QHBoxLayout() + label_layout = QHBoxLayout() + + self.canvas1 = FigureCanvas(Figure(figsize=(5, 5))) + self.canvas2 = FigureCanvas(Figure(figsize=(5, 5))) + + self._ax1 = self.canvas1.figure.subplots() + self._ax2 = self.canvas2.figure.subplots() + + self._ax1.imshow(self.ihc_rgb) + + plot_layout.addWidget(self.canvas1) + plot_layout.addWidget(self.canvas2) + + self.button1 = QPushButton("Hematoxylin") + self.button2 = QPushButton("Eosin") + self.button3 = QPushButton("DAB") + self.button4 = QPushButton("Fluorescence") + + self.button1.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) + self.button2.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) + self.button3.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) + self.button4.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) + + self.button1.clicked.connect(self.plot_hematoxylin) + self.button2.clicked.connect(self.plot_eosin) + self.button3.clicked.connect(self.plot_dab) + self.button4.clicked.connect(self.plot_final) + + self.label1 = QLabel("Original", alignment=Qt.AlignCenter) + self.label2 = QLabel("", alignment=Qt.AlignCenter) + + font = self.label1.font() + font.setPointSize(16) + self.label1.setFont(font) + self.label2.setFont(font) + + label_layout.addWidget(self.label1) + label_layout.addWidget(self.label2) + + button_layout.addWidget(self.button1) + button_layout.addWidget(self.button2) + button_layout.addWidget(self.button3) + button_layout.addWidget(self.button4) + + main_layout.addLayout(label_layout, 2) + main_layout.addLayout(plot_layout, 88) + main_layout.addLayout(button_layout, 10) + + # Default image + self.plot_hematoxylin() + + def set_buttons_state(self, states): + self.button1.setEnabled(states[0]) + self.button2.setEnabled(states[1]) + self.button3.setEnabled(states[2]) + self.button4.setEnabled(states[3]) + + @Slot() + def plot_hematoxylin(self): + cmap_hema = LinearSegmentedColormap.from_list("mycmap", ["white", "navy"]) + self._ax2.imshow(self.ihc_hed[:, :, 0], cmap=cmap_hema) + self.canvas2.draw() + self.label2.setText("Hematoxylin") + self.set_buttons_state((False, True, True, True)) + + @Slot() + def plot_eosin(self): + cmap_eosin = LinearSegmentedColormap.from_list("mycmap", ["darkviolet", "white"]) + self._ax2.imshow(self.ihc_hed[:, :, 1], cmap=cmap_eosin) + self.canvas2.draw() + self.label2.setText("Eosin") + self.set_buttons_state((True, False, True, True)) + + @Slot() + def plot_dab(self): + cmap_dab = LinearSegmentedColormap.from_list("mycmap", ["white", "saddlebrown"]) + self._ax2.imshow(self.ihc_hed[:, :, 2], cmap=cmap_dab) + self.canvas2.draw() + self.label2.setText("DAB") + self.set_buttons_state((True, True, False, True)) + + @Slot() + def plot_final(self): + h = rescale_intensity(self.ihc_hed[:, :, 0], out_range=(0, 1)) + d = rescale_intensity(self.ihc_hed[:, :, 2], out_range=(0, 1)) + zdh = np.dstack((np.zeros_like(h), d, h)) + self._ax2.imshow(zdh) + self.canvas2.draw() + self.label2.setText("Stain separated image") + self.set_buttons_state((True, True, True, False)) + + +if __name__ == "__main__": + + app = QApplication(sys.argv) + w = ApplicationWindow() + w.show() + app.exec_() diff --git a/examples/installer_test/hello.py b/examples/installer_test/hello.py index 77b050206..3aa7a1564 100644 --- a/examples/installer_test/hello.py +++ b/examples/installer_test/hello.py @@ -3,38 +3,39 @@ ############################################################################# ## -## Copyright (C) 2019 The Qt Company Ltd. +## Copyright (C) 2020 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## -## This file is part of Qt for Python. +## This file is part of the Qt for Python examples of the Qt Toolkit. ## -## $QT_BEGIN_LICENSE:LGPL$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: ## -## GNU Lesser General Public License Usage -## Alternatively, this file may be used under the terms of the GNU Lesser -## General Public License version 3 as published by the Free Software -## Foundation and appearing in the file LICENSE.LGPL3 included in the -## packaging of this file. Please review the following information to -## ensure the GNU Lesser General Public License version 3 requirements -## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. ## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 2.0 or (at your option) the GNU General -## Public license version 3 or any later version approved by the KDE Free -## Qt Foundation. The licenses are as published by the Free Software -## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-2.0.html and -## https://www.gnu.org/licenses/gpl-3.0.html. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ## ## $QT_END_LICENSE$ ## diff --git a/examples/installer_test/hello_app.spec b/examples/installer_test/hello_app.spec index 84d6d0029..05ff1b8cb 100644 --- a/examples/installer_test/hello_app.spec +++ b/examples/installer_test/hello_app.spec @@ -3,38 +3,39 @@ ############################################################################# ## -## Copyright (C) 2019 The Qt Company Ltd. +## Copyright (C) 2020 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## -## This file is part of Qt for Python. +## This file is part of the Qt for Python examples of the Qt Toolkit. ## -## $QT_BEGIN_LICENSE:LGPL$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: ## -## GNU Lesser General Public License Usage -## Alternatively, this file may be used under the terms of the GNU Lesser -## General Public License version 3 as published by the Free Software -## Foundation and appearing in the file LICENSE.LGPL3 included in the -## packaging of this file. Please review the following information to -## ensure the GNU Lesser General Public License version 3 requirements -## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. ## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 2.0 or (at your option) the GNU General -## Public license version 3 or any later version approved by the KDE Free -## Qt Foundation. The licenses are as published by the Free Software -## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-2.0.html and -## https://www.gnu.org/licenses/gpl-3.0.html. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ## ## $QT_END_LICENSE$ ## diff --git a/examples/macextras/macextras.pyproject b/examples/macextras/macextras.pyproject new file mode 100644 index 000000000..d559b7ca4 --- /dev/null +++ b/examples/macextras/macextras.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["macpasteboardmime.py"] +} diff --git a/examples/macextras/macpasteboardmime.py b/examples/macextras/macpasteboardmime.py index 8009ccd90..c8513395b 100644 --- a/examples/macextras/macpasteboardmime.py +++ b/examples/macextras/macpasteboardmime.py @@ -40,8 +40,7 @@ ############################################################################ import sys -import math -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets try: from PySide2 import QtMacExtras diff --git a/examples/multimedia/camera.py b/examples/multimedia/camera.py index 5d069d5cf..d58b526d9 100644 --- a/examples/multimedia/camera.py +++ b/examples/multimedia/camera.py @@ -43,9 +43,9 @@ import os, sys from PySide2.QtCore import QDate, QDir, QStandardPaths, Qt, QUrl -from PySide2.QtGui import QClipboard, QGuiApplication, QDesktopServices, QIcon +from PySide2.QtGui import QGuiApplication, QDesktopServices, QIcon from PySide2.QtGui import QImage, QPixmap -from PySide2.QtWidgets import (QAction, qApp, QApplication, QHBoxLayout, QLabel, +from PySide2.QtWidgets import (QAction, QApplication, QHBoxLayout, QLabel, QMainWindow, QPushButton, QTabWidget, QToolBar, QVBoxLayout, QWidget) from PySide2.QtMultimedia import QCamera, QCameraImageCapture, QCameraInfo from PySide2.QtMultimediaWidgets import QCameraViewfinder diff --git a/examples/multimedia/multimedia.pyproject b/examples/multimedia/multimedia.pyproject new file mode 100644 index 000000000..a0b8b441c --- /dev/null +++ b/examples/multimedia/multimedia.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["player.py", "audiooutput.py", "camera.py"] +} diff --git a/examples/multimedia/player.py b/examples/multimedia/player.py index 509e914f9..cb70e50d6 100644 --- a/examples/multimedia/player.py +++ b/examples/multimedia/player.py @@ -42,10 +42,10 @@ """PySide2 Multimedia player example""" import sys -from PySide2.QtCore import SLOT, QStandardPaths, Qt +from PySide2.QtCore import QStandardPaths, Qt from PySide2.QtGui import QIcon, QKeySequence -from PySide2.QtWidgets import (QAction, qApp, QApplication, QDialog, QFileDialog, - QMainWindow, QMenu, QMenuBar, QSlider, QStyle, QToolBar) +from PySide2.QtWidgets import (QAction, QApplication, QDialog, QFileDialog, + QMainWindow, QSlider, QStyle, QToolBar) from PySide2.QtMultimedia import QMediaPlayer, QMediaPlaylist from PySide2.QtMultimediaWidgets import QVideoWidget diff --git a/examples/network/fortuneserver.py b/examples/network/fortuneserver.py index 5a447b1ad..790e9df68 100644 --- a/examples/network/fortuneserver.py +++ b/examples/network/fortuneserver.py @@ -44,7 +44,7 @@ import random -from PySide2 import QtCore, QtGui, QtWidgets, QtNetwork +from PySide2 import QtCore, QtWidgets, QtNetwork class Server(QtWidgets.QDialog): diff --git a/examples/network/network.pyproject b/examples/network/network.pyproject new file mode 100644 index 000000000..44b9ec433 --- /dev/null +++ b/examples/network/network.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["blockingfortuneclient.py", "fortuneserver.py", + "threadedfortuneserver.py", "fortuneclient.py"] +} diff --git a/examples/opengl/2dpainting.py b/examples/opengl/2dpainting.py index 4e4dc8aa4..5b3ba6183 100644 --- a/examples/opengl/2dpainting.py +++ b/examples/opengl/2dpainting.py @@ -43,7 +43,6 @@ """PySide2 port of the opengl/legacy/2dpainting example from Qt v5.x""" import sys -import math from PySide2.QtCore import * from PySide2.QtGui import * from PySide2.QtWidgets import * diff --git a/examples/opengl/grabber.py b/examples/opengl/grabber.py index c376ab7ae..d4b625718 100644 --- a/examples/opengl/grabber.py +++ b/examples/opengl/grabber.py @@ -370,7 +370,7 @@ class MainWindow(QtWidgets.QMainWindow): self.aboutAct = QtWidgets.QAction("&About", self, triggered=self.about) self.aboutQtAct = QtWidgets.QAction("About &Qt", self, - triggered=QtWidgets.qApp.aboutQt) + triggered=qApp.aboutQt) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") diff --git a/examples/opengl/opengl.pyproject b/examples/opengl/opengl.pyproject new file mode 100644 index 000000000..12f435daf --- /dev/null +++ b/examples/opengl/opengl.pyproject @@ -0,0 +1,5 @@ +{ + "files": ["grabber.py", "samplebuffers.py", "hellogl.py", + "hellogl2.py", "contextinfo.py", "2dpainting.py", + "overpainting.py"] +} diff --git a/examples/opengl/textures/textures.py b/examples/opengl/textures/textures.py index c8b421749..9730cf078 100644 --- a/examples/opengl/textures/textures.py +++ b/examples/opengl/textures/textures.py @@ -204,7 +204,7 @@ class Window(QtWidgets.QWidget): mainLayout.addWidget(self.glWidgets[i][j], i, j) self.glWidgets[i][j].clicked.connect(self.setCurrentGlWidget) - QtWidgets.qApp.lastWindowClosed.connect(self.glWidgets[i][j].freeGLResources) + qApp.lastWindowClosed.connect(self.glWidgets[i][j].freeGLResources) self.setLayout(mainLayout) diff --git a/examples/opengl/textures/textures.pyproject b/examples/opengl/textures/textures.pyproject new file mode 100644 index 000000000..05416190a --- /dev/null +++ b/examples/opengl/textures/textures.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["textures.qrc", "textures_rc.py", "textures.py"] +} diff --git a/examples/remoteobjects/modelview/modelview.pyproject b/examples/remoteobjects/modelview/modelview.pyproject new file mode 100644 index 000000000..0b3a1b5e3 --- /dev/null +++ b/examples/remoteobjects/modelview/modelview.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["modelviewserver.py", "modelviewclient.py"] +} diff --git a/examples/remoteobjects/modelview/modelviewclient.py b/examples/remoteobjects/modelview/modelviewclient.py index 319135886..378a0516e 100644 --- a/examples/remoteobjects/modelview/modelviewclient.py +++ b/examples/remoteobjects/modelview/modelviewclient.py @@ -45,8 +45,7 @@ import sys from PySide2.QtCore import QUrl from PySide2.QtWidgets import (QApplication, QTreeView) -from PySide2.QtRemoteObjects import (QAbstractItemModelReplica, - QRemoteObjectNode) +from PySide2.QtRemoteObjects import QRemoteObjectNode if __name__ == '__main__': app = QApplication(sys.argv) @@ -54,9 +53,9 @@ if __name__ == '__main__': node.setHeartbeatInterval(1000) view = QTreeView() view.setWindowTitle("RemoteView") - view.resize(640,480); + view.resize(640,480) model = node.acquireModel("RemoteModel") - view.setModel(model); - view.show(); + view.setModel(model) + view.show() sys.exit(app.exec_()) diff --git a/examples/remoteobjects/modelview/modelviewserver.py b/examples/remoteobjects/modelview/modelviewserver.py index 069cc1d2c..5c0bba518 100644 --- a/examples/remoteobjects/modelview/modelviewserver.py +++ b/examples/remoteobjects/modelview/modelviewserver.py @@ -46,8 +46,7 @@ import sys from PySide2.QtCore import (Qt, QByteArray, QModelIndex, QObject, QTimer, QUrl) from PySide2.QtGui import (QColor, QStandardItemModel, QStandardItem) from PySide2.QtWidgets import (QApplication, QTreeView) -from PySide2.QtRemoteObjects import (QRemoteObjectHost, QRemoteObjectNode, - QRemoteObjectRegistryHost) +from PySide2.QtRemoteObjects import QRemoteObjectHost, QRemoteObjectRegistryHost class TimerHandler(QObject): def __init__(self, model): @@ -60,7 +59,7 @@ class TimerHandler(QObject): QColor(Qt.blue), Qt.BackgroundRole) def insert_data(self): - self._model.insertRows(2, 9); + self._model.insertRows(2, 9) for i in range(2, 11): self._model.setData(self._model.index(i, 1), QColor(Qt.green), Qt.BackgroundRole) @@ -83,18 +82,18 @@ class TimerHandler(QObject): def add_child(num_children, nesting_level): result = [] if nesting_level == 0: - return result; + return result for i in range(num_children): child = QStandardItem("Child num {}, nesting Level {}".format(i + 1, nesting_level)) if i == 0: child.appendRow(add_child(num_children, nesting_level -1)) result.append(child) - return result; + return result if __name__ == '__main__': app = QApplication(sys.argv) - model_size = 100000; + model_size = 100000 list = [] source_model = QStandardItemModel() horizontal_header_list = ["First Column with spacing", diff --git a/examples/samplebinding/CMakeLists.txt b/examples/samplebinding/CMakeLists.txt index 3852ed36f..cb61358bf 100644 --- a/examples/samplebinding/CMakeLists.txt +++ b/examples/samplebinding/CMakeLists.txt @@ -180,6 +180,7 @@ endif() # ================================= Dubious deployment section ================================ +set(windows_shiboken_shared_libraries) if(WIN32) # ========================================================================================= @@ -202,22 +203,12 @@ if(WIN32) set_target_properties(${bindings_library} PROPERTIES LINK_FLAGS "${python_additional_link_flags}") - # Add custom target to hard-link shiboken shared libraries into the build folder, so that + # Compile a list of shiboken shared libraries to be installed, so that # the user doesn't have to set the PATH manually to point to the PySide2 package. foreach(library_path ${shiboken_shared_libraries}) string(REGEX REPLACE ".lib$" ".dll" library_path ${library_path}) - get_filename_component(base_name ${library_path} NAME) - file(TO_NATIVE_PATH ${library_path} source_path) - file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${base_name}" dest_path) - add_custom_command(OUTPUT "${base_name}" - COMMAND mklink /H "${dest_path}" "${source_path}" - DEPENDS ${library_path} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT "Creating hardlink to shiboken shared library ${base_name}") - - # Fake target that depends on the previous one, but has special ALL keyword, which means - # it will always be executed. - add_custom_target("fake_${base_name}" ALL DEPENDS ${base_name}) + file(TO_CMAKE_PATH ${library_path} library_path) + list(APPEND windows_shiboken_shared_libraries "${library_path}") endforeach() # ========================================================================================= # !!! End of dubious section. @@ -233,7 +224,8 @@ endif() install(TARGETS ${bindings_library} ${sample_library} LIBRARY DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} - ) + ) +install(FILES ${windows_shiboken_shared_libraries} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}) # ============================================================================================= # !!! End of dubious section. # ============================================================================================= diff --git a/examples/script/script.pyproject b/examples/script/script.pyproject new file mode 100644 index 000000000..5beba8c3a --- /dev/null +++ b/examples/script/script.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["README.md", "helloscript.py"] +} diff --git a/examples/scriptableapplication/mainwindow.cpp b/examples/scriptableapplication/mainwindow.cpp index 92415a78d..15504cb6e 100644 --- a/examples/scriptableapplication/mainwindow.cpp +++ b/examples/scriptableapplication/mainwindow.cpp @@ -66,12 +66,13 @@ #include <QtCore/QDebug> #include <QtCore/QTextStream> -static const char defaultScript[] = - "print(\"Hello, world\")\n" - "mainWindow.testFunction1()\n"; +static const char defaultScript[] = R"( +print("Hello, world") +mainWindow.testFunction1() +)"; MainWindow::MainWindow() - : m_scriptEdit(new QPlainTextEdit(QLatin1String(defaultScript), this)) + : m_scriptEdit(new QPlainTextEdit(QString::fromLatin1(defaultScript).trimmed(), this)) { setWindowTitle(tr("Scriptable Application")); diff --git a/examples/scriptableapplication/pythonutils.cpp b/examples/scriptableapplication/pythonutils.cpp index f546a5a6c..c5e18f256 100644 --- a/examples/scriptableapplication/pythonutils.cpp +++ b/examples/scriptableapplication/pythonutils.cpp @@ -53,6 +53,7 @@ #include <QtCore/QByteArray> #include <QtCore/QCoreApplication> #include <QtCore/QDebug> +#include <QtCore/QOperatingSystemVersion> #include <QtCore/QStringList> #include <QtCore/QTemporaryFile> #include <QtCore/QDir> @@ -87,15 +88,30 @@ static void cleanup() } } +static const char virtualEnvVar[] = "VIRTUAL_ENV"; + +// If there is an active python virtual environment, use that environment's +// packages location. +static void initVirtualEnvironment() +{ + QByteArray virtualEnvPath = qgetenv(virtualEnvVar); + // As of Python 3.8, Python is no longer able to run stand-alone in a + // virtualenv due to missing libraries. Add the path to the modules instead. + if (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Windows + && (PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 8))) { + qputenv("PYTHONPATH", virtualEnvPath + "\\Lib\\site-packages"); + } else { + qputenv("PYTHONHOME", virtualEnvPath); + } +} + State init() { if (state > PythonUninitialized) return state; - // If there is an active python virtual environment, use that environment's packages location. - QByteArray virtualEnvPath = qgetenv("VIRTUAL_ENV"); - if (!virtualEnvPath.isEmpty()) - qputenv("PYTHONHOME", virtualEnvPath); + if (qEnvironmentVariableIsSet(virtualEnvVar)) + initVirtualEnvironment(); Py_Initialize(); qAddPostRoutine(cleanup); diff --git a/examples/sql/books/bookdelegate.py b/examples/sql/books/bookdelegate.py index a0bd92334..f7e219ad6 100644 --- a/examples/sql/books/bookdelegate.py +++ b/examples/sql/books/bookdelegate.py @@ -40,9 +40,8 @@ import copy from PySide2.QtSql import QSqlRelationalDelegate -from PySide2.QtWidgets import (QItemDelegate, QSpinBox, QStyledItemDelegate, - QStyle, QStyleOptionViewItem) -from PySide2.QtGui import QMouseEvent, QPixmap, QPalette +from PySide2.QtWidgets import QSpinBox, QStyle +from PySide2.QtGui import QPixmap, QPalette from PySide2.QtCore import QEvent, QSize, Qt diff --git a/examples/sql/books/bookwindow.py b/examples/sql/books/bookwindow.py index c6d43b1f3..31d2a055f 100644 --- a/examples/sql/books/bookwindow.py +++ b/examples/sql/books/bookwindow.py @@ -40,12 +40,11 @@ from __future__ import print_function, absolute_import -from PySide2.QtWidgets import (QAction, QAbstractItemView, qApp, QDataWidgetMapper, +from PySide2.QtWidgets import (QAbstractItemView, QDataWidgetMapper, QHeaderView, QMainWindow, QMessageBox) from PySide2.QtGui import QKeySequence -from PySide2.QtSql import (QSqlRelation, QSqlRelationalTableModel, QSqlTableModel, - QSqlError) -from PySide2.QtCore import QAbstractItemModel, QObject, QSize, Qt, Slot +from PySide2.QtSql import QSqlRelation, QSqlRelationalTableModel, QSqlTableModel +from PySide2.QtCore import Qt, Slot import createdb from ui_bookwindow import Ui_BookWindow from bookdelegate import BookDelegate @@ -131,6 +130,7 @@ class BookWindow(QMainWindow, Ui_BookWindow): aboutQt_action = help_menu.addAction("&About Qt") aboutQt_action.triggered.connect(qApp.aboutQt) + @Slot() def about(self): QMessageBox.about(self, self.tr("About Books"), self.tr("<p>The <b>Books</b> example shows how to use Qt SQL classes " diff --git a/examples/sql/books/createdb.py b/examples/sql/books/createdb.py index d03060ad5..f8739b4d0 100644 --- a/examples/sql/books/createdb.py +++ b/examples/sql/books/createdb.py @@ -38,9 +38,8 @@ ## ############################################################################# -from PySide2.QtSql import QSqlDatabase, QSqlError, QSqlQuery -from datetime import datetime - +from PySide2.QtSql import QSqlDatabase, QSqlQuery +from datetime import date def add_book(q, title, year, authorId, genreId, rating): q.addBindValue(title) @@ -59,7 +58,7 @@ def add_genre(q, name): def add_author(q, name, birthdate): q.addBindValue(name) - q.addBindValue(birthdate) + q.addBindValue(str(birthdate)) q.exec_() return q.lastInsertId() @@ -68,7 +67,7 @@ BOOKS_SQL = """ genre integer, year integer, rating integer) """ AUTHORS_SQL = """ - create table authors(id integer primary key, name varchar, birthdate date) + create table authors(id integer primary key, name varchar, birthdate text) """ GENRES_SQL = """ create table genres(id integer primary key, name varchar) @@ -106,9 +105,9 @@ def init_db(): check(q.exec_, GENRES_SQL) check(q.prepare, INSERT_AUTHOR_SQL) - asimovId = add_author(q, "Isaac Asimov", datetime(1920, 2, 1)) - greeneId = add_author(q, "Graham Greene", datetime(1904, 10, 2)) - pratchettId = add_author(q, "Terry Pratchett", datetime(1948, 4, 28)) + asimovId = add_author(q, "Isaac Asimov", date(1920, 2, 1)) + greeneId = add_author(q, "Graham Greene", date(1904, 10, 2)) + pratchettId = add_author(q, "Terry Pratchett", date(1948, 4, 28)) check(q.prepare,INSERT_GENRE_SQL) sfiction = add_genre(q, "Science Fiction") diff --git a/examples/sql/books/ui_bookwindow.py b/examples/sql/books/ui_bookwindow.py index 5eb412d92..dc532744b 100644 --- a/examples/sql/books/ui_bookwindow.py +++ b/examples/sql/books/ui_bookwindow.py @@ -22,63 +22,63 @@ class Ui_BookWindow(object): BookWindow.resize(601, 420) self.centralWidget = QWidget(BookWindow) self.centralWidget.setObjectName(u"centralWidget") - self.vboxLayout = QVBoxLayout(self.centralWidget); + self.vboxLayout = QVBoxLayout(self.centralWidget) self.vboxLayout.setSpacing(6) self.vboxLayout.setObjectName(u"vboxLayout") - self.vboxLayout.setContentsMargins(9, 9, 9, 9); + self.vboxLayout.setContentsMargins(9, 9, 9, 9) self.groupBox = QGroupBox(self.centralWidget) self.groupBox.setObjectName(u"groupBox") - self.vboxLayout1 = QVBoxLayout(self.groupBox); + self.vboxLayout1 = QVBoxLayout(self.groupBox) self.vboxLayout1.setSpacing(6) self.vboxLayout1.setObjectName(u"vboxLayout1") - self.vboxLayout1.setContentsMargins(9, 9, 9, 9); + self.vboxLayout1.setContentsMargins(9, 9, 9, 9) self.bookTable = QTableView(self.groupBox) self.bookTable.setObjectName(u"bookTable") self.bookTable.setSelectionBehavior(QAbstractItemView.SelectRows) - self.vboxLayout1.addWidget(self.bookTable); + self.vboxLayout1.addWidget(self.bookTable) self.groupBox_2 = QGroupBox(self.groupBox) self.groupBox_2.setObjectName(u"groupBox_2") - self.formLayout = QFormLayout(self.groupBox_2); + self.formLayout = QFormLayout(self.groupBox_2) self.formLayout.setObjectName(u"formLayout") self.label_5 = QLabel(self.groupBox_2) self.label_5.setObjectName(u"label_5") - self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_5); + self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_5) self.titleEdit = QLineEdit(self.groupBox_2) self.titleEdit.setObjectName(u"titleEdit") self.titleEdit.setEnabled(True) - self.formLayout.setWidget(0, QFormLayout.FieldRole, self.titleEdit); + self.formLayout.setWidget(0, QFormLayout.FieldRole, self.titleEdit) self.label_2 = QLabel(self.groupBox_2) self.label_2.setObjectName(u"label_2") - self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_2); + self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_2) self.authorEdit = QComboBox(self.groupBox_2) self.authorEdit.setObjectName(u"authorEdit") self.authorEdit.setEnabled(True) - self.formLayout.setWidget(1, QFormLayout.FieldRole, self.authorEdit); + self.formLayout.setWidget(1, QFormLayout.FieldRole, self.authorEdit) self.label_3 = QLabel(self.groupBox_2) self.label_3.setObjectName(u"label_3") - self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3); + self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3) self.genreEdit = QComboBox(self.groupBox_2) self.genreEdit.setObjectName(u"genreEdit") self.genreEdit.setEnabled(True) - self.formLayout.setWidget(2, QFormLayout.FieldRole, self.genreEdit); + self.formLayout.setWidget(2, QFormLayout.FieldRole, self.genreEdit) self.label_4 = QLabel(self.groupBox_2) self.label_4.setObjectName(u"label_4") - self.formLayout.setWidget(3, QFormLayout.LabelRole, self.label_4); + self.formLayout.setWidget(3, QFormLayout.LabelRole, self.label_4) self.yearEdit = QSpinBox(self.groupBox_2) self.yearEdit.setObjectName(u"yearEdit") @@ -86,24 +86,24 @@ class Ui_BookWindow(object): self.yearEdit.setMinimum(-1000) self.yearEdit.setMaximum(2100) - self.formLayout.setWidget(3, QFormLayout.FieldRole, self.yearEdit); + self.formLayout.setWidget(3, QFormLayout.FieldRole, self.yearEdit) self.label = QLabel(self.groupBox_2) self.label.setObjectName(u"label") - self.formLayout.setWidget(4, QFormLayout.LabelRole, self.label); + self.formLayout.setWidget(4, QFormLayout.LabelRole, self.label) self.ratingEdit = QSpinBox(self.groupBox_2) self.ratingEdit.setObjectName(u"ratingEdit") self.ratingEdit.setMaximum(5) - self.formLayout.setWidget(4, QFormLayout.FieldRole, self.ratingEdit); + self.formLayout.setWidget(4, QFormLayout.FieldRole, self.ratingEdit) - self.vboxLayout1.addWidget(self.groupBox_2); + self.vboxLayout1.addWidget(self.groupBox_2) - self.vboxLayout.addWidget(self.groupBox); + self.vboxLayout.addWidget(self.groupBox) BookWindow.setCentralWidget(self.centralWidget) QWidget.setTabOrder(self.bookTable, self.titleEdit) diff --git a/examples/texttospeech/texttospeech.py b/examples/texttospeech/texttospeech.py index f085dbd19..f9c32ed1d 100644 --- a/examples/texttospeech/texttospeech.py +++ b/examples/texttospeech/texttospeech.py @@ -43,10 +43,10 @@ import sys from PySide2.QtCore import Qt -from PySide2.QtWidgets import (qApp, QApplication, QComboBox, QFormLayout, +from PySide2.QtWidgets import (QApplication, QComboBox, QFormLayout, QHBoxLayout, QLineEdit, QMainWindow, QPushButton, QSlider, QWidget) -from PySide2.QtTextToSpeech import QTextToSpeech, QVoice +from PySide2.QtTextToSpeech import QTextToSpeech class MainWindow(QMainWindow): def __init__(self): diff --git a/examples/texttospeech/texttospeech.pyproject b/examples/texttospeech/texttospeech.pyproject new file mode 100644 index 000000000..69fc13f90 --- /dev/null +++ b/examples/texttospeech/texttospeech.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["texttospeech.py"] +} diff --git a/examples/tutorial/t10.py b/examples/tutorial/t10.py index 00ab1f889..12847a002 100644 --- a/examples/tutorial/t10.py +++ b/examples/tutorial/t10.py @@ -148,7 +148,7 @@ class MyWidget(QtWidgets.QWidget): quit.setFont(QtGui.QFont("Times", 18, QtGui.QFont.Bold)) self.connect(quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) angle = LCDRange() angle.setRange(5, 70) diff --git a/examples/tutorial/t11.py b/examples/tutorial/t11.py index 801a2c0a0..cc391201b 100644 --- a/examples/tutorial/t11.py +++ b/examples/tutorial/t11.py @@ -210,7 +210,7 @@ class MyWidget(QtWidgets.QWidget): quit.setFont(QtGui.QFont("Times", 18, QtGui.QFont.Bold)) self.connect(quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) angle = LCDRange() angle.setRange(5, 70) diff --git a/examples/tutorial/t12.py b/examples/tutorial/t12.py index ecafe23da..40945290a 100644 --- a/examples/tutorial/t12.py +++ b/examples/tutorial/t12.py @@ -259,7 +259,7 @@ class MyWidget(QtWidgets.QWidget): quit.setFont(QtGui.QFont("Times", 18, QtGui.QFont.Bold)) self.connect(quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) angle = LCDRange("ANGLE") angle.setRange(5, 70) diff --git a/examples/tutorial/t13.py b/examples/tutorial/t13.py index 8cf5af33c..5198bb459 100644 --- a/examples/tutorial/t13.py +++ b/examples/tutorial/t13.py @@ -293,7 +293,7 @@ class GameBoard(QtWidgets.QWidget): quit.setFont(QtGui.QFont("Times", 18, QtGui.QFont.Bold)) self.connect(quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) angle = LCDRange("ANGLE") angle.setRange(5, 70) diff --git a/examples/tutorial/t14.py b/examples/tutorial/t14.py index 4bb971f1d..0fcfa74c4 100644 --- a/examples/tutorial/t14.py +++ b/examples/tutorial/t14.py @@ -334,7 +334,7 @@ class GameBoard(QtWidgets.QWidget): quit.setFont(QtGui.QFont("Times", 18, QtGui.QFont.Bold)) self.connect(quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) angle = LCDRange("ANGLE") angle.setRange(5, 70) diff --git a/examples/tutorial/t4.py b/examples/tutorial/t4.py index 353e59e4b..c88943c98 100644 --- a/examples/tutorial/t4.py +++ b/examples/tutorial/t4.py @@ -57,7 +57,7 @@ class MyWidget(QtWidgets.QWidget): self.quit.setFont(QtGui.QFont("Times", 18, QtGui.QFont.Bold)) self.connect(self.quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) app = QtWidgets.QApplication(sys.argv) diff --git a/examples/tutorial/t5.py b/examples/tutorial/t5.py index eda1d98aa..4077c0eb2 100644 --- a/examples/tutorial/t5.py +++ b/examples/tutorial/t5.py @@ -60,7 +60,7 @@ class MyWidget(QtWidgets.QWidget): slider.setValue(0) self.connect(quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) self.connect(slider, QtCore.SIGNAL("valueChanged(int)"), lcd, QtCore.SLOT("display(int)")) diff --git a/examples/tutorial/t6.py b/examples/tutorial/t6.py index 6353af1c2..21c4ff311 100644 --- a/examples/tutorial/t6.py +++ b/examples/tutorial/t6.py @@ -70,7 +70,7 @@ class MyWidget(QtWidgets.QWidget): quit = QtWidgets.QPushButton("Quit") quit.setFont(QtGui.QFont("Times", 18, QtGui.QFont.Bold)) self.connect(quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) grid = QtWidgets.QGridLayout() layout = QtWidgets.QVBoxLayout() diff --git a/examples/tutorial/t7.py b/examples/tutorial/t7.py index 97ed27f10..0e01a75cd 100644 --- a/examples/tutorial/t7.py +++ b/examples/tutorial/t7.py @@ -83,7 +83,7 @@ class MyWidget(QtWidgets.QWidget): quit.setFont(QtGui.QFont("Times", 18, QtGui.QFont.Bold)) self.connect(quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) grid = QtWidgets.QGridLayout() previousRange = None diff --git a/examples/tutorial/t8.py b/examples/tutorial/t8.py index 944c9f75b..e67268989 100644 --- a/examples/tutorial/t8.py +++ b/examples/tutorial/t8.py @@ -122,7 +122,7 @@ class MyWidget(QtWidgets.QWidget): quit.setFont(QtGui.QFont("Times", 18, QtGui.QFont.Bold)) self.connect(quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) angle = LCDRange() angle.setRange(5, 70) diff --git a/examples/tutorial/t9.py b/examples/tutorial/t9.py index 9a6462dda..ab37f8eb7 100644 --- a/examples/tutorial/t9.py +++ b/examples/tutorial/t9.py @@ -129,7 +129,7 @@ class MyWidget(QtWidgets.QWidget): quit.setFont(QtGui.QFont("Times", 18, QtGui.QFont.Bold)) self.connect(quit, QtCore.SIGNAL("clicked()"), - QtWidgets.qApp, QtCore.SLOT("quit()")) + qApp, QtCore.SLOT("quit()")) angle = LCDRange() angle.setRange(5, 70) diff --git a/examples/tutorial/tutorial.pyproject b/examples/tutorial/tutorial.pyproject new file mode 100644 index 000000000..09478e108 --- /dev/null +++ b/examples/tutorial/tutorial.pyproject @@ -0,0 +1,5 @@ +{ + "files": ["t6.py", "t9.py", "t8.py", "t13.py", "t10.py", "t7.py", + "t3.py", "t4.py", "t1.py", "t12.py", "t2.py", "t5.py", + "t11.py", "t14.py"] +} diff --git a/examples/uiloader/uiloader.py b/examples/uiloader/uiloader.py new file mode 100644 index 000000000..1e6e72d78 --- /dev/null +++ b/examples/uiloader/uiloader.py @@ -0,0 +1,71 @@ +############################################################################# +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +"""QUiLoader example, showing how to dynamically load a Qt Designer form + from a UI file.""" + +from argparse import ArgumentParser, RawTextHelpFormatter +import sys + +from PySide2.QtCore import Qt, QFile, QIODevice +from PySide2.QtWidgets import QApplication, QWidget +from PySide2.QtUiTools import QUiLoader + + +if __name__ == '__main__': + arg_parser = ArgumentParser(description="QUiLoader example", + formatter_class=RawTextHelpFormatter) + arg_parser.add_argument('file', type=str, help='UI file') + args = arg_parser.parse_args() + ui_file_name = args.file + + app = QApplication(sys.argv) + ui_file = QFile(ui_file_name) + if not ui_file.open(QIODevice.ReadOnly): + print("Cannot open {}: {}".format(ui_file_name, ui_file.errorString())) + sys.exit(-1) + loader = QUiLoader() + widget = loader.load(ui_file, None) + ui_file.close() + if not widget: + print(loader.errorString()) + sys.exit(-1) + widget.show() + sys.exit(app.exec_()) diff --git a/examples/webchannel/standalone/core.py b/examples/webchannel/standalone/core.py new file mode 100644 index 000000000..9fb056496 --- /dev/null +++ b/examples/webchannel/standalone/core.py @@ -0,0 +1,62 @@ +############################################################################# +## +## Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + + +from PySide2.QtCore import QObject, Signal, Slot + + +class Core(QObject): + """An instance of this class gets published over the WebChannel and is then + accessible to HTML clients.""" + sendText = Signal(str) + + def __init__(self, dialog, parent=None): + super(Core, self).__init__(parent) + self._dialog = dialog + self._dialog.sendText.connect(self._emit_send_text) + + @Slot(str) + def _emit_send_text(self, text): + self.sendText.emit(text) + + @Slot(str) + def receiveText(self, text): + self._dialog.displayMessage("Received message: {}".format(text)) diff --git a/examples/webchannel/standalone/dialog.py b/examples/webchannel/standalone/dialog.py new file mode 100644 index 000000000..45951deb9 --- /dev/null +++ b/examples/webchannel/standalone/dialog.py @@ -0,0 +1,68 @@ +############################################################################# +## +## Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + + +from PySide2.QtCore import Signal, Slot +from PySide2.QtWidgets import QDialog +from ui_dialog import Ui_Dialog + + +class Dialog(QDialog): + sendText = Signal(str) + + def __init__(self, parent=None): + super(Dialog, self).__init__(parent) + self._ui = Ui_Dialog() + self._ui.setupUi(self) + self._ui.send.clicked.connect(self.clicked) + + @Slot(str) + def displayMessage(self, message): + self._ui.output.appendPlainText(message) + + @Slot() + def clicked(self): + text = self._ui.input.text() + if not text: + return + self.sendText.emit(text) + self.displayMessage("Sent message: {}".format(text)) + self._ui.input.clear() diff --git a/examples/webchannel/standalone/dialog.ui b/examples/webchannel/standalone/dialog.ui new file mode 100644 index 000000000..056a3f587 --- /dev/null +++ b/examples/webchannel/standalone/dialog.ui @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QDialog" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0"> + <widget class="QLineEdit" name="input"> + <property name="placeholderText"> + <string>Message Contents</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QPushButton" name="send"> + <property name="text"> + <string>Send</string> + </property> + </widget> + </item> + <item row="0" column="0" colspan="2"> + <widget class="QPlainTextEdit" name="output"> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="plainText"> + <string notr="true">Initializing WebChannel...</string> + </property> + <property name="backgroundVisible"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/examples/webchannel/standalone/index.html b/examples/webchannel/standalone/index.html new file mode 100644 index 000000000..7c042cd0c --- /dev/null +++ b/examples/webchannel/standalone/index.html @@ -0,0 +1,79 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <script type="text/javascript" src="./qwebchannel.js"></script> + <script type="text/javascript"> + //BEGIN SETUP + function output(message) { + var output = document.getElementById("output"); + output.innerHTML = output.innerHTML + message + "\n"; + } + window.onload = function() { + if (location.search != "") + var baseUrl = (/[?&]webChannelBaseUrl=([A-Za-z0-9\-:/\.]+)/.exec(location.search)[1]); + else + var baseUrl = "ws://localhost:12345"; + + output("Connecting to WebSocket server at " + baseUrl + "."); + var socket = new WebSocket(baseUrl); + + socket.onclose = function() { + console.error("web channel closed"); + }; + socket.onerror = function(error) { + console.error("web channel error: " + error); + }; + socket.onopen = function() { + output("WebSocket connected, setting up QWebChannel."); + new QWebChannel(socket, function(channel) { + // make core object accessible globally + window.core = channel.objects.core; + + document.getElementById("send").onclick = function() { + var input = document.getElementById("input"); + var text = input.value; + if (!text) { + return; + } + + output("Sent message: " + text); + input.value = ""; + core.receiveText(text); + } + + core.sendText.connect(function(message) { + output("Received message: " + message); + }); + + core.receiveText("Client connected, ready to send/receive messages!"); + output("Connected to WebChannel, ready to send/receive messages!"); + }); + } + } + //END SETUP + </script> + <style type="text/css"> + html { + height: 100%; + width: 100%; + } + #input { + width: 400px; + margin: 0 10px 0 0; + } + #send { + width: 90px; + margin: 0; + } + #output { + width: 500px; + height: 300px; + } + </style> + </head> + <body> + <textarea id="output"></textarea><br /> + <input id="input" /><input type="submit" id="send" value="Send" onclick="javascript:click();" /> + </body> +</html> diff --git a/examples/webchannel/standalone/main.py b/examples/webchannel/standalone/main.py new file mode 100644 index 000000000..d3119141f --- /dev/null +++ b/examples/webchannel/standalone/main.py @@ -0,0 +1,99 @@ +############################################################################# +## +## Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + + +import os +import sys + +from PySide2.QtWidgets import QApplication +from PySide2.QtGui import QDesktopServices +from PySide2.QtNetwork import QHostAddress, QSslSocket +from PySide2.QtCore import (QFile, QFileInfo, QUrl) +from PySide2.QtWebChannel import QWebChannel +from PySide2.QtWebSockets import QWebSocketServer + +from dialog import Dialog +from core import Core +from websocketclientwrapper import WebSocketClientWrapper + + +if __name__ == '__main__': + app = QApplication(sys.argv) + if not QSslSocket.supportsSsl(): + print('The example requires SSL support.') + sys.exit(-1) + cur_dir = os.path.dirname(os.path.abspath(__file__)) + jsFileInfo = QFileInfo(cur_dir + "/qwebchannel.js") + if not jsFileInfo.exists(): + QFile.copy(":/qtwebchannel/qwebchannel.js", + jsFileInfo.absoluteFilePath()) + + # setup the QWebSocketServer + server = QWebSocketServer("QWebChannel Standalone Example Server", + QWebSocketServer.NonSecureMode) + if not server.listen(QHostAddress.LocalHost, 12345): + print("Failed to open web socket server.") + sys.exit(-1) + + # wrap WebSocket clients in QWebChannelAbstractTransport objects + clientWrapper = WebSocketClientWrapper(server) + + # setup the channel + channel = QWebChannel() + clientWrapper.clientConnected.connect(channel.connectTo) + + # setup the UI + dialog = Dialog() + + # setup the core and publish it to the QWebChannel + core = Core(dialog) + channel.registerObject("core", core) + + # open a browser window with the client HTML page + url = QUrl.fromLocalFile(cur_dir + "/index.html") + QDesktopServices.openUrl(url) + + message = "Initialization complete, opening browser at {}.".format( + url.toDisplayString()) + dialog.displayMessage(message) + dialog.show() + + sys.exit(app.exec_()) diff --git a/examples/webchannel/standalone/standalone.pyproject b/examples/webchannel/standalone/standalone.pyproject new file mode 100644 index 000000000..b4fcdfa8e --- /dev/null +++ b/examples/webchannel/standalone/standalone.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["main.py", "core.py", "dialog.py", "websocketclientwrapper.py", + "websockettransport.py", "dialog.ui", "index.html"] +} diff --git a/examples/webchannel/standalone/ui_dialog.py b/examples/webchannel/standalone/ui_dialog.py new file mode 100644 index 000000000..873edba10 --- /dev/null +++ b/examples/webchannel/standalone/ui_dialog.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'dialog.ui' +## +## Created by: Qt User Interface Compiler version 5.14.1 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide2.QtCore import (QCoreApplication, QMetaObject, QObject, QPoint, + QRect, QSize, QUrl, Qt) +from PySide2.QtGui import (QBrush, QColor, QConicalGradient, QCursor, QFont, + QFontDatabase, QIcon, QLinearGradient, QPalette, QPainter, QPixmap, + QRadialGradient) +from PySide2.QtWidgets import * + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + if not Dialog.objectName(): + Dialog.setObjectName(u"Dialog") + Dialog.resize(400, 300) + self.gridLayout = QGridLayout(Dialog) + self.gridLayout.setObjectName(u"gridLayout") + self.input = QLineEdit(Dialog) + self.input.setObjectName(u"input") + + self.gridLayout.addWidget(self.input, 1, 0, 1, 1) + + self.send = QPushButton(Dialog) + self.send.setObjectName(u"send") + + self.gridLayout.addWidget(self.send, 1, 1, 1, 1) + + self.output = QPlainTextEdit(Dialog) + self.output.setObjectName(u"output") + self.output.setReadOnly(True) + self.output.setPlainText(u"Initializing WebChannel...") + self.output.setBackgroundVisible(False) + + self.gridLayout.addWidget(self.output, 0, 0, 1, 2) + + + self.retranslateUi(Dialog) + + QMetaObject.connectSlotsByName(Dialog) + # setupUi + + def retranslateUi(self, Dialog): + Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Dialog", None)) + self.input.setPlaceholderText(QCoreApplication.translate("Dialog", u"Message Contents", None)) + self.send.setText(QCoreApplication.translate("Dialog", u"Send", None)) + # retranslateUi + diff --git a/examples/webchannel/standalone/websocketclientwrapper.py b/examples/webchannel/standalone/websocketclientwrapper.py new file mode 100644 index 000000000..24505b03b --- /dev/null +++ b/examples/webchannel/standalone/websocketclientwrapper.py @@ -0,0 +1,72 @@ +############################################################################# +## +## Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +from PySide2.QtCore import QObject, Signal, Slot + +from websockettransport import WebSocketTransport + + +class WebSocketClientWrapper(QObject): + """Wraps connected QWebSockets clients in WebSocketTransport objects. + + This code is all that is required to connect incoming WebSockets to + the WebChannel. Any kind of remote JavaScript client that supports + WebSockets can thus receive messages and access the published objects. + """ + clientConnected = Signal(WebSocketTransport) + + def __init__(self, server, parent=None): + """Construct the client wrapper with the given parent. All clients + connecting to the QWebSocketServer will be automatically wrapped + in WebSocketTransport objects.""" + super(WebSocketClientWrapper, self).__init__(parent) + self._server = server + self._server.newConnection.connect(self.handleNewConnection) + self._transports = [] + + @Slot() + def handleNewConnection(self): + """Wrap an incoming WebSocket connection in a WebSocketTransport + object.""" + socket = self._server.nextPendingConnection() + transport = WebSocketTransport(socket) + self._transports.append(transport) + self.clientConnected.emit(transport) diff --git a/examples/webchannel/standalone/websockettransport.py b/examples/webchannel/standalone/websockettransport.py new file mode 100644 index 000000000..4e42e7674 --- /dev/null +++ b/examples/webchannel/standalone/websockettransport.py @@ -0,0 +1,88 @@ +############################################################################# +## +## Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +from PySide2.QtWebChannel import QWebChannelAbstractTransport +from PySide2.QtCore import QByteArray, QJsonDocument, Slot + + +class WebSocketTransport(QWebChannelAbstractTransport): + """QWebChannelAbstractSocket implementation using a QWebSocket internally. + + The transport delegates all messages received over the QWebSocket over + its textMessageReceived signal. Analogously, all calls to + sendTextMessage will be sent over the QWebSocket to the remote client. + """ + + def __init__(self, socket): + """Construct the transport object and wrap the given socket. + The socket is also set as the parent of the transport object.""" + super(WebSocketTransport, self).__init__(socket) + self._socket = socket + self._socket.textMessageReceived.connect(self.textMessageReceived) + self._socket.disconnected.connect(self._disconnected) + + def __del__(self): + """Destroys the WebSocketTransport.""" + self._socket.deleteLater() + + def _disconnected(self): + self.deleteLater() + + def sendMessage(self, message): + """Serialize the JSON message and send it as a text message via the + WebSocket to the client.""" + doc = QJsonDocument(message) + json_message = str(doc.toJson(QJsonDocument.Compact), "utf-8") + self._socket.sendTextMessage(json_message) + + @Slot(str) + def textMessageReceived(self, message_data_in): + """Deserialize the stringified JSON messageData and emit + messageReceived.""" + message_data = QByteArray(bytes(message_data_in, encoding='utf8')) + message = QJsonDocument.fromJson(message_data) + if message.isNull(): + print("Failed to parse text message as JSON object:", message_data) + return + if not message.isObject(): + print("Received JSON message that is not an object: ", message_data) + return + self.messageReceived.emit(message.object(), self) diff --git a/examples/webenginequick/webenginequick.pyproject b/examples/webenginequick/webenginequick.pyproject new file mode 100644 index 000000000..dd9039229 --- /dev/null +++ b/examples/webenginequick/webenginequick.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["quicknanobrowser.py", "browser.qml"] +} diff --git a/examples/webenginewidgets/simplebrowser.py b/examples/webenginewidgets/simplebrowser.py index 3d66aac23..365e69a05 100644 --- a/examples/webenginewidgets/simplebrowser.py +++ b/examples/webenginewidgets/simplebrowser.py @@ -44,7 +44,7 @@ import sys from PySide2.QtCore import QUrl from PySide2.QtGui import QIcon -from PySide2.QtWidgets import (QApplication, QDesktopWidget, QLineEdit, +from PySide2.QtWidgets import (QApplication, QLineEdit, QMainWindow, QPushButton, QToolBar) from PySide2.QtWebEngineWidgets import QWebEnginePage, QWebEngineView diff --git a/examples/webenginewidgets/tabbedbrowser/bookmarkwidget.py b/examples/webenginewidgets/tabbedbrowser/bookmarkwidget.py index 6bd2b4586..612c682cb 100644 --- a/examples/webenginewidgets/tabbedbrowser/bookmarkwidget.py +++ b/examples/webenginewidgets/tabbedbrowser/bookmarkwidget.py @@ -38,14 +38,14 @@ ## ############################################################################# -import json, os, warnings +import json +import os +import warnings from PySide2 import QtCore -from PySide2.QtCore import (QDir, QFileInfo, QModelIndex, QStandardPaths, Qt, - QUrl) -from PySide2.QtGui import QIcon, QPixmap, QStandardItem, QStandardItemModel -from PySide2.QtWidgets import (QAction, QDockWidget, QMenu, QMessageBox, - QToolBar, QTreeView, QWidget) +from PySide2.QtCore import QDir, QFileInfo, QStandardPaths, Qt, QUrl +from PySide2.QtGui import QIcon, QStandardItem, QStandardItemModel +from PySide2.QtWidgets import QMenu, QMessageBox, QTreeView _url_role = Qt.UserRole + 1 @@ -55,24 +55,28 @@ _default_bookmarks = [ ['Tool Bar'], ['http://qt.io', 'Qt', ':/qt-project.org/qmessagebox/images/qtlogo-64.png'], ['https://download.qt.io/snapshots/ci/pyside/', 'Downloads'], - ['https://doc-snapshots.qt.io/qtforpython/', 'Documentation'], + ['https://doc.qt.io/qtforpython/', 'Documentation'], ['https://bugreports.qt.io/projects/PYSIDE/', 'Bug Reports'], ['https://www.python.org/', 'Python', None], ['https://wiki.qt.io/PySide2', 'Qt for Python', None], ['Other Bookmarks'] ] + def _config_dir(): return '{}/QtForPythonBrowser'.format( QStandardPaths.writableLocation(QStandardPaths.ConfigLocation)) + _bookmark_file = 'bookmarks.json' + def _create_folder_item(title): result = QStandardItem(title) result.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) return result + def _create_item(url, title, icon): result = QStandardItem(title) result.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) @@ -81,6 +85,7 @@ def _create_item(url, title, icon): result.setIcon(icon) return result + # Create the model from an array of arrays def _create_model(parent, serialized_bookmarks): result = QStandardItemModel(0, 1, parent) @@ -96,6 +101,7 @@ def _create_model(parent, serialized_bookmarks): last_folder_item.appendRow(_create_item(url, title, icon)) return result + # Serialize model into an array of arrays, writing out the icons # into .png files under directory in the process def _serialize_model(model, directory): @@ -113,12 +119,14 @@ def _serialize_model(model, directory): icon_sizes = icon.availableSizes() largest_size = icon_sizes[len(icon_sizes) - 1] icon_file_name = '{}/icon{:02}_{:02}_{}.png'.format(directory, - f, i, largest_size.width()) + f, i, + largest_size.width()) icon.pixmap(largest_size).save(icon_file_name, 'PNG') entry.append(icon_file_name) result.append(entry) return result + # Bookmarks as a tree view to be used in a dock widget with # functionality to persist and populate tool bars and menus. class BookmarkWidget(QTreeView): @@ -189,7 +197,8 @@ class BookmarkWidget(QTreeView): action.setData(url) action.setVisible(True) else: - action = target_object.addAction(icon, BookmarkWidget.short_title(title)) + short_title = BookmarkWidget.short_title(title) + action = target_object.addAction(icon, short_title) action.setToolTip(title) action.setData(url) action.triggered.connect(self._action_activated) @@ -208,7 +217,7 @@ class BookmarkWidget(QTreeView): index = self.currentIndex() if index.isValid(): item = self._model.itemFromIndex(index) - if item.parent(): # exclude top level items + if item.parent(): # exclude top level items return item return None @@ -226,9 +235,9 @@ class BookmarkWidget(QTreeView): self._remove_item(current_item) def _remove_item(self, item): - button = QMessageBox.question(self, "Remove", - "Would you like to remove \"{}\"?".format(item.text()), - QMessageBox.Yes | QMessageBox.No) + message = "Would you like to remove \"{}\"?".format(item.text()) + button = QMessageBox.question(self, "Remove", message, + QMessageBox.Yes | QMessageBox.No) if button == QMessageBox.Yes: item.parent().removeRow(item.row()) @@ -248,11 +257,11 @@ class BookmarkWidget(QTreeView): bookmark_file_name = os.path.join(native_dir_path, _bookmark_file) print('Writing {}...'.format(bookmark_file_name)) with open(bookmark_file_name, 'w') as bookmark_file: - json.dump(serialized_model, bookmark_file, indent = 4) + json.dump(serialized_model, bookmark_file, indent=4) def _read_bookmarks(self): bookmark_file_name = os.path.join(QDir.toNativeSeparators(_config_dir()), - _bookmark_file) + _bookmark_file) if os.path.exists(bookmark_file_name): print('Reading {}...'.format(bookmark_file_name)) return json.load(open(bookmark_file_name)) diff --git a/examples/webenginewidgets/tabbedbrowser/browsertabwidget.py b/examples/webenginewidgets/tabbedbrowser/browsertabwidget.py index 29411d368..093eed6bb 100644 --- a/examples/webenginewidgets/tabbedbrowser/browsertabwidget.py +++ b/examples/webenginewidgets/tabbedbrowser/browsertabwidget.py @@ -39,16 +39,15 @@ ############################################################################# from functools import partial -import sys from bookmarkwidget import BookmarkWidget from webengineview import WebEngineView from historywindow import HistoryWindow from PySide2 import QtCore -from PySide2.QtCore import QPoint, Qt, QUrl -from PySide2.QtWidgets import (QAction, QMenu, QTabBar, QTabWidget) -from PySide2.QtWebEngineWidgets import (QWebEngineDownloadItem, - QWebEngineHistory, QWebEnginePage, QWebEngineProfile) +from PySide2.QtCore import Qt, QUrl +from PySide2.QtWidgets import QMenu, QTabBar, QTabWidget +from PySide2.QtWebEngineWidgets import QWebEngineDownloadItem, QWebEnginePage + class BrowserTabWidget(QTabWidget): """Enables having several tabs with QWebEngineView.""" @@ -62,7 +61,7 @@ class BrowserTabWidget(QTabWidget): self.setTabsClosable(True) self._window_factory_function = window_factory_function self._webengineviews = [] - self._history_windows = {} # map WebengineView to HistoryWindow + self._history_windows = {} # map WebengineView to HistoryWindow self.currentChanged.connect(self._current_changed) self.tabCloseRequested.connect(self.handle_tab_close_request) self._actions_enabled = {} @@ -76,7 +75,8 @@ class BrowserTabWidget(QTabWidget): def add_browser_tab(self): factory_func = partial(BrowserTabWidget.add_browser_tab, self) - web_engine_view = WebEngineView(factory_func, self._window_factory_function) + web_engine_view = WebEngineView(factory_func, + self._window_factory_function) index = self.count() self._webengineviews.append(web_engine_view) title = 'Tab {}'.format(index + 1) @@ -211,7 +211,7 @@ class BrowserTabWidget(QTabWidget): elif chosen_action == close_other_tabs_action: for t in range(tab_count - 1, -1, -1): if t != index: - self.handle_tab_close_request(t) + self.handle_tab_close_request(t) elif chosen_action == close_tabs_to_the_right_action: for t in range(tab_count - 1, index, -1): self.handle_tab_close_request(t) @@ -241,4 +241,4 @@ class BrowserTabWidget(QTabWidget): return -1 def _download_requested(self, item): - self.downloadRequested.emit(item) + self.download_requested.emit(item) diff --git a/examples/webenginewidgets/tabbedbrowser/downloadwidget.py b/examples/webenginewidgets/tabbedbrowser/downloadwidget.py index 437c534ec..73b8d116b 100644 --- a/examples/webenginewidgets/tabbedbrowser/downloadwidget.py +++ b/examples/webenginewidgets/tabbedbrowser/downloadwidget.py @@ -42,10 +42,10 @@ import sys from PySide2 import QtCore from PySide2.QtCore import QDir, QFileInfo, QStandardPaths, Qt, QUrl from PySide2.QtGui import QDesktopServices -from PySide2.QtWidgets import (QAction, QLabel, QMenu, QProgressBar, - QStyleFactory, QWidget) +from PySide2.QtWidgets import QMenu, QProgressBar, QStyleFactory from PySide2.QtWebEngineWidgets import QWebEngineDownloadItem + # A QProgressBar with context menu for displaying downloads in a QStatusBar. class DownloadWidget(QProgressBar): """Lets you track progress of a QWebEngineDownloadItem.""" @@ -64,7 +64,8 @@ class DownloadWidget(QProgressBar): description = QFileInfo(path).fileName() description_length = len(description) if description_length > 30: - description = '{}...{}'.format(description[0:10], description[description_length - 10:]) + description = '{}...{}'.format(description[0:10], + description[description_length - 10:]) self.setFormat('{} %p%'.format(description)) self.setOrientation(Qt.Horizontal) self.setMinimum(0) @@ -90,8 +91,8 @@ class DownloadWidget(QProgressBar): def _update_tool_tip(self): path = self._download_item.path() tool_tip = "{}\n{}".format(self._download_item.url().toString(), - QDir.toNativeSeparators(path)) - total_bytes = self._download_item.total_bytes() + QDir.toNativeSeparators(path)) + total_bytes = self._download_item.totalBytes() if total_bytes > 0: tool_tip += "\n{}K".format(total_bytes / 1024) state = self.state() @@ -117,11 +118,11 @@ class DownloadWidget(QProgressBar): def _launch(self): DownloadWidget.open_file(self._download_item.path()) - def mouse_double_click_event(self, event): + def mouseDoubleClickEvent(self, event): if self.state() == QWebEngineDownloadItem.DownloadCompleted: self._launch() - def context_menu_event(self, event): + def contextMenuEvent(self, event): state = self.state() context_menu = QMenu() launch_action = context_menu.addAction("Launch") @@ -137,7 +138,8 @@ class DownloadWidget(QProgressBar): if chosen_action == launch_action: self._launch() elif chosen_action == show_in_folder_action: - DownloadWidget.open_file(QFileInfo(self._download_item.path()).absolutePath()) + path = QFileInfo(self._download_item.path()).absolutePath() + DownloadWidget.open_file(path) elif chosen_action == cancel_action: self._download_item.cancel() elif chosen_action == remove_action: diff --git a/examples/webenginewidgets/tabbedbrowser/findtoolbar.py b/examples/webenginewidgets/tabbedbrowser/findtoolbar.py index 68a1fd595..3557c2e31 100644 --- a/examples/webenginewidgets/tabbedbrowser/findtoolbar.py +++ b/examples/webenginewidgets/tabbedbrowser/findtoolbar.py @@ -39,12 +39,12 @@ ############################################################################# from PySide2 import QtCore -from PySide2.QtCore import Qt, QUrl +from PySide2.QtCore import Qt from PySide2.QtGui import QIcon, QKeySequence -from PySide2.QtWidgets import (QAction, QCheckBox, QDockWidget, QHBoxLayout, - QLabel, QLineEdit, QToolBar, QToolButton, QWidget) +from PySide2.QtWidgets import QCheckBox, QLineEdit, QToolBar, QToolButton from PySide2.QtWebEngineWidgets import QWebEnginePage + # A Find tool bar (bottom area) class FindToolBar(QToolBar): @@ -60,12 +60,13 @@ class FindToolBar(QToolBar): self.addWidget(self._line_edit) self._previous_button = QToolButton() - self._previous_button.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/up-32.png')) + style_icons = ':/qt-project.org/styles/commonstyle/images/' + self._previous_button.setIcon(QIcon(style_icons + 'up-32.png')) self._previous_button.clicked.connect(self._find_previous) self.addWidget(self._previous_button) self._next_button = QToolButton() - self._next_button.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/down-32.png')) + self._next_button.setIcon(QIcon(style_icons + 'down-32.png')) self._next_button.clicked.connect(self._find_next) self.addWidget(self._next_button) @@ -74,7 +75,7 @@ class FindToolBar(QToolBar): self._hideButton = QToolButton() self._hideButton.setShortcut(QKeySequence(Qt.Key_Escape)) - self._hideButton.setIcon(QIcon(':/qt-project.org/styles/macstyle/images/closedock-16.png')) + self._hideButton.setIcon(QIcon(style_icons + 'closedock-16.png')) self._hideButton.clicked.connect(self.hide) self.addWidget(self._hideButton) @@ -82,7 +83,7 @@ class FindToolBar(QToolBar): self._line_edit.setFocus() def _emit_find(self, backward): - needle = self._line_edit.text().strip() + needle = self._line_edit.text().strip() if needle: flags = QWebEnginePage.FindFlags() if self._case_sensitive_checkbox.isChecked(): diff --git a/examples/webenginewidgets/tabbedbrowser/historywindow.py b/examples/webenginewidgets/tabbedbrowser/historywindow.py index 06c9b73be..6ce779743 100644 --- a/examples/webenginewidgets/tabbedbrowser/historywindow.py +++ b/examples/webenginewidgets/tabbedbrowser/historywindow.py @@ -38,18 +38,14 @@ ## ############################################################################# -from PySide2.QtWebEngineWidgets import (QWebEnginePage, QWebEngineView, - QWebEngineHistory, QWebEngineHistoryItem) +from PySide2.QtWidgets import QApplication, QTreeView -from PySide2.QtWidgets import QApplication, QDesktopWidget, QTreeView - -from PySide2.QtCore import (Signal, QAbstractTableModel, QModelIndex, Qt, - QRect, QUrl) +from PySide2.QtCore import Signal, QAbstractTableModel, QModelIndex, Qt, QUrl class HistoryModel(QAbstractTableModel): - def __init__(self, history, parent = None): + def __init__(self, history, parent=None): super(HistoryModel, self).__init__(parent) self._history = history diff --git a/examples/webenginewidgets/tabbedbrowser/main.py b/examples/webenginewidgets/tabbedbrowser/main.py index 51220469a..438dd5c9d 100644 --- a/examples/webenginewidgets/tabbedbrowser/main.py +++ b/examples/webenginewidgets/tabbedbrowser/main.py @@ -46,36 +46,39 @@ from bookmarkwidget import BookmarkWidget from browsertabwidget import BrowserTabWidget from downloadwidget import DownloadWidget from findtoolbar import FindToolBar -from webengineview import QWebEnginePage, WebEngineView +from webengineview import WebEngineView from PySide2 import QtCore from PySide2.QtCore import Qt, QUrl -from PySide2.QtGui import QCloseEvent, QKeySequence, QIcon -from PySide2.QtWidgets import (qApp, QAction, QApplication, QDesktopWidget, - QDockWidget, QLabel, QLineEdit, QMainWindow, QMenu, QMenuBar, QPushButton, - QStatusBar, QToolBar) -from PySide2.QtWebEngineWidgets import (QWebEngineDownloadItem, QWebEnginePage, - QWebEngineView) +from PySide2.QtGui import QKeySequence, QIcon +from PySide2.QtWidgets import (QAction, QApplication, QDockWidget, QLabel, + QLineEdit, QMainWindow, QToolBar) +from PySide2.QtWebEngineWidgets import QWebEngineDownloadItem, QWebEnginePage main_windows = [] + def create_main_window(): """Creates a MainWindow using 75% of the available screen resolution.""" main_win = MainWindow() main_windows.append(main_win) available_geometry = app.desktop().availableGeometry(main_win) - main_win.resize(available_geometry.width() * 2 / 3, available_geometry.height() * 2 / 3) + main_win.resize(available_geometry.width() * 2 / 3, + available_geometry.height() * 2 / 3) main_win.show() return main_win + def create_main_window_with_browser(): """Creates a MainWindow with a BrowserTabWidget.""" main_win = create_main_window() return main_win.add_browser_tab() + class MainWindow(QMainWindow): """Provides the parent window that includes the BookmarkWidget, BrowserTabWidget, and a DownloadWidget, to offer the complete web browsing experience.""" + def __init__(self): super(MainWindow, self).__init__() @@ -128,33 +131,33 @@ class MainWindow(QMainWindow): def _create_menu(self): file_menu = self.menuBar().addMenu("&File") exit_action = QAction(QIcon.fromTheme("application-exit"), "E&xit", - self, shortcut = "Ctrl+Q", triggered=qApp.quit) + self, shortcut="Ctrl+Q", triggered=qApp.quit) file_menu.addAction(exit_action) navigation_menu = self.menuBar().addMenu("&Navigation") style_icons = ':/qt-project.org/styles/commonstyle/images/' back_action = QAction(QIcon.fromTheme("go-previous", - QIcon(style_icons + 'left-32.png')), - "Back", self, - shortcut = QKeySequence(QKeySequence.Back), - triggered = self._tab_widget.back) + QIcon(style_icons + 'left-32.png')), + "Back", self, + shortcut=QKeySequence(QKeySequence.Back), + triggered=self._tab_widget.back) self._actions[QWebEnginePage.Back] = back_action back_action.setEnabled(False) navigation_menu.addAction(back_action) forward_action = QAction(QIcon.fromTheme("go-next", - QIcon(style_icons + 'right-32.png')), - "Forward", self, - shortcut = QKeySequence(QKeySequence.Forward), - triggered = self._tab_widget.forward) + QIcon(style_icons + 'right-32.png')), + "Forward", self, + shortcut=QKeySequence(QKeySequence.Forward), + triggered=self._tab_widget.forward) forward_action.setEnabled(False) self._actions[QWebEnginePage.Forward] = forward_action navigation_menu.addAction(forward_action) reload_action = QAction(QIcon(style_icons + 'refresh-32.png'), - "Reload", self, - shortcut = QKeySequence(QKeySequence.Refresh), - triggered = self._tab_widget.reload) + "Reload", self, + shortcut=QKeySequence(QKeySequence.Refresh), + triggered=self._tab_widget.reload) self._actions[QWebEnginePage.Reload] = reload_action reload_action.setEnabled(False) navigation_menu.addAction(reload_action) @@ -162,39 +165,39 @@ class MainWindow(QMainWindow): navigation_menu.addSeparator() new_tab_action = QAction("New Tab", self, - shortcut = 'Ctrl+T', - triggered = self.add_browser_tab) + shortcut='Ctrl+T', + triggered=self.add_browser_tab) navigation_menu.addAction(new_tab_action) close_tab_action = QAction("Close Current Tab", self, - shortcut = "Ctrl+W", - triggered = self._close_current_tab) + shortcut="Ctrl+W", + triggered=self._close_current_tab) navigation_menu.addAction(close_tab_action) navigation_menu.addSeparator() history_action = QAction("History...", self, - triggered = self._tab_widget.show_history) + triggered=self._tab_widget.show_history) navigation_menu.addAction(history_action) edit_menu = self.menuBar().addMenu("&Edit") find_action = QAction("Find", self, - shortcut = QKeySequence(QKeySequence.Find), - triggered = self._show_find) + shortcut=QKeySequence(QKeySequence.Find), + triggered=self._show_find) edit_menu.addAction(find_action) edit_menu.addSeparator() undo_action = QAction("Undo", self, - shortcut = QKeySequence(QKeySequence.Undo), - triggered = self._tab_widget.undo) + shortcut=QKeySequence(QKeySequence.Undo), + triggered=self._tab_widget.undo) self._actions[QWebEnginePage.Undo] = undo_action undo_action.setEnabled(False) edit_menu.addAction(undo_action) redo_action = QAction("Redo", self, - shortcut = QKeySequence(QKeySequence.Redo), - triggered = self._tab_widget.redo) + shortcut=QKeySequence(QKeySequence.Redo), + triggered=self._tab_widget.redo) self._actions[QWebEnginePage.Redo] = redo_action redo_action.setEnabled(False) edit_menu.addAction(redo_action) @@ -202,22 +205,22 @@ class MainWindow(QMainWindow): edit_menu.addSeparator() cut_action = QAction("Cut", self, - shortcut = QKeySequence(QKeySequence.Cut), - triggered = self._tab_widget.cut) + shortcut=QKeySequence(QKeySequence.Cut), + triggered=self._tab_widget.cut) self._actions[QWebEnginePage.Cut] = cut_action cut_action.setEnabled(False) edit_menu.addAction(cut_action) copy_action = QAction("Copy", self, - shortcut = QKeySequence(QKeySequence.Copy), - triggered = self._tab_widget.copy) + shortcut=QKeySequence(QKeySequence.Copy), + triggered=self._tab_widget.copy) self._actions[QWebEnginePage.Copy] = copy_action copy_action.setEnabled(False) edit_menu.addAction(copy_action) paste_action = QAction("Paste", self, - shortcut = QKeySequence(QKeySequence.Paste), - triggered = self._tab_widget.paste) + shortcut=QKeySequence(QKeySequence.Paste), + triggered=self._tab_widget.paste) self._actions[QWebEnginePage.Paste] = paste_action paste_action.setEnabled(False) edit_menu.addAction(paste_action) @@ -225,24 +228,24 @@ class MainWindow(QMainWindow): edit_menu.addSeparator() select_all_action = QAction("Select All", self, - shortcut = QKeySequence(QKeySequence.SelectAll), - triggered = self._tab_widget.select_all) + shortcut=QKeySequence(QKeySequence.SelectAll), + triggered=self._tab_widget.select_all) self._actions[QWebEnginePage.SelectAll] = select_all_action select_all_action.setEnabled(False) edit_menu.addAction(select_all_action) self._bookmark_menu = self.menuBar().addMenu("&Bookmarks") add_bookmark_action = QAction("&Add Bookmark", self, - triggered = self._add_bookmark) + triggered=self._add_bookmark) self._bookmark_menu.addAction(add_bookmark_action) add_tool_bar_bookmark_action = QAction("&Add Bookmark to Tool Bar", self, - triggered = self._add_tool_bar_bookmark) + triggered=self._add_tool_bar_bookmark) self._bookmark_menu.addAction(add_tool_bar_bookmark_action) self._bookmark_menu.addSeparator() tools_menu = self.menuBar().addMenu("&Tools") download_action = QAction("Open Downloads", self, - triggered = DownloadWidget.open_download_directory) + triggered=DownloadWidget.open_download_directory) tools_menu.addAction(download_action) window_menu = self.menuBar().addMenu("&Window") @@ -252,26 +255,26 @@ class MainWindow(QMainWindow): window_menu.addSeparator() zoom_in_action = QAction(QIcon.fromTheme("zoom-in"), - "Zoom In", self, - shortcut = QKeySequence(QKeySequence.ZoomIn), - triggered = self._zoom_in) + "Zoom In", self, + shortcut=QKeySequence(QKeySequence.ZoomIn), + triggered=self._zoom_in) window_menu.addAction(zoom_in_action) zoom_out_action = QAction(QIcon.fromTheme("zoom-out"), - "Zoom Out", self, - shortcut = QKeySequence(QKeySequence.ZoomOut), - triggered = self._zoom_out) + "Zoom Out", self, + shortcut=QKeySequence(QKeySequence.ZoomOut), + triggered=self._zoom_out) window_menu.addAction(zoom_out_action) reset_zoom_action = QAction(QIcon.fromTheme("zoom-original"), - "Reset Zoom", self, - shortcut = "Ctrl+0", - triggered = self._reset_zoom) + "Reset Zoom", self, + shortcut="Ctrl+0", + triggered=self._reset_zoom) window_menu.addAction(reset_zoom_action) about_menu = self.menuBar().addMenu("&About") about_action = QAction("About Qt", self, - shortcut = QKeySequence(QKeySequence.HelpContents), - triggered=qApp.aboutQt) + shortcut=QKeySequence(QKeySequence.HelpContents), + triggered=qApp.aboutQt) about_menu.addAction(about_action) def add_browser_tab(self): @@ -350,15 +353,15 @@ class MainWindow(QMainWindow): def _download_requested(self, item): # Remove old downloads before opening a new one for old_download in self.statusBar().children(): - if type(old_download).__name__ == 'download_widget' and \ - old_download.state() != QWebEngineDownloadItem.DownloadInProgress: + if (type(old_download).__name__ == 'DownloadWidget' and + old_download.state() != QWebEngineDownloadItem.DownloadInProgress): self.statusBar().removeWidget(old_download) del old_download item.accept() - download_widget = download_widget(item) - download_widget.removeRequested.connect(self._remove_download_requested, - Qt.QueuedConnection) + download_widget = DownloadWidget(item) + download_widget.remove_requested.connect(self._remove_download_requested, + Qt.QueuedConnection) self.statusBar().addWidget(download_widget) def _remove_download_requested(self): @@ -378,6 +381,7 @@ class MainWindow(QMainWindow): def write_bookmarks(self): self._bookmark_widget.write_bookmarks() + if __name__ == '__main__': app = QApplication(sys.argv) main_win = create_main_window() diff --git a/examples/webenginewidgets/tabbedbrowser/webengineview.py b/examples/webenginewidgets/tabbedbrowser/webengineview.py index 4fdbf1801..81b156f93 100644 --- a/examples/webenginewidgets/tabbedbrowser/webengineview.py +++ b/examples/webenginewidgets/tabbedbrowser/webengineview.py @@ -38,16 +38,16 @@ ## ############################################################################# -import sys from PySide2.QtWebEngineWidgets import QWebEnginePage, QWebEngineView from PySide2 import QtCore _web_actions = [QWebEnginePage.Back, QWebEnginePage.Forward, - QWebEnginePage.Reload, - QWebEnginePage.Undo, QWebEnginePage.Redo, - QWebEnginePage.Cut, QWebEnginePage.Copy, - QWebEnginePage.Paste, QWebEnginePage.SelectAll] + QWebEnginePage.Reload, + QWebEnginePage.Undo, QWebEnginePage.Redo, + QWebEnginePage.Cut, QWebEnginePage.Copy, + QWebEnginePage.Paste, QWebEnginePage.SelectAll] + class WebEngineView(QWebEngineView): @@ -80,7 +80,8 @@ class WebEngineView(QWebEngineView): return self.page().action(web_action).isEnabled() def createWindow(self, window_type): - if window_type == QWebEnginePage.WebBrowserTab or window_type == QWebEnginePage.WebBrowserBackgroundTab: + if (window_type == QWebEnginePage.WebBrowserTab or + window_type == QWebEnginePage.WebBrowserBackgroundTab): return self._tab_factory_func() return self._window_factory_func() diff --git a/examples/webenginewidgets/webenginewidgets.pyproject b/examples/webenginewidgets/webenginewidgets.pyproject new file mode 100644 index 000000000..6bc12af6b --- /dev/null +++ b/examples/webenginewidgets/webenginewidgets.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["simplebrowser.py"] +} diff --git a/examples/widgets/animation/animatedtiles/animatedtiles.pyproject b/examples/widgets/animation/animatedtiles/animatedtiles.pyproject new file mode 100644 index 000000000..08ee55685 --- /dev/null +++ b/examples/widgets/animation/animatedtiles/animatedtiles.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["animatedtiles.qrc", "animatedtiles.py", + "animatedtiles_rc.py"] +} diff --git a/examples/widgets/animation/appchooser/appchooser.pyproject b/examples/widgets/animation/appchooser/appchooser.pyproject new file mode 100644 index 000000000..14bc351a1 --- /dev/null +++ b/examples/widgets/animation/appchooser/appchooser.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["appchooser_rc.py", "appchooser.py", "appchooser.qrc"] +} diff --git a/examples/widgets/animation/easing/easing.pyproject b/examples/widgets/animation/easing/easing.pyproject new file mode 100644 index 000000000..2677e28ea --- /dev/null +++ b/examples/widgets/animation/easing/easing.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["easing.qrc", "ui_form.py", "easing.py", "easing_rc.py", + "form.ui"] +} diff --git a/examples/widgets/animation/easing/ui_form.py b/examples/widgets/animation/easing/ui_form.py index 515a4ee91..c2279c5c5 100644 --- a/examples/widgets/animation/easing/ui_form.py +++ b/examples/widgets/animation/easing/ui_form.py @@ -18,13 +18,13 @@ class Ui_Form(object): if Form.objectName(): Form.setObjectName(u"Form") Form.resize(545, 471) - self.gridLayout = QGridLayout(Form); + self.gridLayout = QGridLayout(Form) self.gridLayout.setObjectName(u"gridLayout") self.easingCurvePicker = QListWidget(Form) self.easingCurvePicker.setObjectName(u"easingCurvePicker") sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.easingCurvePicker.sizePolicy().hasHeightForWidth()) self.easingCurvePicker.setSizePolicy(sizePolicy) self.easingCurvePicker.setMaximumSize(QSize(16777215, 120)) @@ -34,13 +34,13 @@ class Ui_Form(object): self.easingCurvePicker.setViewMode(QListView.IconMode) self.easingCurvePicker.setSelectionRectVisible(False) - self.gridLayout.addWidget(self.easingCurvePicker, 0, 0, 1, 2); + self.gridLayout.addWidget(self.easingCurvePicker, 0, 0, 1, 2) - self.verticalLayout = QVBoxLayout(); + self.verticalLayout = QVBoxLayout() self.verticalLayout.setObjectName(u"verticalLayout") self.groupBox_2 = QGroupBox(Form) self.groupBox_2.setObjectName(u"groupBox_2") - self.verticalLayout_2 = QVBoxLayout(self.groupBox_2); + self.verticalLayout_2 = QVBoxLayout(self.groupBox_2) self.verticalLayout_2.setObjectName(u"verticalLayout_2") self.lineRadio = QRadioButton(self.groupBox_2) self.buttonGroup = QButtonGroup(Form) @@ -50,31 +50,31 @@ class Ui_Form(object): self.lineRadio.setObjectName(u"lineRadio") self.lineRadio.setChecked(True) - self.verticalLayout_2.addWidget(self.lineRadio); + self.verticalLayout_2.addWidget(self.lineRadio) self.circleRadio = QRadioButton(self.groupBox_2) self.buttonGroup.addButton(self.circleRadio) self.circleRadio.setObjectName(u"circleRadio") - self.verticalLayout_2.addWidget(self.circleRadio); + self.verticalLayout_2.addWidget(self.circleRadio) - self.verticalLayout.addWidget(self.groupBox_2); + self.verticalLayout.addWidget(self.groupBox_2) self.groupBox = QGroupBox(Form) self.groupBox.setObjectName(u"groupBox") sizePolicy1 = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) - sizePolicy1.setHorizontalStretch(0); - sizePolicy1.setVerticalStretch(0); + sizePolicy1.setHorizontalStretch(0) + sizePolicy1.setVerticalStretch(0) sizePolicy1.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) self.groupBox.setSizePolicy(sizePolicy1) - self.formLayout = QFormLayout(self.groupBox); + self.formLayout = QFormLayout(self.groupBox) self.formLayout.setObjectName(u"formLayout") self.formLayout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) self.label = QLabel(self.groupBox) self.label.setObjectName(u"label") - self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label); + self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label) self.periodSpinBox = QDoubleSpinBox(self.groupBox) self.periodSpinBox.setObjectName(u"periodSpinBox") @@ -83,12 +83,12 @@ class Ui_Form(object): self.periodSpinBox.setSingleStep(0.100000000000000) self.periodSpinBox.setValue(-1.000000000000000) - self.formLayout.setWidget(0, QFormLayout.FieldRole, self.periodSpinBox); + self.formLayout.setWidget(0, QFormLayout.FieldRole, self.periodSpinBox) self.label_2 = QLabel(self.groupBox) self.label_2.setObjectName(u"label_2") - self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_2); + self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_2) self.amplitudeSpinBox = QDoubleSpinBox(self.groupBox) self.amplitudeSpinBox.setObjectName(u"amplitudeSpinBox") @@ -97,12 +97,12 @@ class Ui_Form(object): self.amplitudeSpinBox.setSingleStep(0.100000000000000) self.amplitudeSpinBox.setValue(-1.000000000000000) - self.formLayout.setWidget(1, QFormLayout.FieldRole, self.amplitudeSpinBox); + self.formLayout.setWidget(1, QFormLayout.FieldRole, self.amplitudeSpinBox) self.label_3 = QLabel(self.groupBox) self.label_3.setObjectName(u"label_3") - self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3); + self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3) self.overshootSpinBox = QDoubleSpinBox(self.groupBox) self.overshootSpinBox.setObjectName(u"overshootSpinBox") @@ -111,27 +111,27 @@ class Ui_Form(object): self.overshootSpinBox.setSingleStep(0.100000000000000) self.overshootSpinBox.setValue(-1.000000000000000) - self.formLayout.setWidget(2, QFormLayout.FieldRole, self.overshootSpinBox); + self.formLayout.setWidget(2, QFormLayout.FieldRole, self.overshootSpinBox) - self.verticalLayout.addWidget(self.groupBox); + self.verticalLayout.addWidget(self.groupBox) - self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding); + self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - self.verticalLayout.addItem(self.verticalSpacer); + self.verticalLayout.addItem(self.verticalSpacer) - self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1); + self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1) self.graphicsView = QGraphicsView(Form) self.graphicsView.setObjectName(u"graphicsView") sizePolicy2 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - sizePolicy2.setHorizontalStretch(0); - sizePolicy2.setVerticalStretch(0); + sizePolicy2.setHorizontalStretch(0) + sizePolicy2.setVerticalStretch(0) sizePolicy2.setHeightForWidth(self.graphicsView.sizePolicy().hasHeightForWidth()) self.graphicsView.setSizePolicy(sizePolicy2) - self.gridLayout.addWidget(self.graphicsView, 1, 1, 1, 1); + self.gridLayout.addWidget(self.graphicsView, 1, 1, 1, 1) self.retranslateUi(Form) diff --git a/examples/widgets/animation/states/states.pyproject b/examples/widgets/animation/states/states.pyproject new file mode 100644 index 000000000..d94cf2e65 --- /dev/null +++ b/examples/widgets/animation/states/states.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["states.py", "states_rc.py"] +} diff --git a/examples/widgets/dialogs/classwizard/classwizard.pyproject b/examples/widgets/dialogs/classwizard/classwizard.pyproject new file mode 100644 index 000000000..1c1fe9998 --- /dev/null +++ b/examples/widgets/dialogs/classwizard/classwizard.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["classwizard.qrc", "classwizard.py", "classwizard_rc.py", + "classwizard_rc.pyc"] +} diff --git a/examples/widgets/dialogs/dialogs.pyproject b/examples/widgets/dialogs/dialogs.pyproject new file mode 100644 index 000000000..001fd141b --- /dev/null +++ b/examples/widgets/dialogs/dialogs.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["findfiles.py", "standarddialogs.py", "extension.py", + "trivialwizard.py"] +} diff --git a/examples/widgets/dialogs/findfiles.py b/examples/widgets/dialogs/findfiles.py index 9d18324ad..cf2be86db 100644 --- a/examples/widgets/dialogs/findfiles.py +++ b/examples/widgets/dialogs/findfiles.py @@ -131,7 +131,7 @@ class Window(QtWidgets.QDialog): for i in range(len(files)): progressDialog.setValue(i) progressDialog.setLabelText("Searching file number %d of %d..." % (i, len(files))) - QtCore.qApp.processEvents() + QtCore.QCoreApplication.processEvents() if progressDialog.wasCanceled(): break diff --git a/examples/widgets/draganddrop/draggabletext/draggabletext.pyproject b/examples/widgets/draganddrop/draggabletext/draggabletext.pyproject new file mode 100644 index 000000000..0d422076e --- /dev/null +++ b/examples/widgets/draganddrop/draggabletext/draggabletext.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["draggabletext_rc.py", "words.txt", "draggabletext.qrc", + "draggabletext.py"] +} diff --git a/examples/widgets/effects/effects.pyproject b/examples/widgets/effects/effects.pyproject new file mode 100644 index 000000000..c64fe46d4 --- /dev/null +++ b/examples/widgets/effects/effects.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["lighting.py"] +} diff --git a/examples/widgets/graphicsview/anchorlayout.py b/examples/widgets/graphicsview/anchorlayout.py index 3e2c54d78..f7f4edc65 100644 --- a/examples/widgets/graphicsview/anchorlayout.py +++ b/examples/widgets/graphicsview/anchorlayout.py @@ -40,7 +40,7 @@ ## ############################################################################# -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets def createItem(minimum, preferred, maximum, name): diff --git a/examples/widgets/graphicsview/collidingmice/collidingmice.pyproject b/examples/widgets/graphicsview/collidingmice/collidingmice.pyproject new file mode 100644 index 000000000..ea5821866 --- /dev/null +++ b/examples/widgets/graphicsview/collidingmice/collidingmice.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["collidingmice.py", "mice_rc.py"] +} diff --git a/examples/widgets/graphicsview/diagramscene/diagramscene.pyproject b/examples/widgets/graphicsview/diagramscene/diagramscene.pyproject new file mode 100644 index 000000000..0acabdd78 --- /dev/null +++ b/examples/widgets/graphicsview/diagramscene/diagramscene.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["diagramscene.qrc", "diagramscene.py", "diagramscene_rc.py"] +} diff --git a/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.pyproject b/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.pyproject new file mode 100644 index 000000000..587484a97 --- /dev/null +++ b/examples/widgets/graphicsview/dragdroprobot/dragdroprobot.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["dragdroprobot.qrc", "dragdroprobot_rc.py", "dragdroprobot.py"] +} diff --git a/examples/widgets/graphicsview/graphicsview.pyproject b/examples/widgets/graphicsview/graphicsview.pyproject new file mode 100644 index 000000000..007d36bd2 --- /dev/null +++ b/examples/widgets/graphicsview/graphicsview.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["elasticnodes.py", "anchorlayout.py"] +} diff --git a/examples/widgets/itemviews/addressbook/addressbook.pyproject b/examples/widgets/itemviews/addressbook/addressbook.pyproject new file mode 100644 index 000000000..2aa763753 --- /dev/null +++ b/examples/widgets/itemviews/addressbook/addressbook.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["tablemodel.py", "addressbook.py", "adddialogwidget.py", + "addresswidget.py", "newaddresstab.py"] +} diff --git a/examples/widgets/itemviews/addressbook/addresswidget.py b/examples/widgets/itemviews/addressbook/addresswidget.py index 42c75e326..b70b44b0a 100644 --- a/examples/widgets/itemviews/addressbook/addresswidget.py +++ b/examples/widgets/itemviews/addressbook/addresswidget.py @@ -46,9 +46,8 @@ except ImportError: import pickle from PySide2.QtCore import (Qt, Signal, QRegExp, QModelIndex, - QItemSelection, QItemSelectionModel, QSortFilterProxyModel) -from PySide2.QtWidgets import (QWidget, QTabWidget, QMessageBox, QTableView, - QAbstractItemView) + QItemSelection, QSortFilterProxyModel) +from PySide2.QtWidgets import QTabWidget, QMessageBox, QTableView, QAbstractItemView from tablemodel import TableModel from newaddresstab import NewAddressTab diff --git a/examples/widgets/itemviews/fetchmore.py b/examples/widgets/itemviews/fetchmore.py index 7db8ae447..2b0d8c104 100644 --- a/examples/widgets/itemviews/fetchmore.py +++ b/examples/widgets/itemviews/fetchmore.py @@ -41,7 +41,7 @@ ## ############################################################################# -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets class FileListModel(QtCore.QAbstractListModel): @@ -70,9 +70,9 @@ class FileListModel(QtCore.QAbstractListModel): batch = (index.row() // 100) % 2 # FIXME: QGuiApplication::palette() required if batch == 0: - return QtWidgets.qApp.palette().base() + return qApp.palette().base() - return QtWidgets.qApp.palette().alternateBase() + return qApp.palette().alternateBase() return None diff --git a/examples/widgets/itemviews/itemviews.pyproject b/examples/widgets/itemviews/itemviews.pyproject new file mode 100644 index 000000000..a582259cc --- /dev/null +++ b/examples/widgets/itemviews/itemviews.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["basicsortfiltermodel.py", "fetchmore.py"] +} diff --git a/examples/widgets/itemviews/stardelegate/stardelegate.py b/examples/widgets/itemviews/stardelegate/stardelegate.py index 236dc3db8..86fd99ce6 100644 --- a/examples/widgets/itemviews/stardelegate/stardelegate.py +++ b/examples/widgets/itemviews/stardelegate/stardelegate.py @@ -41,7 +41,7 @@ ## ############################################################################# -from PySide2.QtWidgets import (QItemDelegate, QStyledItemDelegate, QStyle) +from PySide2.QtWidgets import QStyledItemDelegate, QStyle from starrating import StarRating from stareditor import StarEditor diff --git a/examples/widgets/itemviews/stardelegate/stardelegate.pyproject b/examples/widgets/itemviews/stardelegate/stardelegate.pyproject new file mode 100644 index 000000000..13fdf9dde --- /dev/null +++ b/examples/widgets/itemviews/stardelegate/stardelegate.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["stardelegate.py", "stareditor.py", "starrating.py"] +} diff --git a/examples/widgets/itemviews/stardelegate/stareditor.py b/examples/widgets/itemviews/stardelegate/stareditor.py index 5921b73be..820aba8bf 100644 --- a/examples/widgets/itemviews/stardelegate/stareditor.py +++ b/examples/widgets/itemviews/stardelegate/stareditor.py @@ -45,9 +45,10 @@ from PySide2.QtWidgets import (QWidget) from PySide2.QtGui import (QPainter) from PySide2.QtCore import Signal +from starrating import StarRating class StarEditor(QWidget): - """ The custome editor for editing StarRatings. """ + """ The custom editor for editing StarRatings. """ # A signal to tell the delegate when we've finished editing. editingFinished = Signal() @@ -60,6 +61,7 @@ class StarEditor(QWidget): self.setMouseTracking(True) self.setAutoFillBackground(True) + self.starRating = StarRating() def sizeHint(self): """ Tell the caller how big we are. """ diff --git a/examples/widgets/itemviews/stardelegate/starrating.py b/examples/widgets/itemviews/stardelegate/starrating.py index d056e4c64..d40b382f4 100644 --- a/examples/widgets/itemviews/stardelegate/starrating.py +++ b/examples/widgets/itemviews/stardelegate/starrating.py @@ -68,8 +68,7 @@ class StarRating(object): diamondPoints = [QPointF(0.4, 0.5), QPointF(0.5, 0.4), QPointF(0.6, 0.5), QPointF(0.5, 0.6), QPointF(0.4, 0.5)] - for point in diamondPoints: - self.diamondPolygon.append(point) + self.diamondPolygon.append(diamondPoints) def sizeHint(self): """ Tell the caller how big we are. """ diff --git a/examples/widgets/layouts/basiclayouts.py b/examples/widgets/layouts/basiclayouts.py index e925630cb..565ce728d 100644 --- a/examples/widgets/layouts/basiclayouts.py +++ b/examples/widgets/layouts/basiclayouts.py @@ -42,7 +42,7 @@ """PySide2 port of the widgets/layouts/basiclayout example from Qt v5.x""" -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtWidgets class Dialog(QtWidgets.QDialog): diff --git a/examples/widgets/layouts/flowlayout.py b/examples/widgets/layouts/flowlayout.py index 57e541555..f63fd5549 100644 --- a/examples/widgets/layouts/flowlayout.py +++ b/examples/widgets/layouts/flowlayout.py @@ -42,7 +42,7 @@ """PySide2 port of the widgets/layouts/flowlayout example from Qt v5.x""" -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets class Window(QtWidgets.QWidget): diff --git a/examples/widgets/layouts/layouts.pyproject b/examples/widgets/layouts/layouts.pyproject new file mode 100644 index 000000000..85eb22785 --- /dev/null +++ b/examples/widgets/layouts/layouts.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["basiclayouts.py", "dynamiclayouts.py", "flowlayout.py"] +} diff --git a/examples/widgets/mainwindows/application/application.py b/examples/widgets/mainwindows/application/application.py index 624fb47d5..8c4626f9b 100644 --- a/examples/widgets/mainwindows/application/application.py +++ b/examples/widgets/mainwindows/application/application.py @@ -147,7 +147,7 @@ class MainWindow(QtWidgets.QMainWindow): self.aboutQtAct = QtWidgets.QAction("About &Qt", self, statusTip="Show the Qt library's About box", - triggered=QtWidgets.qApp.aboutQt) + triggered=qApp.aboutQt) self.cutAct.setEnabled(False) self.copyAct.setEnabled(False) diff --git a/examples/widgets/mainwindows/application/application.pyproject b/examples/widgets/mainwindows/application/application.pyproject new file mode 100644 index 000000000..0e0413982 --- /dev/null +++ b/examples/widgets/mainwindows/application/application.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["application.qrc", "application.py", "application_rc.py"] +} diff --git a/examples/widgets/mainwindows/dockwidgets/dockwidgets.pyproject b/examples/widgets/mainwindows/dockwidgets/dockwidgets.pyproject new file mode 100644 index 000000000..2df11468e --- /dev/null +++ b/examples/widgets/mainwindows/dockwidgets/dockwidgets.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["dockwidgets.qrc", "dockwidgets.py", "dockwidgets_rc.py"] +} diff --git a/examples/widgets/mainwindows/mdi/mdi.pyproject b/examples/widgets/mainwindows/mdi/mdi.pyproject new file mode 100644 index 000000000..7df26fd77 --- /dev/null +++ b/examples/widgets/mainwindows/mdi/mdi.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["mdi_rc.py", "mdi.py", "mdi.qrc"] +} diff --git a/examples/widgets/painting/basicdrawing/basicdrawing.pyproject b/examples/widgets/painting/basicdrawing/basicdrawing.pyproject new file mode 100644 index 000000000..9ecbfadcf --- /dev/null +++ b/examples/widgets/painting/basicdrawing/basicdrawing.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["basicdrawing_rc.py", "basicdrawing.qrc", "basicdrawing.py"] +} diff --git a/examples/widgets/painting/painting.pyproject b/examples/widgets/painting/painting.pyproject new file mode 100644 index 000000000..ed24e12b0 --- /dev/null +++ b/examples/widgets/painting/painting.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["concentriccircles.py"] +} diff --git a/examples/widgets/richtext/richtext.pyproject b/examples/widgets/richtext/richtext.pyproject new file mode 100644 index 000000000..e91a98961 --- /dev/null +++ b/examples/widgets/richtext/richtext.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["syntaxhighlighter.py", "orderform.py"] +} diff --git a/examples/widgets/richtext/syntaxhighlighter.py b/examples/widgets/richtext/syntaxhighlighter.py index 5a5d7c8e0..82e4c79a1 100644 --- a/examples/widgets/richtext/syntaxhighlighter.py +++ b/examples/widgets/richtext/syntaxhighlighter.py @@ -102,14 +102,14 @@ class MainWindow(QtWidgets.QMainWindow): fileMenu.addAction("&New...", self.newFile, "Ctrl+N") fileMenu.addAction("&Open...", self.openFile, "Ctrl+O") - fileMenu.addAction("E&xit", QtWidgets.qApp.quit, "Ctrl+Q") + fileMenu.addAction("E&xit", qApp.quit, "Ctrl+Q") def setupHelpMenu(self): helpMenu = QtWidgets.QMenu("&Help", self) self.menuBar().addMenu(helpMenu) helpMenu.addAction("&About", self.about) - helpMenu.addAction("About &Qt", QtWidgets.qApp.aboutQt) + helpMenu.addAction("About &Qt", qApp.aboutQt) class Highlighter(QtGui.QSyntaxHighlighter): diff --git a/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.py b/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.py index a0f2e5937..55805e469 100644 --- a/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.py +++ b/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.py @@ -47,8 +47,8 @@ import re from PySide2.QtCore import (QFile, Qt, QTextStream) from PySide2.QtGui import (QColor, QFont, QKeySequence, QSyntaxHighlighter, QTextCharFormat) -from PySide2.QtWidgets import (QAction, qApp, QApplication, QFileDialog, QMainWindow, - QMenu, QMenuBar, QPlainTextEdit) +from PySide2.QtWidgets import (QApplication, QFileDialog, QMainWindow, + QPlainTextEdit) import syntaxhighlighter_rc diff --git a/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.pyproject b/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.pyproject new file mode 100644 index 000000000..e42b221a8 --- /dev/null +++ b/examples/widgets/richtext/syntaxhighlighter/syntaxhighlighter.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["syntaxhighlighter_rc.py", "syntaxhighlighter.py", + "syntaxhighlighter.qrc"] +} diff --git a/examples/widgets/richtext/textobject/textobject.pyproject b/examples/widgets/richtext/textobject/textobject.pyproject new file mode 100644 index 000000000..ed4135844 --- /dev/null +++ b/examples/widgets/richtext/textobject/textobject.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["textobject.py"] +} diff --git a/examples/widgets/state-machine/state-machine.pyproject b/examples/widgets/state-machine/state-machine.pyproject new file mode 100644 index 000000000..dafb204c8 --- /dev/null +++ b/examples/widgets/state-machine/state-machine.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["pingpong.py", "trafficlight.py", "twowaybutton.py", + "eventtrans.py", "rogue.py", "factstates.py"] +} diff --git a/examples/widgets/threads/thread_signals.py b/examples/widgets/threads/thread_signals.py new file mode 100644 index 000000000..d63040491 --- /dev/null +++ b/examples/widgets/threads/thread_signals.py @@ -0,0 +1,100 @@ + +############################################################################# +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +import sys +from PySide2.QtCore import QObject, QThread, Signal, Slot +from PySide2.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget + + +# Create a basic window with a layout and a button +class MainForm(QWidget): + def __init__(self): + QWidget.__init__(self) + self.setWindowTitle("My Form") + self.layout = QVBoxLayout() + self.button = QPushButton("Click me!") + self.button.clicked.connect(self.start_thread) + self.layout.addWidget(self.button) + self.setLayout(self.layout) + + # Instantiate and start a new thread + def start_thread(self): + instanced_thread = WorkerThread(self) + instanced_thread.start() + + # Create the Slots that will receive signals + @Slot(str) + def update_str_field(self, message): + print(message) + + @Slot(int) + def update_int_field(self, value): + print(value) + + +# Signals must inherit QObject +class MySignals(QObject): + signal_str = Signal(str) + signal_int = Signal(int) + + +# Create the Worker Thread +class WorkerThread(QThread): + def __init__(self, parent=None): + QThread.__init__(self, parent) + # Instantiate signals and connect signals to the slots + self.signals = MySignals() + self.signals.signal_str.connect(parent.update_str_field) + self.signals.signal_int.connect(parent.update_int_field) + + def run(self): + # Do something on the worker thread + a = 1 + 1 + # Emit signals whenever you want + self.signals.signal_int.emit(a) + self.signals.signal_str.emit("This text comes to Main thread from our Worker thread.") + + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = MainForm() + window.show() + sys.exit(app.exec_()) diff --git a/examples/widgets/tutorials/addressbook/addressbook.pyproject b/examples/widgets/tutorials/addressbook/addressbook.pyproject new file mode 100644 index 000000000..13d739e1b --- /dev/null +++ b/examples/widgets/tutorials/addressbook/addressbook.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["part3.py", "part1.py", "part5.py", "part2.py", + "part7.py", "part6.py", "part4.py"] +} diff --git a/examples/widgets/tutorials/addressbook/part1.py b/examples/widgets/tutorials/addressbook/part1.py index 6bdb97d2b..895873036 100644 --- a/examples/widgets/tutorials/addressbook/part1.py +++ b/examples/widgets/tutorials/addressbook/part1.py @@ -40,7 +40,7 @@ ## ############################################################################# -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets class AddressBook(QtWidgets.QWidget): diff --git a/examples/widgets/tutorials/addressbook/part2.py b/examples/widgets/tutorials/addressbook/part2.py index 772b4d463..6eac33bfc 100644 --- a/examples/widgets/tutorials/addressbook/part2.py +++ b/examples/widgets/tutorials/addressbook/part2.py @@ -40,7 +40,7 @@ ## ############################################################################# -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets class SortedDict(dict): diff --git a/examples/widgets/tutorials/addressbook/part3.py b/examples/widgets/tutorials/addressbook/part3.py index 835adb3c6..d425c11d9 100644 --- a/examples/widgets/tutorials/addressbook/part3.py +++ b/examples/widgets/tutorials/addressbook/part3.py @@ -40,7 +40,7 @@ ## ############################################################################# -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets class SortedDict(dict): diff --git a/examples/widgets/tutorials/addressbook/part4.py b/examples/widgets/tutorials/addressbook/part4.py index 93cd310be..e4b1d1630 100644 --- a/examples/widgets/tutorials/addressbook/part4.py +++ b/examples/widgets/tutorials/addressbook/part4.py @@ -40,7 +40,7 @@ ## ############################################################################# -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets class SortedDict(dict): diff --git a/examples/widgets/tutorials/addressbook/part5.py b/examples/widgets/tutorials/addressbook/part5.py index 9ea5312db..cb666ff9f 100644 --- a/examples/widgets/tutorials/addressbook/part5.py +++ b/examples/widgets/tutorials/addressbook/part5.py @@ -40,7 +40,7 @@ ## ############################################################################# -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets class SortedDict(dict): diff --git a/examples/widgets/tutorials/addressbook/part6.py b/examples/widgets/tutorials/addressbook/part6.py index 6f0550440..559cc355f 100644 --- a/examples/widgets/tutorials/addressbook/part6.py +++ b/examples/widgets/tutorials/addressbook/part6.py @@ -42,7 +42,7 @@ import pickle -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets class SortedDict(dict): diff --git a/examples/widgets/tutorials/addressbook/part7.py b/examples/widgets/tutorials/addressbook/part7.py index 8ad2e35c0..f32a2a6a8 100644 --- a/examples/widgets/tutorials/addressbook/part7.py +++ b/examples/widgets/tutorials/addressbook/part7.py @@ -42,7 +42,7 @@ import pickle -from PySide2 import QtCore, QtGui, QtWidgets +from PySide2 import QtCore, QtWidgets class SortedDict(dict): diff --git a/examples/widgets/widgets/tetrix.py b/examples/widgets/widgets/tetrix.py index f90793ca9..134eec4e4 100644 --- a/examples/widgets/widgets/tetrix.py +++ b/examples/widgets/widgets/tetrix.py @@ -77,7 +77,7 @@ class TetrixWindow(QtWidgets.QWidget): startButton.clicked.connect(self.board.start) pauseButton.clicked.connect(self.board.pause) - quitButton.clicked.connect(QtWidgets.qApp.quit) + quitButton.clicked.connect(qApp.quit) self.board.scoreChanged.connect(scoreLcd.display) self.board.levelChanged.connect(levelLcd.display) self.board.linesRemovedChanged.connect(linesLcd.display) diff --git a/examples/widgets/widgets/widgets.pyproject b/examples/widgets/widgets/widgets.pyproject new file mode 100644 index 000000000..b4e3ef67e --- /dev/null +++ b/examples/widgets/widgets/widgets.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["tetrix.py", "hellogl_openglwidget_legacy.py"] +} diff --git a/examples/xml/dombookmarks/dombookmarks.py b/examples/xml/dombookmarks/dombookmarks.py index 9a0168fde..20ec09e2d 100644 --- a/examples/xml/dombookmarks/dombookmarks.py +++ b/examples/xml/dombookmarks/dombookmarks.py @@ -112,7 +112,7 @@ class MainWindow(QtWidgets.QMainWindow): self.aboutAct = QtWidgets.QAction("&About", self, triggered=self.about) self.aboutQtAct = QtWidgets.QAction("About &Qt", self, - triggered=QtWidgets.qApp.aboutQt) + triggered=qApp.aboutQt) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") diff --git a/examples/xml/dombookmarks/dombookmarks.pyproject b/examples/xml/dombookmarks/dombookmarks.pyproject new file mode 100644 index 000000000..9a688558d --- /dev/null +++ b/examples/xml/dombookmarks/dombookmarks.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["jennifer.xbel", "frank.xbel", "dombookmarks.py"] +} diff --git a/examples/xmlpatterns/schema/schema.py b/examples/xmlpatterns/schema/schema.py index aef92011e..677b56498 100644 --- a/examples/xmlpatterns/schema/schema.py +++ b/examples/xmlpatterns/schema/schema.py @@ -200,7 +200,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_SchemaMainWindow): self.validate() def instanceSelected(self, index): - if index is -1: + if index == -1: return index += 2 * self.schemaSelection.currentIndex() diff --git a/examples/xmlpatterns/schema/schema.pyproject b/examples/xmlpatterns/schema/schema.pyproject new file mode 100644 index 000000000..697e58d70 --- /dev/null +++ b/examples/xmlpatterns/schema/schema.pyproject @@ -0,0 +1,4 @@ +{ + "files": ["schema.qrc", "schema.py", "schema.ui", "ui_schema.py", + "schema_rc.py"] +} diff --git a/examples/xmlpatterns/schema/ui_schema.py b/examples/xmlpatterns/schema/ui_schema.py index 28084624d..f9cc751eb 100644 --- a/examples/xmlpatterns/schema/ui_schema.py +++ b/examples/xmlpatterns/schema/ui_schema.py @@ -20,52 +20,52 @@ class Ui_SchemaMainWindow(object): SchemaMainWindow.resize(417, 594) self.centralwidget = QWidget(SchemaMainWindow) self.centralwidget.setObjectName(u"centralwidget") - self.gridLayout = QGridLayout(self.centralwidget); + self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout.setObjectName(u"gridLayout") self.schemaLabel = QLabel(self.centralwidget) self.schemaLabel.setObjectName(u"schemaLabel") - self.gridLayout.addWidget(self.schemaLabel, 0, 0, 1, 2); + self.gridLayout.addWidget(self.schemaLabel, 0, 0, 1, 2) self.schemaSelection = QComboBox(self.centralwidget) self.schemaSelection.setObjectName(u"schemaSelection") - self.gridLayout.addWidget(self.schemaSelection, 0, 2, 1, 2); + self.gridLayout.addWidget(self.schemaSelection, 0, 2, 1, 2) self.schemaView = QTextBrowser(self.centralwidget) self.schemaView.setObjectName(u"schemaView") - self.gridLayout.addWidget(self.schemaView, 1, 0, 1, 4); + self.gridLayout.addWidget(self.schemaView, 1, 0, 1, 4) self.instanceLabel = QLabel(self.centralwidget) self.instanceLabel.setObjectName(u"instanceLabel") - self.gridLayout.addWidget(self.instanceLabel, 2, 0, 1, 2); + self.gridLayout.addWidget(self.instanceLabel, 2, 0, 1, 2) self.instanceSelection = QComboBox(self.centralwidget) self.instanceSelection.setObjectName(u"instanceSelection") - self.gridLayout.addWidget(self.instanceSelection, 2, 2, 1, 2); + self.gridLayout.addWidget(self.instanceSelection, 2, 2, 1, 2) self.instanceEdit = QTextEdit(self.centralwidget) self.instanceEdit.setObjectName(u"instanceEdit") - self.gridLayout.addWidget(self.instanceEdit, 3, 0, 1, 4); + self.gridLayout.addWidget(self.instanceEdit, 3, 0, 1, 4) self.label = QLabel(self.centralwidget) self.label.setObjectName(u"label") - self.gridLayout.addWidget(self.label, 4, 0, 1, 1); + self.gridLayout.addWidget(self.label, 4, 0, 1, 1) self.validationStatus = QLabel(self.centralwidget) self.validationStatus.setObjectName(u"validationStatus") - self.gridLayout.addWidget(self.validationStatus, 4, 1, 1, 2); + self.gridLayout.addWidget(self.validationStatus, 4, 1, 1, 2) self.validateButton = QPushButton(self.centralwidget) self.validateButton.setObjectName(u"validateButton") - self.gridLayout.addWidget(self.validateButton, 4, 3, 1, 1); + self.gridLayout.addWidget(self.validateButton, 4, 3, 1, 1) SchemaMainWindow.setCentralWidget(self.centralwidget) self.statusbar = QStatusBar(SchemaMainWindow) |