PyQt/QGraphicsView练习/QChartToolTipTest.py

234 lines
8 KiB
Python
Raw Normal View History

2017-12-24 02:16:55 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Created on 2017年12月23日
@author: Irony."[讽刺]
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
@email: 892768447@qq.com
@file: QChartToolTipTest
@description:
'''
import random
import sys
from PyQt5.QtChart import QChartView, QChart, QLineSeries
2017-12-25 01:07:21 +08:00
from PyQt5.QtCore import Qt, QRectF, QPoint, QPointF
2017-12-25 00:54:18 +08:00
from PyQt5.QtGui import QPainter, QCursor
from PyQt5.QtWidgets import QApplication, QGraphicsProxyWidget, QLabel, \
QWidget, QHBoxLayout, QVBoxLayout, QToolTip, QGraphicsLineItem
2017-12-24 02:16:55 +08:00
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
__Copyright__ = "Copyright (c) 2017 Irony.\"[讽刺]"
__Version__ = "Version 1.0"
m_listCount = 3
m_valueMax = 10
m_valueCount = 7
def generateRandomData(listCount, valueMax, valueCount):
random.seed()
dataTable = []
for i in range(listCount):
dataList = []
yValue = 0.0
f_valueCount = float(valueCount)
for j in range(valueCount):
yValue += random.uniform(0, valueMax) / f_valueCount
value = j + random.random() * m_valueMax / f_valueCount, yValue
label = "Slice " + str(i) + ":" + str(j)
dataList.append((value, label))
dataTable.append(dataList)
return dataTable
m_dataTable = generateRandomData(m_listCount, m_valueMax, m_valueCount)
2017-12-25 00:54:18 +08:00
'''
2017-12-24 02:16:55 +08:00
class CircleWidget(QGraphicsProxyWidget):
def __init__(self, color, *args, **kwargs):
super(CircleWidget, self).__init__(*args, **kwargs)
label = QLabel()
label.setMinimumSize(12, 12)
label.setMaximumSize(12, 12)
label.setStyleSheet(
"border:1px solid green;border-radius:6px;background: %s;" % color)
self.setWidget(label)
class TextWidget(QGraphicsProxyWidget):
def __init__(self, text, *args, **kwargs):
super(TextWidget, self).__init__(*args, **kwargs)
self.setWidget(QLabel(text, styleSheet="color:white;"))
class GraphicsWidget(QGraphicsWidget):
def __init__(self, *args, **kwargs):
super(GraphicsWidget, self).__init__(*args, **kwargs)
# self.setFlags(self.ItemClipsChildrenToShape)
self.setZValue(999)
layout = QGraphicsGridLayout(self)
for row in range(6):
layout.addItem(CircleWidget("red"), row, 0)
layout.addItem(TextWidget("red"), row, 1)
self.hide()
def show(self, pos):
self.setGeometry(pos.x(), pos.y(), self.size().width(),
self.size().height())
super(GraphicsWidget, self).show()
2017-12-25 00:54:18 +08:00
'''
2017-12-24 02:16:55 +08:00
class ToolTipItem(QWidget):
def __init__(self, color, text, parent=None):
super(ToolTipItem, self).__init__(parent)
layout = QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
clabel = QLabel(self)
clabel.setMinimumSize(12, 12)
clabel.setMaximumSize(12, 12)
clabel.setStyleSheet("border-radius:6px;background: rgba(%s,%s,%s,%s);" % (
color.red(), color.green(), color.blue(), color.alpha()))
layout.addWidget(clabel)
self.textLabel = QLabel(text, self, styleSheet="color:white;")
layout.addWidget(self.textLabel)
def setText(self, text):
self.textLabel.setText(text)
class ToolTipWidget(QWidget):
Cache = {}
def __init__(self, *args, **kwargs):
super(ToolTipWidget, self).__init__(*args, **kwargs)
self.setAttribute(Qt.WA_StyledBackground, True)
self.setStyleSheet(
"ToolTipWidget{background: rgba(50,50,50,70);}")
layout = QVBoxLayout(self)
self.titleLabel = QLabel(self, styleSheet="color:white;")
layout.addWidget(self.titleLabel)
def updateUi(self, title, points):
self.titleLabel.setText(title)
for serie, point in points:
if serie not in self.Cache:
item = ToolTipItem(
serie.color(),
(serie.name() or "-") + ":" + str(point.y()), self)
self.layout().addWidget(item)
self.Cache[serie] = item
else:
self.Cache[serie].setText(
(serie.name() or "-") + ":" + str(point.y()))
class GraphicsProxyWidget(QGraphicsProxyWidget):
def __init__(self, *args, **kwargs):
super(GraphicsProxyWidget, self).__init__(*args, **kwargs)
self.setZValue(999)
self.tipWidget = ToolTipWidget()
self.setWidget(self.tipWidget)
self.hide()
def show(self, title, points, pos):
self.setGeometry(QRectF(pos, self.size()))
self.tipWidget.updateUi(title, points)
super(GraphicsProxyWidget, self).show()
class ChartView(QChartView):
def __init__(self, *args, **kwargs):
super(ChartView, self).__init__(*args, **kwargs)
self.resize(800, 600)
self.setRenderHint(QPainter.Antialiasing) # 抗锯齿
self.initChart()
self.toolTipWidget = GraphicsProxyWidget(self._chart)
2017-12-25 00:54:18 +08:00
# line
self.lineItem = QGraphicsLineItem(self._chart)
self.lineItem.setZValue(998)
self.lineItem.hide()
2017-12-24 02:16:55 +08:00
def mouseMoveEvent(self, event):
super(ChartView, self).mouseMoveEvent(event)
# 获取x和y轴的最小最大值
axisX, axisY = self._chart.axisX(), self._chart.axisY()
min_x, max_x = axisX.min(), axisX.max()
min_y, max_y = axisY.min(), axisY.max()
2017-12-25 19:54:13 +08:00
# 坐标系中左上角顶点
point_top = self._chart.mapToPosition(QPointF(min_x, max_y))
# 坐标原点坐标
point_bottom = self._chart.mapToPosition(QPointF(min_x, min_y))
2017-12-24 02:16:55 +08:00
step_x = (max_x - min_x) / (axisX.tickCount() - 1)
step_y = (max_y - min_y) / (axisY.tickCount() - 1)
# 把鼠标位置所在点转换为对应的xy值
x = self._chart.mapToValue(event.pos()).x()
y = self._chart.mapToValue(event.pos()).y()
2017-12-25 01:07:21 +08:00
# print(x, y, step_x, step_y, event.pos())
2017-12-24 02:16:55 +08:00
r_x = x / step_x
2017-12-25 00:54:18 +08:00
r_y = y / step_y # @UnusedVariable
2017-12-24 02:16:55 +08:00
index = round(r_x) - 1 # 四舍五入
# print(r_x, r_y, index, step_x, step_y)
# 得到在坐标系中的所有series的类型和点
points = [(serie, serie.at(index))
for serie in self._chart.series() if min_x <= x <= max_x and min_y <= y <= max_y]
if points:
2017-12-25 19:54:13 +08:00
# 跟随鼠标的黑线条
self.lineItem.setLine(event.pos().x(), point_top.y(),
event.pos().x(), point_bottom.y())
2017-12-25 00:54:18 +08:00
self.lineItem.show()
2017-12-24 02:16:55 +08:00
self.toolTipWidget.show("", points, event.pos() + QPoint(20, 20))
else:
self.toolTipWidget.hide()
2017-12-25 00:54:18 +08:00
self.lineItem.hide()
def onSeriesHoverd(self, point, state):
if state:
try:
name = self.sender().name()
except:
name = ""
QToolTip.showText(QCursor.pos(), "%s\nx: %s\ny: %s" %
(name, point.x(), point.y()))
2017-12-24 02:16:55 +08:00
def initChart(self):
self._chart = QChart(title="Line Chart")
2017-12-25 00:54:18 +08:00
self._chart.setAcceptHoverEvents(True)
2017-12-24 02:16:55 +08:00
for i, data_list in enumerate(m_dataTable):
series = QLineSeries(self._chart)
for value, _ in data_list:
series.append(*value)
series.setName("Series " + str(i))
2017-12-25 00:54:18 +08:00
series.setPointsVisible(True) # 显示原点
series.hovered.connect(self.onSeriesHoverd)
2017-12-24 02:16:55 +08:00
self._chart.addSeries(series)
self._chart.createDefaultAxes() # 创建默认的轴
self.setChart(self._chart)
if __name__ == "__main__":
app = QApplication(sys.argv)
2017-12-25 00:54:18 +08:00
app.setStyleSheet("""QToolTip {
border: none;
padding: 5px;
color: white;
background: rgb(50,50,50);
opacity: 100;
}""")
2017-12-24 02:16:55 +08:00
view = ChartView()
view.show()
sys.exit(app.exec_())