建议先看这个,再来呀:http://t.csdn.cn/Oatgb
里面包含的知识点这里不重复讲了
在PyQt中建立了如图窗口:
对于窗口的ui文件,我放在百度网盘中:
链接:https://pan.baidu.com/s/1nXqx0xbKHVkbyrtr6gBvyw
提取码:cyss
还有对应的图标文件:
链接:https://pan.baidu.com/s/1LHvmRr9QFIlwCiRWhP3cUw
提取码:cyss
1.创建下图所示的数据表:
2.新建appMain文件,用于显示主窗体:
import sys from PyQt6.QtWidgets import QApplication from myMainWindow import QmyMainWindow app=QApplication(sys.argv)#构造GUI应用程序 mainform=QmyMainWindow() #创建主窗体 mainform.show() #显示主窗体 sys.exit(app.exec())
3.新建myChartView文件:
QChart 和 QChartView 是基于 Graphics View 结构的绘图类。要对一个 QChart 图表进行鼠标和按键操作,需要在 QChartView 类里对鼠标和按键事件进行处理,这就需要自定义一个从QChartView 继承的类。
QmyChartView 类是从 QChartView 类继承的用作图表的视图组件,实现了鼠标、按键事件的处理,能够在鼠标移动时发射信号 mouseMove(),鼠标框选中一个矩形区域时放大显示此区域,通过按键进行图表缩放和移动操作。
from PyQt6.QtWidgets import QGraphicsView from PyQt6.QtCore import pyqtSignal, QPoint, Qt, QRectF from PyQt6.QtCharts import QChartView class QmyChartView(QChartView): mouseMove=pyqtSignal(QPoint)##鼠标移动 def __init__(self, parent=None): super().__init__(parent) self.setDragMode(QGraphicsView.DragMode.RubberBandDrag) self.__beginPoint=QPoint() self.__endPoint=QPoint() def mousePressEvent(self, event):##鼠标单击 if event.button()==Qt.MouseButton.LeftButton: self.__beginPoint=event.pos() super().mousePressEvent(event) def mouseMoveEvent(self, event):##鼠标移动 point=event.pos() self.mouseMove.emit(point) super().mouseMoveEvent(event) def mouseReleaseEvent(self, event):##鼠标框选放大,右键恢复 if event.button()==Qt.MouseButton.LeftButton: self.__endPoint=event.pos() rectF=QRectF() rectF.setTopLeft(self.__beginPoint.toPointF()) rectF.setBottomRight(self.__endPoint.toPointF()) self.chart().zoomIn(rectF) elif event.button()==Qt.MouseButton.RightButton: self.chart().zoomReset()#鼠标右键释放,resetZoon
(1)mousePressEvent:在鼠标左键或右键按下时触发的事件函数。self.__beginPoint 记录左键按下时,鼠标在视图组件中的位置。
(2)mouseMoveEvent: 鼠标在图表上移动时触发的事件函数,通过 event.pos()获取鼠标在视图组件中的坐标 point,然后发射信号 mouseMove(point)。在使用 QmyChartView 类组件的主窗口里,可以定义槽函数与此信号关联,通过传递的参数将视图坐标变换为图表的坐 标,从而实现鼠标光标处的坐标数值实时显示。
(3)mouseReleaseEvent:在鼠标左键或右键释放时触发的事件函数。若是鼠标左键释放,则用 self.__endPoint 记录鼠标位置坐标。self.__beginPoint 和 self.__endPoint 就定义了鼠标框选的矩形区域,用关联的 QChart 组件的 zoomIn(QRectF)函数对这个矩形区域进行放大。注意这里rectF的类型是QRectF,所以需要用toPointF将__beginPoint和__endPoint从QPoint类型转换为 QPointF 类型。
def keyPressEvent(self, event): key=event.key() if key ==Qt.Key.Key_Plus:# + self.chart().zoom(1.2) elif key ==Qt.Key.Key_Minus:# - self.chart().zoom(0.8) elif key==Qt.Key.Key_Left: #向左 self.chart().scroll(10, 0) elif key ==Qt.Key.Key_Right:#向右 self.chart().scroll(-10, 0) elif key==Qt.Key.Key_Up:#向上 self.chart().scroll(0, -10) elif key==Qt.Key.Key_Down:#向下 self.chart(0, 10) elif key==Qt.Key.Key_PageUp:#pageup self.chart().scroll(0, -50) elif key==Qt.Key.Key_PageDown:#pagedown self.chart().scroll(0, 50) elif key ==Qt.Key.Key_Home:#home self.chart().zoomReset() super().mouseReleaseEvent(event)
keyPressEvent 是键盘按键按下时触发的事件函数,从 event.key()可以获得按下按键的名称,判断按键然后做出缩放、移动等动作。
4.myMainWindow文件:
import sys from PyQt6.QtWidgets import QApplication,QMainWindow, QMessageBox from PyQt6.QtCore import pyqtSlot, Qt from PyQt6.QtSql import QSqlDatabase, QSqlQuery from PyQt6.QtGui import QStandardItemModel, QStandardItem, QPen, QPainter from PyQt6.QtCharts import (QChart, QBarSet, QBarSeries, QHorizontalBarSeries, QBarCategoryAxis, QValueAxis, QLineSeries, QAbstractBarSeries, QStackedBarSeries, QHorizontalStackedBarSeries , QPercentBarSeries, QHorizontalPercentBarSeries , QPieSeries) from Ui_MainWindow import Ui_MainWindow class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent)#调用父类构造函数,创建窗体 self.ui=Ui_MainWindow()#创建UI对象 self.ui.setupUi(self)#构造UI界面 self.setWindowTitle("三国志") self.ui.tableView.setAlternatingRowColors(True) self.ui.treeWidget.setAlternatingRowColors(True) self.setStyleSheet("QTreeWidget,QTableView{" "alternate-background-color:rgb(170,241,190)}") self.dataModel=QStandardItemModel(self)#数据模型 self.ui.tableView.setModel(self.dataModel)#设置数据模型 self.__openDB()#打开数据库 self.__generateData()#初始化数据 self.__surveyData()#数据统计 self.__iniBarChart()#柱状图初始化 self.__iniStackedBar()#堆叠状图初始化 self.__iniPercentBar()#百分比柱状图初始化 self.__iniPieChart()#饼图初始化 ##=====page 1.柱状图========= @pyqtSlot() def __iniBarChart(self): chart =QChart() chart.setTitle("Barchart 演示") chart.setAnimationOptions(QChart.AnimationOption.SeriesAnimations) self.ui.chartViewBar.setChart(chart)#为ChartView设置chart self.ui.chartViewBar.setRenderHint(QPainter.RenderHint.Antialiasing)#反走样 self.ui.chartViewBar.setCursor(Qt.CursorShape.CrossCursor)#设置鼠标指针为十字星 ##绘制柱状图,或水平柱状图 def draw_barChart(self, isVertical=True): chart = self.ui.chartViewBar.chart() chart.removeAllSeries() #删除所有序列 for axis in chart.axes(): chart.removeAxis(axis) #删除坐标轴 if isVertical: chart.setTitle("Barchart 演示") chart.legend().setAlignment(Qt.AlignmentFlag.AlignBottom) else: chart.setTitle("Horizontal Barchart 演示") chart.legend().setAlignment(Qt.AlignmentFlag.AlignRight) setTongshuai = QBarSet("统帅") setWuli = QBarSet("武力") setZhili=QBarSet("智力") setZhengzhi=QBarSet("政治") setMeili = QBarSet("魅力") seriesLine = QLineSeries() seriesLine.setName("平均分") pen=QPen(Qt.GlobalColor.red) pen.setWidth(2) seriesLine.setPen(pen) seriesLine.setPointLabelsVisible(True) if isVertical: seriesLine.setPointLabelsFormat("@yPoint") else: seriesLine.setPointLabelsFormat("@xPoint") font=seriesLine.pointLabelsFont() font.setPointSize(10) font.setBold(True) seriesLine.setPointLabelsFont(font) stud_Count=self.dataModel.rowCount() nameList=[]#学生姓名列表,用于QBarCategoryAxis类坐标轴 for i in range(stud_Count): #从数据模型中获取数据 item=self.dataModel.item(i, 0)#第0列姓名 nameList.append(item.text())#姓名,用作坐标轴标签 item=self.dataModel.item(i, 1)#第一列统帅 setTongshuai.append(float(item.text())) item=self.dataModel.item(i, 2)#第二列武力 setWuli.append(float(item.text())) item=self.dataModel.item(i, 3)#第三列智力 setZhili.append(float(item.text())) item=self.dataModel.item(i, 4)#第四列政治 setZhengzhi.append(float(item.text())) item=self.dataModel.item(i, 5)#第五列魅力 setMeili.append(float(item.text())) item=self.dataModel.item(i, 6) if isVertical: seriesLine.append(i, float(item.text()))#平均分,用于柱状图 else: seriesLine.append(float(item.text()), i)#平均分,用于水平柱状图 #创建一个序列QBarSeries,并添加数据集 if isVertical: seriesBar =QBarSeries()#柱状图 else: seriesBar=QHorizontalBarSeries()#水平柱状图 seriesBar.append(setTongshuai)#添加数据集 seriesBar.append(setWuli) seriesBar.append(setZhili) seriesBar.append(setZhengzhi) seriesBar.append(setMeili)#数据点标签可见 seriesBar.setLabelsVisible(True)#数据点标签可见 seriesBar.setLabelsFormat("@value")#显示数值标签 seriesBar.setLabelsPosition(QAbstractBarSeries.LabelsPosition.LabelsCenter)#数据标签显示位置 seriesBar.hovered.connect(self.do_barSeries_Hovered)#hovered信号 seriesBar.clicked.connect(self.do_barSeries_Clicked)#clicked信号 chart.addSeries(seriesBar)#添加柱状图序列 chart.addSeries(seriesLine)#添加折线图序列 ##学生姓名坐标轴 axisStud=QBarCategoryAxis() axisStud.append(nameList)#添加横坐标文字列表 axisStud.setRange(nameList[0], nameList[stud_Count-1])#坐标轴范围 #数值型坐标轴 axisValue=QValueAxis() axisValue.setRange(0, 100) axisValue.setTitleText("分数") axisValue.setTickCount(6) #刻度线数量 axisValue.applyNiceNumbers() #让刻度线更好看 if isVertical: chart.addAxis(axisStud, Qt.AlignmentFlag.AlignBottom) seriesBar.attachAxis(axisStud) seriesLine.attachAxis(axisStud) chart.addAxis(axisValue, Qt.AlignmentFlag.AlignLeft) seriesBar.attachAxis(axisValue) seriesLine.attachAxis(axisValue) else: chart.addAxis(axisStud, Qt.AlignmentFlag.AlignLeft) seriesBar.attachAxis(axisStud) seriesLine.attachAxis(axisStud) chart.addAxis(axisValue, Qt.AlignmentFlag.AlignBottom) seriesBar.attachAxis(axisValue) seriesLine.attachAxis(axisValue) for marker in chart.legend().markers():#QLegendMarker类型列表 marker.clicked.connect(self.do_LegendMarkerClicked) @pyqtSlot() def on_btnBuildBarChart_clicked(self): self.draw_barChart() @pyqtSlot() ##绘制水平柱状图 def on_btnBuildBarChartH_clicked(self): self.draw_barChart(False) #与seriesBar.hovered.connect(self.do_barSeries_Hovered)关联 def do_barSeries_Hovered(self, status, index, barset): hint = "hovered barset="+barset.label() if status: hint=hint+",index=%d,value=%.2f"%(index, barset.at(index)) else: hint="" self.ui.statusbar.showMessage(hint) def do_barSeries_Clicked(self, index, barset): hint="clicked barSet="+barset.label() hint=hint+",count=%d,sum=%.2f"%(barset.count(), barset.sum()) self.ui.statusbar.showMessage(hint) @pyqtSlot() def __openDB(self): self.DB=QSqlDatabase.addDatabase("QODBC") self.DB.setHostName("localhost") self.DB.setDatabaseName("pyqt") self.DB.setUserName("pyqt") self.DB.setPassword("pyqt123456") if not self.DB.open(): QMessageBox.warning(self, "错误", "打开数据库失败") @pyqtSlot() def __generateData(self): self.dataModel.clear() headerList=["姓名", "统帅", "武力", "智力", "政治", "魅力", "平均分"] self.dataModel.setHorizontalHeaderLabels(headerList)#设置头文字 qryStudList = QSqlQuery(self.DB)#学生信息列表 qryStudList.exec("select 姓名,统帅,武力,智力,政治,魅力 from sanguozhi") qryStudList.first() while(qryStudList.isValid()): itemList=[] studName=qryStudList.value("姓名") item=QStandardItem(studName) item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) itemList.append(item) avgScore=0 studTongshuai=qryStudList.value("统帅") item =QStandardItem("%.0f"%studTongshuai) item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) item.setFlags(item.flags() & ~(Qt.ItemFlag.ItemIsEditable)) itemList.append(item) avgScore=avgScore+studTongshuai #其实这里只是求和,用于计算平均值 studWuli =qryStudList.value("武力") item =QStandardItem("%.0f"%studWuli) item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) item.setFlags(item.flags() & ~(Qt.ItemFlag.ItemIsEditable)) itemList.append(item) avgScore=avgScore+studWuli studZhili =qryStudList.value("智力") item =QStandardItem("%.0f"%studZhili) item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) item.setFlags(item.flags() & ~(Qt.ItemFlag.ItemIsEditable)) itemList.append(item) avgScore=avgScore+studZhili studZhengzhi =qryStudList.value("政治") item =QStandardItem("%.0f"%studZhengzhi) item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) item.setFlags(item.flags() & ~(Qt.ItemFlag.ItemIsEditable)) itemList.append(item) avgScore=avgScore+studZhengzhi studMeili =qryStudList.value("魅力") item =QStandardItem("%.0f"%studMeili)#创建item item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) item.setFlags(item.flags() & ~(Qt.ItemFlag.ItemIsEditable)) itemList.append(item) avgScore=avgScore+studMeili item =QStandardItem("%1.f"%(avgScore/5.0))#创建平均分item item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) item.setFlags(item.flags() & ~(Qt.ItemFlag.ItemIsEditable))#平均分不允许编辑 itemList.append(item)#添加到列表 self.dataModel.appendRow(itemList)#添加数据模型 if not qryStudList.next():#移动到下一条记录,并判断是否到末尾了 break for i in range(0, 6): self.ui.tableView.setColumnWidth(i, 50) self.ui.tableView.setColumnWidth(6, 80)#个性化的列设置 @pyqtSlot() def __surveyData(self): for i in range(1, 6):#0姓名 1统帅 2武力 3智力 4政治 5魅力,range(1,6)即1到5 cnt50, cnt60, cnt70, cnt80, cnt90=0, 0, 0, 0, 0 for j in range(self.dataModel.rowCount()):#行数表示人数 val=float(self.dataModel.item(j, i).text())#分数 if val<60: cnt50=cnt50+1 elif (val>=60 and val<70): cnt60=cnt60+1 elif(val>=70 and val<80): cnt70=cnt70+1 elif (val>=80 and val<90): cnt80=cnt80+1 else: cnt90=cnt90+1 #统计分数 item=self.ui.treeWidget.topLevelItem(0)#第一行,<60 item.setText(i,str(cnt50))#第i列 item.setTextAlignment(i, Qt.AlignmentFlag.AlignCenter) item=self.ui.treeWidget.topLevelItem(1)#第二行,[60~70] item.setText(i,str(cnt60))#第i列 item.setTextAlignment(i, Qt.AlignmentFlag.AlignCenter) item=self.ui.treeWidget.topLevelItem(2)#第三行,[70~80] item.setText(i,str(cnt70))#第i列 item.setTextAlignment(i, Qt.AlignmentFlag.AlignCenter) item=self.ui.treeWidget.topLevelItem(3)#第四行,[80~90] item.setText(i,str(cnt80))#第i列 item.setTextAlignment(i, Qt.AlignmentFlag.AlignCenter) item=self.ui.treeWidget.topLevelItem(4)#第五行,[90~100] item.setText(i,str(cnt90))#第i列 item.setTextAlignment(i, Qt.AlignmentFlag.AlignCenter) self.ui.treeWidget.setColumnWidth(0, 80)#个性化列宽设置 for i in range(1, 6): self.ui.treeWidget.setColumnWidth(i, 50) @pyqtSlot() def do_LegendMarkerClicked(self): marker = self.sender()#QLendMarker marker.series().setVisible(not marker.series().isVisible()) marker.setVisible(True) alpha= 1.0#对比度 if not marker.series().isVisible(): alpha= 0.5 brush = marker.labelBrush()#QBrush color =brush.color() color.setAlphaF(alpha) brush.setColor(color) marker.setLabelBrush(brush) brush=marker.brush() color = brush.color() color.setAlphaF(alpha) brush.setColor(color) marker.setBrush(brush) pen=marker.pen() color=pen.color() color.setAlphaF(alpha) pen.setColor(color) marker.setPen(pen) ##======page 2.StackedBar========== @pyqtSlot()##初始化堆叠柱状图 def __iniStackedBar(self): chart = QChart() chart.setTitle("StackedBar 演示") self.ui.chartViewStackedBar.setChart(chart) self.ui.chartViewStackedBar.setRenderHint(QPainter.RenderHint.Antialiasing)#反走样 self.ui.chartViewStackedBar.setCursor(Qt.CursorShape.CrossCursor)#设置鼠标指针为十字星 @pyqtSlot()##绘制StackedBar def on_btnBuildStackedBar_clicked(self): self.draw_stackedBar() @pyqtSlot()##绘制水平StackedBar def on_btnBuildStackedBarH_clicked(self): self.draw_stackedBar(False) def draw_stackedBar(self,isVertical=True): chart=self.ui.chartViewStackedBar.chart() chart.removeAllSeries() #删除所有序列 for axis in chart.axes(): chart.removeAxis(axis)#删除坐标轴 if isVertical: chart.setTitle("Stackedchart 演示") chart.legend().setAlignment(Qt.AlignmentFlag.AlignBottom)#图标放于底部 else: chart.setTitle("Horizontal Stackedchart 演示") chart.legend().setAlignment(Qt.AlignmentFlag.AlignRight)#图标放于右侧 setTongshuai = QBarSet("统帅") setWuli = QBarSet("武力") setZhili=QBarSet("智力") setZhengzhi=QBarSet("政治") setMeili = QBarSet("魅力") stud_Count=self.dataModel.rowCount() nameList=[]#学生姓名列表,用于QBarCategoryAxis类坐标轴 for i in range(stud_Count): #从数据模型中获取数据 item=self.dataModel.item(i, 0)#第0列姓名 nameList.append(item.text())#姓名,用作坐标轴标签 item=self.dataModel.item(i, 1)#第一列统帅 setTongshuai.append(float(item.text())) item=self.dataModel.item(i, 2)#第二列武力 setWuli.append(float(item.text())) item=self.dataModel.item(i, 3)#第三列智力 setZhili.append(float(item.text())) item=self.dataModel.item(i, 4)#第四列政治 setZhengzhi.append(float(item.text())) item=self.dataModel.item(i, 5)#第五列魅力 setMeili.append(float(item.text())) ##创建序列 if isVertical: seriesBar =QStackedBarSeries() else: seriesBar=QHorizontalStackedBarSeries()#水平柱状图 seriesBar.append(setTongshuai)#添加数据集 seriesBar.append(setWuli) seriesBar.append(setZhili) seriesBar.append(setZhengzhi) seriesBar.append(setMeili)#数据点标签可见 seriesBar.setLabelsVisible(True)#数据点标签可见 seriesBar.setLabelsFormat("@value")#显示数值标签 seriesBar.setLabelsPosition(QAbstractBarSeries.LabelsPosition.LabelsCenter)#数据标签显示位置 seriesBar.hovered.connect(self.do_barSeries_Hovered)#hovered信号 seriesBar.clicked.connect(self.do_barSeries_Clicked)#clicked信号 chart.addSeries(seriesBar)#添加柱状图序列 axisStud=QBarCategoryAxis() axisStud.append(nameList)#添加横坐标文字列表 axisStud.setRange(nameList[0], nameList[stud_Count-1])#坐标轴范围 #数值型坐标轴 axisValue=QValueAxis() axisValue.setRange(0, 500) axisValue.setTitleText("总分") axisValue.setTickCount(6) #刻度线数量 axisValue.applyNiceNumbers() #让刻度线更好看 if isVertical: chart.addAxis(axisStud, Qt.AlignmentFlag.AlignBottom) seriesBar.attachAxis(axisStud)#添加轴 chart.addAxis(axisValue, Qt.AlignmentFlag.AlignLeft) seriesBar.attachAxis(axisValue) else: chart.addAxis(axisStud, Qt.AlignmentFlag.AlignLeft) seriesBar.attachAxis(axisStud) chart.addAxis(axisValue, Qt.AlignmentFlag.AlignBottom) seriesBar.attachAxis(axisValue) for marker in chart.legend().markers():#QLegendMarker类型列表 marker.clicked.connect(self.do_LegendMarkerClicked) ##===========page3.百分比柱状图================= @pyqtSlot()##初始化百分比柱状图 def __iniPercentBar(self): chart=QChart() chart.setTitle("PercentBar 演示") self.ui.chartViewPercentBar.setChart(chart) self.ui.chartViewPercentBar.setRenderHint(QPainter.RenderHint.Antialiasing)#反走样 self.ui.chartViewPercentBar.setCursor(Qt.CursorShape.CrossCursor)#设置鼠标指针为十字星 @pyqtSlot()##绘制PercentBar def on_btnBuildPercentBar_clicked(self): self.draw_percentBar() @pyqtSlot()##绘制水平PercentBar def on_btnBuildPercentBarH_clicked(self): self.draw_percentBar(False) def draw_percentBar(self, isVertical=True): chart=self.ui.chartViewPercentBar.chart() chart.removeAllSeries() for axis in chart.axes(): chart.removeAxis(axis)#删除坐标轴 chart.legend().setAlignment(Qt.AlignmentFlag.AlignRight) if isVertical: chart.setTitle("PercentBar 演示") else: chart.setTitle("Horizontal PercentBar 演示") scoreBarSets=[] #QBarSet对象列表 sectionCount=5 #5个分数段,分数段是数据集 for i in range(sectionCount): item=self.ui.treeWidget.topLevelItem(i) barSet=QBarSet(item.text(0)) #一个分数段 scoreBarSets.append(barSet) #QBarSet对象列表 categories=["统帅", "武力", "智力", "政治", "魅力"] courseCount=5 #5门课程 for i in range(sectionCount): #5个分数段 item=self.ui.treeWidget.topLevelItem(i) #treeWidget第i行 barSet=scoreBarSets[i] #某个分数段的QBarSet for j in range(courseCount): #课程是category barSet.append(float(item.text(j+1))) if isVertical: seriesBar=QPercentBarSeries()#序列 else: seriesBar=QHorizontalPercentBarSeries()#序列 seriesBar.append(scoreBarSets)#添加一个QBarset对象列表 seriesBar.setLabelsVisible(True)#显示百分比 seriesBar.hovered.connect(self.do_barSeries_Hovered)#hovered信号 seriesBar.clicked.connect(self.do_barSeries_Clicked)#clicked信号 chart.addSeries(seriesBar) axisSection= QBarCategoryAxis()#分类坐标 axisSection.append(categories) axisSection.setTitleText("分数段") axisSection.setRange(categories[0], categories[courseCount-1]) axisValue= QValueAxis()#数值坐标 axisValue.setRange(0, 100) axisValue.setTitleText("累积百分比") axisValue.setTickCount(6) axisValue.setLabelFormat("%.0f%")#标签格式 axisValue.applyNiceNumbers() if isVertical: chart.addAxis(axisSection, Qt.AlignmentFlag.AlignBottom) seriesBar.attachAxis(axisSection) chart.addAxis(axisValue, Qt.AlignmentFlag.AlignLeft) seriesBar.attachAxis(axisValue) else: chart.addAxis(axisSection, Qt.AlignmentFlag.AlignLeft) seriesBar.attachAxis(axisSection) chart.addAxis(axisValue, Qt.AlignmentFlag.AlignBottom) seriesBar.attachAxis(axisValue) for marker in chart.legend().markers():#QLegendMarker类型列表 marker.clicked.connect(self.do_LegendMarkerClicked) ##===============page 4.饼图============== @pyqtSlot()##初始化饼图 def __iniPieChart(self): chart=QChart() chart.setTitle("Piechart 演示") self.ui.chartViewPie.setChart(chart)#为ChartView设置chart self.ui.chartViewPie.setRenderHint(QPainter.RenderHint.Antialiasing)#反走样 self.ui.chartViewPie.setCursor(Qt.CursorShape.CrossCursor)#设置鼠标指针为十字星 @pyqtSlot()#绘制饼图 def on_btnDrawPieChart_clicked(self): self.draw_pieChart() @pyqtSlot() def draw_pieChart(self): chart=self.ui.chartViewPie.chart()#获取chart对象 chart.legend().setAlignment(Qt.AlignmentFlag.AlignRight) chart.removeAllSeries() colNo=1+self.ui.comboCourse.currentIndex() seriesPie = QPieSeries() seriesPie.setHoleSize(self.ui.spinHoleSize.value()) sec_count=5 seriesPie.setLabelsVisible(True) for i in range(sec_count): item=self.ui.treeWidget.topLevelItem(i) sliceLabel=item.text(0)+"(%s人)"%item.text(colNo) sliceValue=int(item.text(colNo)) seriesPie.append(sliceLabel, sliceValue) seriesPie.setLabelsVisible(True)#只影响当前的slices,必须添加玩slice之后再设置 seriesPie.hovered.connect(self.do_pieHovered)#鼠标落在某个分块上时,次分块弹出 chart.addSeries(seriesPie) chart.setTitle("Piechart---"+self.ui.comboCourse.currentText()) @pyqtSlot(int) def on_comboCourse_currentIndexChanged(self, index): self.draw_pieChart() @pyqtSlot(float)##设置holeSize def on_spinHoleSize_valueChanged(self, arg1): seriesPie=self.ui.chartViewPie.chart().series()[0] seriesPie.setHoleSize(arg1) @pyqtSlot(float)##设置pieSize def on_spinPieSize_valueChanged(self, arg1): seriesPie=self.ui.chartViewPie.chart().series()[0] seriesPie.setPieSize(arg1) @pyqtSlot(bool)##显示图例checkbox def on_chkBoxPieLegend_clicked(self, checked): self.ui.chartViewPie.chart().legend().setVisible(checked) def do_pieHovered(self, pieSlice, state): pieSlice.setExploded(state)#弹回或缩回,具有动态效果 if state:#显示带百分数的标签 self.__oldLabel=pieSlice.label()#保存原来的label pieSlice.setLabel(self.__oldLabel+":%.1f%%" %(pieSlice.percentage()*100)) else:#显示原来的标签 pieSlice.setLabel(self.__oldLabel) ##================工具栏按钮============ @pyqtSlot()##重新生成数据 def on_toolBtn_GenData_clicked(self): self.__generateData() self.__surveyData() @pyqtSlot()##重新统计 def on_toolBtn_Counting_clicked(self): self.__surveyData() @pyqtSlot()##获取当前Qchart对象 def __getCurrentChart(self): page=self.ui.tabWidget.currentIndex() if page ==0: chart=self.ui.chartViewBar.chart() elif page==1: chart=self.ui.chartViewStackedBar.chart() elif page==2: chart=self.ui.chartViewPercentBar.chart() else: chart=self.ui.chartViewPie.chart() return chart @pyqtSlot(int) def on_comboTheme_currentIndexChanged(self, index): chart=self.__getCurrentChart() chart.setTheme(QChart.ChartTheme(index)) @pyqtSlot(int)##图表动画 def on_comboAnimation_currentIndexChanged(self, index): chart=self.__getCurrentChart() chart.setAnimationOptions(QChart.AnimationOption(index)) if __name__=="__main__":#用于当前窗体测试 app=QApplication(sys.argv)#创建GUI应用程序 form=QmyMainWindow()#创建窗体 form.show() sys.exit(app.exec())
这里的特别说一下饼图:
饼图是根据窗口左下角的 treeWidget 里面的数据绘制的。饼图只能表示一种能力的各个 分数段的人数和百分比,所以在饼图界面需要选择相关能力。HoleSize 用于设置饼图中心空 心圆的相对大小,数值在 0 到 1 之间。PieSize 用于设置饼图与图表视图的相对大小,数值 在 0 到 1 之间。
向饼图中添加动画效果
chart.setAnimationOptions(QChart.AnimationOption.SeriesAnimations)
添加饼图操作的效果:
@pyqtSlot(int) def on_comboCourse_currentIndexChanged(self, index): self.draw_pieChart() @pyqtSlot(float)##设置holeSize def on_spinHoleSize_valueChanged(self, arg1): seriesPie=self.ui.chartViewPie.chart().series()[0] seriesPie.setHoleSize(arg1) @pyqtSlot(float)##设置pieSize def on_spinPieSize_valueChanged(self, arg1): seriesPie=self.ui.chartViewPie.chart().series()[0] seriesPie.setPieSize(arg1) @pyqtSlot(bool)##显示图例checkbox def on_chkBoxPieLegend_clicked(self, checked): self.ui.chartViewPie.chart().legend().setVisible(checked)
holesize的效果:
piesize的效果:
checkbox的效果:
hover用于悬浮饼图:
def do_pieHovered(self, pieSlice, state): pieSlice.setExploded(state)#弹回或缩回,具有动态效果 if state:#显示带百分数的标签 self.__oldLabel=pieSlice.label()#保存原来的label pieSlice.setLabel(self.__oldLabel+":%.1f%%" %(pieSlice.percentage()*100)) else:#显示原来的标签 pieSlice.setLabel(self.__oldLabel)
设置图表主题:
0:Light;1:BlueCerulean;2:Dark;3:BrownSand;4:BlueNcs;5:HighContrast;6:
BlueIcy;7:Qt。
看一下官网对 ChartTheme 的定义,对照理解一下。
设置图表的动画:
0:NoAnimation;1:GridAxisAnimations;2:SeriesAnimations;3:AllAnimations
对照一下官网对 AnimationOption 的定义:
效果呈现:
(1)主题:默认light主题
改为Qt主题:
(2)动画:
默认情况是 NoAnimation,柱状图、堆叠柱状图、百分比柱状图是没动画的,而饼图代码加了动画语句进去,是有动画的。
选择 GridAnimation,看柱状图,发现有动画效果。坐标轴从左上角开始,往下往右出来。棒柱不变
选择 SeriesAnimation,看柱状图,发现有动画效果。坐标轴不动,棒柱从下往上,逐渐长高
选择 AllAnimations,发现坐标轴和棒柱同时发生变化。坐标轴从左上角的原点出发,拉伸到右下角。棒柱从下往上长高。
注:
要在Ui_MainWindow中需加入import res_rc
同时将res_rc.py中的
from PySide6 import QtCore
改为:from PyQt6 import QtCore
这样才能在运行窗口中显示图标
这是老师布置的作业,但是感觉学到很多,也分享给大家啦!
————————————————