在 github 上发现了一个还挺不错的资源:《PyQt 的各种测试和例子》,所以准备在此新开一个坑,逐个研习一下这些例子,把研习过程中的一些重要内容记录在此作为备忘。由于平时工作忙,可能自己研习的时间没有规律,但会坚持不断的更新。
本例源代码如下:非原创,具体来源见链接,此处仅做研习记录用途
#!/usr/bin/env python
# encoding: utf-8
'''
Created on 2019年5月2日
@author: weike32
@site: https://pyqt5.com ,https://github.com/weike32
@email: [email protected]
@file: CopyContent
@description: 查阅了很多博客,如果有异,可以联系作者邮箱。本Demo仅作学习参考用,保有后续相关权益。
'''
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5 import QtCore
import numpy as np
import pyqtgraph as pg
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(726, 595)
self.graphicsView = pg.PlotWidget(Form)
self.graphicsView.setGeometry(QtCore.QRect(75, 131, 621, 441))
self.graphicsView.setObjectName("graphicsView")
class MyWindow(QMainWindow, Ui_Form):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.setupUi(self)
x = np.linspace(-100, 100, 1000)
data = np.sin(x) / x
self.graphicsView.plot(data, pen=(255, 255, 255, 200))
self.label = pg.TextItem(text="横坐标:{}".format(0))
self.graphicsView.addItem(self.label)
self.setMouseTracking(True)
self.graphicsView.scene().sigMouseMoved.connect(self.onMouseMoved)
def onMouseMoved(self, evt):
if self.graphicsView.plotItem.vb.mapSceneToView(evt):
point =self.graphicsView.plotItem.vb.mapSceneToView(evt)
self.label.setHtml("横坐标:{0}
".format(point.x()))
if __name__ == '__main__':
app = QApplication(sys.argv)
myWin = MyWindow()
myWin.show()
sys.exit(app.exec_())
以上代码主窗口为 MyWindow
类,该类继承自 QMainWindow
和 Ui_Form
。
在这个例子中,有以下值得注意的点:
super(MyWindow, self).__init__(parent)
这一行的作用是执行父类的构造函数,以便我们能够使用父类的属性和方法;Ui_Form
是一个自定义类,加不加 object
其实对于 Python3 来说已经没有区别,因为 Python3 中默认都是新式类,具体可以参考以下链接:python的class(类)中的object是什么意思?Ui_Form
类其实就是一个构造视图的方法,通过实例化 pyqtgraph.PlotWidget()
来设置一个绘图区域,关于这一个类的具体使用可以参考官方API:PlotWidgetMyWindow
的构造函数中,添加setMouseTrack(True)
,得到监听事件。若是setMouseTrack(False),只有鼠标按下才会有mouseMove监听事件响应。self.graphicsView.scene().sigMouseMoved.connect(self.onMouseMoved)
中 , self.graphicsView.scene()
是用来获取 pyqtgraph.GraphicsScene
对象,对于 GraphicsScene
来说,有着三个鼠标事件:sigMouseClicked(event)
, sigMouseMoved(pos)
, sigMouseHover(items)
。分别对应鼠标在视图区域内的单击,移动以及悬停事件。关于这部分的具体内容,可以参考:GraphicsScene and Mouse Events。在此处用到的是第二种,鼠标移动信息,该信号被绑定在了 onMouseMoved(self, evt)
成员函数上,由于这个信号本身是有参数,evt 就是用来接收这个参数的。sigMouseMoved(pos)
信号中关于 pos 的解释是:The position is given in scene coordinates.也就是说,这个参数是用视图坐标给出的,实际如果要对应到坐标系中,需要进行转换,self.graphicsView.plotItem.vb.mapSceneToView()
方法就是进行转换的。转换前和转换后都是 PyQt5.QtCore.QPointF
类, 可以使用 .x()
和 .y()
方法来进行坐标的获取。与mapSceneToView
方法对应的是 mapViewToScene
方法。#!/usr/bin/env python
# encoding: utf-8
'''
Created on 2019年5月21日
@author: weike32
@site: https://pyqt5.com ,https://github.com/weike32
@email: [email protected]
@file: CopyContent
@description: 禁止右键,添加滑动窗口,点击按钮生成图片,自定义Y轴坐标,背景颜色调整
'''
import sys
from PyQt5.QtWidgets import QDialog, QApplication, QWidget
from qtpy import QtWidgets
import pyqtgraph as pg
from PyQtGraph.Data.graphTest import graph_Form
class CustomViewBox(pg.ViewBox):
def __init__(self, *args, **kwds):
pg.ViewBox.__init__(self, *args, **kwds)
self.RectMode = 3
self.setMouseMode(self.RectMode)
def mouseClickEvent(self, ev):
if ev.button() == pg.QtCore.Qt.RightButton:
self.autoRange()
def mouseDragEvent(self, ev):
pg.ViewBox.mouseDragEvent(self, ev)
def wheelEvent(self,ev, axis=None):
# pg.ViewBox.wheelEvent(self, ev, axis)
ev.ignore()
class graphAnalysis(QDialog,graph_Form):
def __init__(self):
super(graphAnalysis, self).__init__()
self.setupUi(self)
self.pushButton_7.clicked.connect(self.test)
self.tabWidget.clear()
def test(self):
tab1 = QtWidgets.QWidget()
scrollArea = QtWidgets.QScrollArea(tab1)
scrollArea.setMinimumSize(984,550)
scrollArea.setWidgetResizable(True)
labelsContainer = QWidget()
labelsContainer.setMinimumSize(0,1500)
scrollArea.setWidget(labelsContainer)
layout = QtWidgets.QVBoxLayout(labelsContainer)
time = ['2019-04-20 08:09:00', '2019-04-20 08:09:00', '2019-04-20 08:09:00', '2019-04-20 08:09:00']
value = [1.2, 2, 1, 4]
xdict = dict(enumerate(time))
ticks = [list(zip(range(4), tuple(time)))]
vb = CustomViewBox()
plt = pg.PlotWidget(title="标题这里填写",viewBox=vb)
plt.setBackground(background=None)
plt.plot(list(xdict.keys()), value)
plt.getPlotItem().getAxis("bottom").setTicks(ticks)
temp = QtWidgets.QWidget()
temp.setMinimumSize(900,300)
temp.setMaximumSize(900,300)
layout1 = QtWidgets.QVBoxLayout(temp)
layout1.addWidget(plt)
layout.addWidget(temp)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
layout.addItem(spacerItem)
self.tabWidget.addTab(tab1, '这里tabWidget修改标签')
if __name__ =="__main__":
app = QApplication(sys.argv)
w = graphAnalysis()
w.show()
sys.exit(app.exec_())
from PyQtGraph.Data.graphTest import graph_Form 运行可能报错,目录结构的问题
测试时可以将Data目录下的 graphTest .py 和 graphTest.ui 拷贝到和 graph1.py 同级的目录里,并将 from PyQtGraph.Data.graphTest import graph_Form
改成 from graphTest import graph_Form
默认的绘图,在绘图区域单击右键,可以得到很多的操作菜单。
本例中通过 改写 ViewBox
来实现禁用右键点击功能
ViewBox.RectMode
和 ViewBox.PanMode
:对于viewbox来说,鼠标模式只支持两种,一种是 rect 模式,一种是 pan 模式;两种模式的区别在于鼠标左边的拖拽功能不一样:Rect 模式拖拽鼠标左键时会产生一个矩形方框,松开鼠标会放大方框内的图形;而 Pan 模式拖拽鼠标左键时平移作用。值得注意的是,两种模式下,鼠标中键和右键的作用均相同,鼠标中键等同于左键,单击鼠标右键作用默认为唤出交互菜单。经测试,PanMode对应的值为3,而RectMode对应的值为1,self.RectMode = 3; self.setMouseMode(self.RectMode);
两行代码实际上是将鼠标模式设置为了 PanMode,直接使用一句 self.setMouseMode(self.PanMode)
即可ev.ignore()
一行,禁用了鼠标滚轮的滚动效果(原本可以用来缩放图形),这样鼠标滚轮滚动可以只触发滚动条滚动而不影响图形。mouseClickEvent
中,通过判断鼠标单击事件单击的是右键,来重新定义单击右键的功能,从而改变原来的右键单击功能(唤出菜单),改变以后的右键功能为:单击右键显示全部图形(autoRange)按住右键左右拖拽为缩放X轴,上下拖拽为缩放Y轴graphAnalysis
中的布局写的有点难以阅读,逻辑是这样的:
__init__(self)
中,通过继承 graph_Form
,得到父类的布局,一个 tabWidget 和 一个 pushButton_7,并且通过 self.tabWidget.clear()
函数将原有的 tab 里的内容情空掉了,新的内容通过按钮的回调函数 test()
来添加;test
函数中添加的视图结构如下,个人认为嵌套得过于复杂,实际自己写代码时,如果这样写,会给后期维护带来很大的麻烦;tabWidget布局
scrollArea
里,也就是 QtWidgets.QScrollArea
实例,实际上,只要是QWidget,都可以装载进这个容器里,以达到滚动条滚动显示的目的 temp = QtWidgets.QWidget()
temp.setMinimumSize(900,300)
temp.setMaximumSize(900,300)
通过设置 最大 和 最小 尺寸 一致,来禁止图形内容被放大或缩小,当父级控件被缩放的时候,该控件只会显示局部或者留白
plt = pg.PlotWidget(title="标题这里填写",viewBox=vb)
通过重载 ViewBox,来实现前述的禁用右键和滚动等功能
time = ['2019-04-20 08:09:00', '2019-04-20 08:09:00', '2019-04-20 08:09:00', '2019-04-20 08:09:00']
xdict = dict(enumerate(time))
ticks = [list(zip(range(4), tuple(time)))]
value = [1.2, 2, 1, 4]
plt.plot(list(xdict.keys()), value)
plt.getPlotItem().getAxis("bottom").setTicks(ticks)
通过 setTicks
来实现时间轴的显示,注意 ticks 的格式问题
等待研习。。。
最后插一条私人恩怨
山东中天物联网(另一个名字,威海天乐物联网有限公司)是个不诚信商家,需要采购传感器和采集仪的朋友们千万注意避坑。我为公司采购,事前明确确认过的参数,收货后发现无法满足,但对方耍无赖拒绝退货退款。吃了个闷亏。