簡介
在本文中,我們將演示如何繪製繪製一個三維柱狀圖,並結合使用GUI部件來控制柱狀圖的繪製引數。本文的示例演示了:
使用Q3DBars和一些部件建立應用程式;使用QBar3DSeries和QBarDataProxy將資料設定為圖形;使用部件控制元件調整一些圖形和序列的屬性;透過單擊軸標籤選擇行或列;負的數值如何影響圖形繪製。GraphModifer類定義GraphModifer類來設定圖形序列資料,座標軸, 相機和縮放參數等,並實現對圖形的控制方法。這些控制方法包括:
changeRange(self, range): 改變年度座標的範圍。changeStyle(self, style): 改變圖形的網格樣式。changePresetCamera(self): 改變預置相機。changeTheme(self, theme): 改變圖形主題樣式。changeLabelBackground(self): 啟用/禁用標籤的背景。changeSelectionMode(self, selectionMode):改變圖形的選擇模式。changeFont(self, font): 改變標籤字型。changeFontSize(self, fontsize): 改變標籤字型的尺寸。changeLabelRotation(self, rotation): 對座標軸進行旋轉。setAxisTitleVisibility(self, enabled):設定座標軸的標籤可見還是隱藏。setAxisTitleFixed(self, enabled): 是否固定座標軸的標籤。zoomToSelectedBar(self): 縮放選中的柱狀條。changeShadowQuality(self, quality):陰影質量控制。rotateX(self, rotation):繞X軸旋轉。rotateY(self, rotation):繞Y軸旋轉。使用部件控制圖形繪製根據GraphModifer實現的控制方法,在主介面中新增控制部件,實現對三維柱狀圖繪製的互動控制,這些互動功能包括:
旋轉圖形;修改標籤樣式;預設相機控制;背景是否可見;網格是否可見;控制柱狀條的陰影平滑度;是否顯示第二個柱狀條序列。座標軸標題是否可見及旋轉控制。控制顯示的資料範圍。控制柱狀圖的顯示主題方式。控制柱狀條的顯示風格。控制選擇方式。控制陰影質量。控制字型和字型大小。控制座標軸的旋轉。圖形縮放顯示。示例程式碼程式程式碼為GraphModifer類的實現和主程式控制兩部分,其程式碼分別如下:
GraphModifer類 實現部分(graphmodifier.py):
import mathfrom PyQt5.QtCore import QObject,QPropertyAnimation, pyqtSignal, QByteArrayfrom PyQt5.QtGui import QFont, QVector3Dfrom PyQt5.QtDataVisualization import (Q3DBars, QBar3DSeries, QBarDataProxy, QAbstract3DSeries, QValue3DAxis, QCategory3DAxis, QAbstract3DGraph, Q3DCamera, QBarDataItem) class GraphModifer(QObject): shadowQualityChanged = pyqtSignal(int) backgroundEnabledChanged = pyqtSignal(bool) gridEnabledChanged = pyqtSignal(bool) fontChanged = pyqtSignal(QFont) fontSizeChanged = pyqtSignal(int) def __init__(self, bargraph): super(GraphModifer, self).__init__() self.animationCameraX = QPropertyAnimation() self.animationCameraY = QPropertyAnimation() self.animationCameraZoom = QPropertyAnimation() self.animationCameraTarget = QPropertyAnimation() self.preset = Q3DCamera.CameraPresetFront self.graph = bargraph self.xRotation = 0.0 self.yRotation = 0.0 self.fontSize = 30 self.segments = 4 self.subSegments = 3 self.minVal = -20.0 self.maxVal = 20.0 self.temperatureAxis = QValue3DAxis() self.yearAxis = QCategory3DAxis() self.monthAxis = QCategory3DAxis() self.primarySeries = QBar3DSeries() self.secondarySeries = QBar3DSeries() self.barMesh = QAbstract3DSeries.MeshBevelBar self.smooth = False self.graph.setShadowQuality(QAbstract3DGraph.ShadowQualitySoftMedium) self.graph.activeTheme().setBackgroundEnabled(False) self.graph.activeTheme().setFont(QFont('Times New Roman', self.fontSize)) self.graph.activeTheme().setLabelBackgroundEnabled(True) self.graph.setMultiSeriesUniform(True) #self.months = ['January', 'February', 'March', 'April', 'May', 'June', # 'July', 'August', 'September', 'October', 'November', 'December'] self.months = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'] self.years = ['2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013'] self.temperatureAxis.setTitle('平均氣溫') self.temperatureAxis.setSegmentCount(self.segments) self.temperatureAxis.setSubSegmentCount(self.subSegments) self.temperatureAxis.setRange(self.minVal, self.maxVal) self.temperatureAxis.setLabelFormat('%.1f ' + '\u00b0'+'C') self.temperatureAxis.setLabelAutoRotation(30.0) self.temperatureAxis.setTitleVisible(True) self.yearAxis.setTitle('年') self.yearAxis.setLabelAutoRotation(30.0) self.yearAxis.setTitleVisible(True) self.monthAxis.setTitle('月') self.monthAxis.setLabelAutoRotation(30.0) self.monthAxis.setTitleVisible(True) self.graph.setValueAxis(self.temperatureAxis) self.graph.setRowAxis(self.yearAxis) self.graph.setColumnAxis(self.monthAxis) self.graph.setValueAxis(self.temperatureAxis) self.graph.setRowAxis(self.yearAxis) self.graph.setColumnAxis(self.monthAxis) self.primarySeries.setItemLabelFormat('Oulu - @colLabel @rowLabel: @valueLabel') self.primarySeries.setMesh(QAbstract3DSeries.MeshBevelBar) self.primarySeries.setMeshSmooth(False) self.secondarySeries.setItemLabelFormat('Helsinki - @colLabel @rowLabel: @valueLabel') self.secondarySeries.setMesh(QAbstract3DSeries.MeshBevelBar) self.secondarySeries.setMeshSmooth(False) self.secondarySeries.setVisible(False) self.graph.addSeries(self.primarySeries) self.graph.addSeries(self.secondarySeries) self.changePresetCamera() self.resetTemperatureData() # 設定屬性動畫以縮放到所選的欄 camera = self.graph.scene().activeCamera() self.defaultAngleX = camera.xRotation() self.defaultAngleY = camera.yRotation() self.defaultZoom = camera.zoomLevel() self.defaultTarget = camera.target() self.animationCameraX.setTargetObject(camera) self.animationCameraY.setTargetObject(camera) self.animationCameraZoom.setTargetObject(camera) self.animationCameraTarget.setTargetObject(camera) self.animationCameraX.setPropertyName(bytes('xRotation', 'ascii')) self.animationCameraY.setPropertyName(bytes('yRotation', 'ascii')) self.animationCameraZoom.setPropertyName(bytes('zoomLevel', 'ascii')) self.animationCameraTarget.setPropertyName(bytes('target', 'ascii')) duration = 1700 self.animationCameraX.setDuration(duration) self.animationCameraY.setDuration(duration) self.animationCameraZoom.setDuration(duration) self.animationCameraTarget.setDuration(duration) zoomOutFraction = 0.3 self.animationCameraX.setKeyValueAt(zoomOutFraction, 0.0) self.animationCameraY.setKeyValueAt(zoomOutFraction, 90.0) self.animationCameraZoom.setKeyValueAt(zoomOutFraction, 50.0) self.animationCameraTarget.setKeyValueAt(zoomOutFraction, QVector3D(0.0, 0.0, 0.0)) def resetTemperatureData(self): tempOulu = [ [-6.7, -11.7, -9.7, 3.3, 9.2, 14.0, 16.3, 17.8, 10.2, 2.1, -2.6, -0.3], # 2006 [-6.8, -13.3, 0.2, 1.5, 7.9, 13.4, 16.1, 15.5, 8.2, 5.4, -2.6, -0.8], # 2007 [-4.2, -4.0, -4.6, 1.9, 7.3, 12.5, 15.0, 12.8, 7.6, 5.1, -0.9, -1.3], # 2008 [-7.8, -8.8, -4.2, 0.7, 9.3, 13.2, 15.8, 15.5, 11.2, 0.6, 0.7, -8.4], # 2009 [-14.4, -12.1, -7.0, 2.3, 11.0, 12.6, 18.8, 13.8, 9.4, 3.9, -5.6, -13.0], # 2010 [-9.0, -15.2, -3.8, 2.6, 8.3, 15.9, 18.6, 14.9, 11.1, 5.3, 1.8, -0.2], # 2011 [-8.7, -11.3, -2.3, 0.4, 7.5, 12.2, 16.4, 14.1, 9.2, 3.1, 0.3, -12.1], # 2012 [-7.9, -5.3, -9.1, 0.8, 11.6, 16.6, 15.9, 15.5, 11.2, 4.0, 0.1, -1.9] # 2013 ] tempHelsinki = [ [-3.7, -7.8, -5.4, 3.4, 10.7, 15.4, 18.6, 18.7, 14.3, 8.5, 2.9, 4.1], # 2006 [-1.2, -7.5, 3.1, 5.5, 10.3, 15.9, 17.4, 17.9, 11.2, 7.3, 1.1, 0.5], # 2007 [-0.6, 1.2, 0.2, 6.3, 10.2, 13.8, 18.1, 15.1, 10.1, 9.4, 2.5, 0.4], # 2008 [-2.9, -3.5, -0.9, 4.7, 10.9, 14.0, 17.4, 16.8, 13.2, 4.1, 2.6, -2.3], # 2009 [-10.2, -8.0, -1.9, 6.6, 11.3, 14.5, 21.0, 18.8, 12.6, 6.1, -0.5, -7.3], # 2010 [-4.4, -9.1, -2.0, 5.5, 9.9, 15.6, 20.8, 17.8, 13.4, 8.9, 3.6, 1.5], # 2011 [-3.5, -3.2, -0.7, 4.0, 11.1, 13.4, 17.3, 15.8, 13.1, 6.4, 4.1, -5.1], # 2012 [-4.8, -1.8, -5.0, 2.9, 12.8, 17.2, 18.0, 17.1, 12.5, 7.5, 4.5, 2.3] # 2013 ] #建立資料列表 dataSet = [] dataSet2 = [] for year in range(len(self.years)): #生成一個數據行 dataRow = [None] * len(self.months) dataRow2 = [None] * len(self.months) for month in range(len(self.months)): #新增一個數據行 dataRow[month] = QBarDataItem(tempOulu[year][month]) dataRow2[month] = QBarDataItem(tempHelsinki[year][month]) #向集合中新增行 dataSet.append(dataRow) dataSet2.append(dataRow2) #將資料新增到代理中 self.primarySeries.dataProxy().resetArray(dataSet, self.years, self.months) self.secondarySeries.dataProxy().resetArray(dataSet2, self.years, self.months) def changeRange(self, range): if range >= len(self.years): self.yearAxis.setRange(0, len(self.years) - 1) else: self.yearAxis.setRange(range, range) def changeStyle(self, style): combox = self.sender() if combox: self.barMesh = QAbstract3DSeries.Mesh(int(combox.itemData(style))) self.primarySeries.setMesh(self.barMesh) self.secondarySeries.setMesh(self.barMesh) def changePresetCamera(self): self.animationCameraX.stop() self.animationCameraY.stop() self.animationCameraZoom.stop() self.animationCameraTarget.stop() #如果動畫改變了相機的目標,則恢復回去 self.graph.scene().activeCamera().setTarget(QVector3D(0.0, 0.0, 0.0)) self.graph.scene().activeCamera().setCameraPreset(self.preset) self.preset += 1 if self.preset > Q3DCamera.CameraPresetDirectlyBelow: self.preset = Q3DCamera.CameraPresetFrontLow def changeTheme(self, theme): currentTheme = self.graph.activeTheme() currentTheme.setType(theme) self.backgroundEnabledChanged.emit(currentTheme.isBackgroundEnabled()) self.gridEnabledChanged.emit(currentTheme.isGridEnabled()) self.fontChanged.emit(currentTheme.font()) self.fontSizeChanged.emit(currentTheme.font().pointSize()) def changeLabelBackground(self): self.graph.activeTheme().setLabelBackgroundEnabled(not self.graph.activeTheme().isLabelBackgroundEnabled()) def changeSelectionMode(self, selectionMode): comboBox = self.sender() if comboBox: flags = comboBox.itemData(selectionMode) self.graph.setSelectionMode(QAbstract3DGraph.SelectionFlags(flags)) def changeFont(self, font): self.graph.activeTheme().setFont(font) def changeFontSize(self, fontsize): self.fontSize = fontsize font = self.graph.activeTheme().font() font.setPointSize(fontsize) self.graph.activeTheme().setFont(font) def shadowQualityUpdatedByVisual(self, sq): self.shadowQualityChanged.emit(sq) def changeLabelRotation(self, rotation): self.temperatureAxis.setLabelAutoRotation(rotation) self.monthAxis.setLabelAutoRotation(rotation) self.yearAxis.setLabelAutoRotation(rotation) def setAxisTitleVisibility(self, enabled): self.temperatureAxis.setTitleVisible(enabled) self.monthAxis.setTitleVisible(enabled) self.yearAxis.setTitleVisible(enabled) def setAxisTitleFixed(self, enabled): self.temperatureAxis.setTitleFixed(enabled) self.monthAxis.setTitleFixed(enabled) self.yearAxis.setTitleFixed(enabled) def zoomToSelectedBar(self): self.animationCameraX.stop() self.animationCameraY.stop() self.animationCameraZoom.stop() self.animationCameraTarget.stop() camera = self.graph.scene().activeCamera() currentX = camera.xRotation() currentY = camera.yRotation() currentZoom = camera.zoomLevel() currentTarget = camera.target() self.animationCameraX.setStartValue(currentX) self.animationCameraY.setStartValue(currentY) self.animationCameraZoom.setStartValue(currentZoom) self.animationCameraTarget.setStartValue(currentTarget) if self.graph.selectedSeries(): selectedBar = self.graph.selectedSeries().selectedBar() else: selectedBar = QBar3DSeries.invalidSelectionPosition() if selectedBar != QBar3DSeries.invalidSelectionPosition(): #根據座標軸的範圍對選中的柱形條做歸一化處理以確定目標座標 xMin = self.graph.columnAxis().min() xRange = self.graph.columnAxis().max() - xMin zMin = self.graph.rowAxis().min() zRange = self.graph.rowAxis().max() - zMin endTarget = QVector3D() endTarget.setX((selectedBar.y() - xMin) / xRange * 2.0 - 1.0) endTarget.setZ((selectedBar.x() - zMin) / zRange * 2.0 - 1.0) #旋轉像機,使其始終近似地指向圖形中心 endAngleX = 90.0 - math.atan2(endTarget.z(), endTarget.x()) * 180.0 / math.pi if endTarget.x() > 0.0: endAngleX -= 180.0 barValue = self.graph.selectedSeries().dataProxy().itemAt(selectedBar.x(), selectedBar.y()).value() if barValue >= 0.0: endAngleY = 30.0 else: endAngleY = -30.0 if self.graph.valueAxis().reversed(): endAngleY *= 1.0 self.animationCameraX.setEndValue(endAngleX) self.animationCameraY.setEndValue(endAngleY) self.animationCameraZoom.setEndValue(250.0) self.animationCameraTarget.setEndValue(endTarget) else: #未選擇柱狀條,設定為預設值 self.animationCameraX.setEndValue(self.defaultAngleX) self.animationCameraY.setEndValue(self.defaultAngleY) self.animationCameraZoom.setEndValue(self.defaultZoom) self.animationCameraTarget.setEndValue(self.defaultTarget) self.animationCameraX.start() self.animationCameraY.start() self.animationCameraZoom.start() self.animationCameraTarget.start() def changeShadowQuality(self, quality): sq = QAbstract3DGraph.ShadowQuality(quality) self.graph.setShadowQuality(sq) self.shadowQualityChanged.emit(quality) def rotateX(self, rotation): self.xRotation = rotation self.graph.scene().activeCamera().setCameraPosition(self.xRotation, self.yRotation) def rotateY(self, rotation): self.yRotation = rotation self.graph.scene().activeCamera().setCameraPosition(self.xRotation, self.yRotation) def setBackgroundEnabled(self, enabled): self.graph.activeTheme().setBackgroundEnabled(enabled) def setGridEnabled(self, enabled): self.graph.activeTheme().setGridEnabled(enabled) def setSmoothBars(self, smooth): self.primarySeries.setMeshSmooth(smooth) self.secondarySeries.setMeshSmooth(smooth) def setSeriesVisibility(self, enabled:int): self.secondarySeries.setVisible(enabled) def setReverseValueAxis(self, enabled): self.graph.valueAxis().setReversed(enabled) def setReflection(self, enabled): self.graph.setReflection(enabled)
主程式部分:
import sysfrom PyQt5 import QtCore, QtGui, QtWidgetsfrom PyQt5.QtCore import Qt, QSizefrom PyQt5.QtGui import QFontfrom PyQt5.QtWidgets import (QApplication, QWidget, QMessageBox, QSizePolicy, QHBoxLayout, QVBoxLayout, QComboBox, QPushButton, QCheckBox, QSlider, QFontComboBox, QLabel)from PyQt5.QtDataVisualization import (Q3DBars, QAbstract3DSeries, QAbstract3DGraph) from graphmodifier import GraphModifer class DemoWidget(QWidget): def __init__(self, parent=None): super(DemoWidget, self).__init__(parent) # 設定視窗標題 self.setWindowTitle('實戰 Qt for Python: 城市平均溫度視覺化演示') # 設定視窗大小 self.resize(640, 480) self.initUi() def initUi(self): widgetgraph = Q3DBars() container = QWidget.createWindowContainer(widgetgraph) if not widgetgraph.hasContext(): msgBox = QMessageBox() msgBox.setText('不能初始化OpenGL上下文') msgBox.exec() return; screenSize = widgetgraph.screen().size() container.setMinimumSize(QSize(int(screenSize.width() / 2.0), int(screenSize.height() / 1.5))) container.setMaximumSize(screenSize) container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) container.setFocusPolicy(Qt.StrongFocus) hLayout = QHBoxLayout() vLayout = QVBoxLayout() hLayout.addWidget(container, 1) #左邊繪圖部分 hLayout.addLayout(vLayout) #右邊控制部分 #圖表主題控制 themeList = QComboBox(self) themeList.addItem('Qt') themeList.addItem('Primary Colors') themeList.addItem('Digia') themeList.addItem('Stone Moss') themeList.addItem('Army Blue') themeList.addItem('Retro') themeList.addItem('Ebony') themeList.addItem('Isabelle') themeList.setCurrentIndex(0) labelButton = QPushButton(self) labelButton.setText('改變標籤樣式') smoothCheckBox = QCheckBox(self) smoothCheckBox.setText('平滑柱狀條') smoothCheckBox.setChecked(False) #柱狀條樣式 barStyleList = QComboBox(self) barStyleList.addItem('Bar', int(QAbstract3DSeries.MeshBar)) barStyleList.addItem('Pyramid', int(QAbstract3DSeries.MeshPyramid)) barStyleList.addItem('Cone', int(QAbstract3DSeries.MeshCone)) barStyleList.addItem('Cylinder', int(QAbstract3DSeries.MeshCylinder)) barStyleList.addItem('Bevel bar', int(QAbstract3DSeries.MeshBevelBar)) barStyleList.addItem('Sphere', int(QAbstract3DSeries.MeshSphere)) barStyleList.setCurrentIndex(4) cameraButton = QPushButton(self) cameraButton.setText('改變相機設定') zoomToSelectedButton = QPushButton(self) zoomToSelectedButton.setText('縮放選擇的柱狀條') #選擇模式列表 selectionModeList = QComboBox(self) selectionModeList.addItem('None', int(QAbstract3DGraph.SelectionNone)) selectionModeList.addItem('Bar', int(QAbstract3DGraph.SelectionItem)) selectionModeList.addItem('Row', int(QAbstract3DGraph.SelectionRow)) selectionModeList.addItem('Bar and Row', int(QAbstract3DGraph.SelectionItemAndRow)) selectionModeList.addItem('Column', int(QAbstract3DGraph.SelectionColumn)) selectionModeList.addItem('Bar and Column', int(QAbstract3DGraph.SelectionItemAndColumn)) selectionModeList.addItem('Row and Column', int(QAbstract3DGraph.SelectionRowAndColumn)) selectionModeList.addItem('Bar, Row and Column', int(QAbstract3DGraph.SelectionItemRowAndColumn)) selectionModeList.addItem('Slice into Row', int(QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionRow)) selectionModeList.addItem('"Slice into Row and Item', int(QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionItemAndRow)) selectionModeList.addItem('Slice into Column', int(QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionColumn)) selectionModeList.addItem('Slice into Column and Item', int(QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionItemAndColumn)) selectionModeList.addItem('Multi: Bar, Row, Col', int(QAbstract3DGraph.SelectionItemRowAndColumn | QAbstract3DGraph.SelectionMultiSeries)) selectionModeList.addItem('Multi, Slice: Row, Item', int(QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionItemAndRow | QAbstract3DGraph.SelectionMultiSeries)) selectionModeList.addItem('Multi, Slice: Col, Item', int(QAbstract3DGraph.SelectionSlice | QAbstract3DGraph.SelectionItemAndColumn | QAbstract3DGraph.SelectionMultiSeries)) selectionModeList.setCurrentIndex(1) backgroundCheckBox = QCheckBox(self) backgroundCheckBox.setText('顯示背景') backgroundCheckBox.setChecked(False) gridCheckBox = QCheckBox(self) gridCheckBox.setText('顯示網格') gridCheckBox.setChecked(True) seriesCheckBox = QCheckBox(self) seriesCheckBox.setText('顯示第二個序列') seriesCheckBox.setChecked(False) reverseValueAxisCheckBox = QCheckBox(self) reverseValueAxisCheckBox.setText('翻轉數值座標軸') reverseValueAxisCheckBox.setChecked(False) reflectionCheckBox = QCheckBox(self) reflectionCheckBox.setText('顯示反射') reflectionCheckBox.setChecked(False) #旋轉 rotationSliderX = QSlider(Qt.Horizontal, self) rotationSliderX.setTickInterval(30) rotationSliderX.setTickPosition(QSlider.TicksBelow) rotationSliderX.setMinimum(-180) rotationSliderX.setValue(0) rotationSliderX.setMaximum(180) rotationSliderY = QSlider(Qt.Horizontal, self) rotationSliderY.setTickInterval(15) rotationSliderY.setTickPosition(QSlider.TicksAbove) rotationSliderY.setMinimum(-90) rotationSliderY.setValue(0) rotationSliderY.setMaximum(90) fontSizeSlider = QSlider(Qt.Horizontal, self) fontSizeSlider.setTickInterval(10) fontSizeSlider.setTickPosition(QSlider.TicksBelow) fontSizeSlider.setMinimum(1) fontSizeSlider.setValue(30) fontSizeSlider.setMaximum(100) fontList = QFontComboBox(self) fontList.setCurrentFont(QFont('Times New Roman')) #陰影質量 shadowQuality = QComboBox(self) shadowQuality.addItem('None') shadowQuality.addItem('Low') shadowQuality.addItem('Medium') shadowQuality.addItem('High') shadowQuality.addItem('Low Soft') shadowQuality.addItem('Medium Soft') shadowQuality.addItem('High Soft') shadowQuality.setCurrentIndex(5) #範圍選擇 rangeList = QComboBox(self) rangeList.addItem('2006') rangeList.addItem('2007') rangeList.addItem('2008') rangeList.addItem('2009') rangeList.addItem('2010') rangeList.addItem('2011') rangeList.addItem('2012') rangeList.addItem('2013') rangeList.addItem('All') rangeList.setCurrentIndex(8) axisTitlesVisibleCB = QCheckBox(self) axisTitlesVisibleCB.setText('座標軸標籤可見') axisTitlesVisibleCB.setChecked(True) axisTitlesFixedCB = QCheckBox(self) axisTitlesFixedCB.setText('座標軸標籤固定') axisTitlesFixedCB.setChecked(True) axisLabelRotationSlider = QSlider(Qt.Horizontal, self) axisLabelRotationSlider.setTickInterval(10) axisLabelRotationSlider.setTickPosition(QSlider.TicksBelow) axisLabelRotationSlider.setMinimum(0) axisLabelRotationSlider.setValue(30) axisLabelRotationSlider.setMaximum(90) vLayout.addWidget(QLabel('水平旋轉')) vLayout.addWidget(rotationSliderX, 0, Qt.AlignTop) vLayout.addWidget(QLabel('垂直旋轉')) vLayout.addWidget(rotationSliderY, 0, Qt.AlignTop) vLayout.addWidget(labelButton, 0, Qt.AlignTop) vLayout.addWidget(cameraButton, 0, Qt.AlignTop) vLayout.addWidget(zoomToSelectedButton, 0, Qt.AlignTop) vLayout.addWidget(backgroundCheckBox) vLayout.addWidget(gridCheckBox) vLayout.addWidget(smoothCheckBox) vLayout.addWidget(reflectionCheckBox) vLayout.addWidget(seriesCheckBox) vLayout.addWidget(reverseValueAxisCheckBox) vLayout.addWidget(axisTitlesVisibleCB) vLayout.addWidget(axisTitlesFixedCB) vLayout.addWidget(QLabel('顯示年份')) vLayout.addWidget(rangeList) vLayout.addWidget(QLabel('改變柱狀條樣式')) vLayout.addWidget(barStyleList) vLayout.addWidget(QLabel('改變選擇模式')) vLayout.addWidget(selectionModeList) vLayout.addWidget(QLabel('改變主題')) vLayout.addWidget(themeList) vLayout.addWidget(QLabel('調整陰影質量')) vLayout.addWidget(shadowQuality) vLayout.addWidget(QLabel('改變字型')) vLayout.addWidget(fontList) vLayout.addWidget(QLabel('調整字型尺寸')) vLayout.addWidget(fontSizeSlider) vLayout.addWidget(QLabel('旋轉座標軸標籤')) vLayout.addWidget(axisLabelRotationSlider, 1, Qt.AlignTop) self.modifier = GraphModifer(widgetgraph) rotationSliderX.valueChanged.connect(self.modifier.rotateX) rotationSliderY.valueChanged.connect(self.modifier.rotateY) labelButton.clicked.connect(self.modifier.changeLabelBackground) cameraButton.clicked.connect(self.modifier.changePresetCamera) zoomToSelectedButton.clicked.connect(self.modifier.zoomToSelectedBar) backgroundCheckBox.stateChanged.connect(self.modifier.setBackgroundEnabled) gridCheckBox.stateChanged.connect(self.modifier.setGridEnabled) smoothCheckBox.stateChanged.connect(self.modifier.setSmoothBars) seriesCheckBox.stateChanged.connect(self.modifier.setSeriesVisibility) reverseValueAxisCheckBox.stateChanged.connect(self.modifier.setReverseValueAxis) reflectionCheckBox.stateChanged.connect(self.modifier.setReflection) self.modifier.backgroundEnabledChanged.connect(backgroundCheckBox.setChecked) self.modifier.gridEnabledChanged.connect(gridCheckBox.setChecked) rangeList.currentIndexChanged.connect(self.modifier.changeRange) barStyleList.currentIndexChanged.connect(self.modifier.changeStyle) selectionModeList.currentIndexChanged.connect(self.modifier.changeSelectionMode) themeList.currentIndexChanged.connect(self.modifier.changeTheme) shadowQuality.currentIndexChanged.connect(self.modifier.changeShadowQuality) self.modifier.shadowQualityChanged.connect(shadowQuality.setCurrentIndex) widgetgraph.shadowQualityChanged.connect(self.modifier.shadowQualityUpdatedByVisual) fontSizeSlider.valueChanged.connect(self.modifier.changeFontSize) fontList.currentFontChanged.connect(self.modifier.changeFont) self.modifier.fontSizeChanged.connect(fontSizeSlider.setValue) self.modifier.fontChanged.connect(fontList.setCurrentFont) axisTitlesVisibleCB.stateChanged.connect(self.modifier.setAxisTitleVisibility) axisTitlesFixedCB.stateChanged.connect(self.modifier.setAxisTitleFixed) axisLabelRotationSlider.valueChanged.connect(self.modifier.changeLabelRotation) self.setLayout(hLayout) if __name__ == '__main__': app = QApplication(sys.argv) window = DemoWidget() window.show() sys.exit(app.exec())
最終執行結果如下圖:
最新評論