前言:
我发现百度上都搜不到有关PyQt有用的东西,全是C语言的Qt,对于我这种不懂C语言的萌新实在是不友好,官方文档也看不懂,实在是难堪。好像PyQt都没人用一样,哎。
我在学习Pyqt5过程中,看到ps的刻度尺然后突发奇想的想要去用pyqt5写一个刻度尺,然而只找到一个相关的代码。
想要的成果如下:
1、首先创建一个pyqt5的窗口
import sys
from PyQt5.QtWidgets import QWidget, QApplication
# 刻度尺
class GraduatedRuler(QWidget):
def __init__(self):
super(GraduatedRuler, self).__init__()
self.gr_width = 800
self.gr_height = 500
self.setFixedSize(self.gr_width, self.gr_height)
if __name__ == '__main__':
app = QApplication(sys.argv)
gr = GraduatedRuler()
gr.show()
sys.exit(app.exec_())
2、第一步:绘画出刻度尺
from PyQt5 import QtGui
from PyQt5.QtCore import QRect, QPoint, Qt
from PyQt5.QtGui import QPainter, QBrush, QPen
# 绘图事件
def paintEvent(self, a0: QtGui.QPaintEvent):
super().paintEvent(a0)
painter = QPainter(self) # 画图
painter.setPen(QPen(QBrush(Qt.black), 1)) # 设置画笔
width = int(self.gr_width)
height = int(self.gr_height)
painter.drawLine(20, 0, 20, height) # 画一条左侧刻度尺线
painter.drawLine(0, 20, width, 20) # 画一条上边刻度尺线
self.width_rect = QRect(0, 40, 20, height) # 保存左侧刻度尺的范围
self.height_rect = QRect(40, 0, width, 20) # 保存上边刻度尺的范围
# 左侧刻度,每10像素为一个小刻度,每40像素为一个大刻度
for i in range(40, height, 10):
if i % 40 == 0:
painter.drawText(QPoint(2, i - 22), str(i))
painter.drawLine(0, i, 20, i)
else:
painter.drawLine(20, i, 15, i)
# 上边刻度,每10像素为一个小刻度,每40像素为一个大刻度
for i in range(40, width, 10):
if i % 40 == 0:
painter.drawText(QPoint(i + 5, 10), str(i))
painter.drawLine(i, 0, i, 20)
else:
painter.drawLine(i, 20, i, 15)
3、第二步:点击刻度尺,向右或向下拉动出现刻度线
def __init__(self):
super(GraduatedRuler, self).__init__()
self.gr_width = 800
self.gr_height = 500
self.width_rect = None # 左侧刻度尺的范围,是一个矩形,QRect类型
self.height_rect = None # 上边刻度尺的范围,是一个矩形,QRect类型
self.width_moveLine = False # 判断是否为左侧刻度尺被拉动
self.height_moveLine = False # 判断是否为上边刻度尺被拉动
self.right_click = False # 右键点击
self.drawing_line = [] # 移动画线保存
self.drew_line = [] # 保存所有画线
self.setFixedSize(self.gr_width, self.gr_height)
# 绘图事件
def paintEvent(self, a0: QtGui.QPaintEvent):
......
# 更换画笔样式
painter.setPen(QPen(QColor(74, 255, 255), 1, Qt.SolidLine))
# 绘制已保存的画线
if self.drew_line:
for line_norms in self.drew_line:
line = line_norms['line']
painter.drawLine(line[0], line[1], line[2], line[3])
# 绘制“移动画线”,实时显示
if self.drawing_line:
for line in self.drawing_line:
painter.drawLine(line[0], line[1], line[2], line[3])
>> 鼠标操作事件
# 鼠标按压事件
def mousePressEvent(self, a0: QtGui.QMouseEvent):
super().mousePressEvent(a0)
self.mStartPoint = a0.pos()
# 如果不是右键点击
if a0.buttons() != Qt.RightButton:
# 如果鼠标点击位置是否在左侧刻度尺范围
if self.width_rect.contains(self.mStartPoint):
self.width_moveLine = True
else:
self.width_moveLine = False
# 如果鼠标点击位置是否在上边刻度尺范围
if self.height_rect.contains(self.mStartPoint):
self.height_moveLine = True
else:
self.height_moveLine = False
else:
self.right_click = True
# 鼠标移动事件
def mouseMoveEvent(self, a0: QtGui.QMouseEvent):
super().mouseMoveEvent(a0)
self.mMovePoint = a0.pos()
# 如果不是右键点击
if self.right_click is False:
if self.mStartPoint is not None:
# 如果是点击左侧刻度尺,把竖线保存在“移动画线”列表中,同一时间“移动画线”仅有一个
if self.width_moveLine is True:
self.drawing_line.clear()
self.drawing_line.append([self.mMovePoint.x(), 0, self.mMovePoint.x(), self.height()])
self.repaint()
# 如果是点击上边刻度尺,也把横线保存在“移动画线”列表中,同一时间“移动画线”仅有一个
if self.height_moveLine is True:
self.drawing_line.clear()
self.drawing_line.append([0, self.mMovePoint.y(), self.width(), self.mMovePoint.y()])
self.repaint()
# 鼠标施放事件
def mouseReleaseEvent(self, a0: QtGui.QMouseEvent):
super().mouseReleaseEvent(a0)
self.mReleasePoint = a0.pos()
# 如果不是右键点击
if self.right_click is False:
# 如果是点击左侧刻度尺,鼠标释放后就保存竖线
if self.width_moveLine is True:
for line in self.drawing_line:
self.drew_line.append({"norms": "width", "line": line})
self.repaint()
# 如果是点击上边刻度尺,鼠标释放后就保存横线
if self.height_moveLine is True:
for line in self.drawing_line:
self.drew_line.append({"norms": "height", "line": line})
self.repaint()
# 鼠标释放后,初始化动态状态
self.drawing_line.clear()
self.width_moveLine = False
self.height_moveLine = False
self.right_click = False
>> 效果展示:
4、第三步:点击刻度线,可以任意拖动
# 鼠标按压事件
def mousePressEvent(self, a0: QtGui.QMouseEvent):
super().mousePressEvent(a0)
self.mStartPoint = a0.pos()
# 如果不是右键点击
if a0.buttons() != Qt.RightButton:
# 如果鼠标点击位置是否在左侧刻度尺范围
if self.width_rect.contains(self.mStartPoint):
self.width_moveLine = True
else:
self.width_moveLine = False
# 如果鼠标点击位置是否在上边刻度尺范围
if self.height_rect.contains(self.mStartPoint):
self.height_moveLine = True
else:
self.height_moveLine = False
# 将刻度线变成可移动状态
index = 0
for drew_line in self.drew_line:
norms = drew_line['norms']
line = drew_line['line']
# 将线变成矩形,利用contains函数判断点击位置是或否在刻度线范围
if norms == "width":
tmp_rect = QRect(line[0], line[1], 3, line[3])
else:
tmp_rect = QRect(line[0], line[1], line[2], 3)
if tmp_rect.contains(self.mStartPoint):
self.drawing_line.clear()
self.drawing_line.append(line)
if norms == "width":
self.width_moveLine = True
else:
self.height_moveLine = True
break
index += 1
# 可移动的原理是,将已保存的画线取出放到“移动画线”中,删除已保存画线,“移动画线”释放后会再次保存在保存列表中
if index != len(self.drew_line):
del self.drew_line[index]
else:
self.right_click = True
5、删除刻度线,用右键策略
# 鼠标按压事件
def mousePressEvent(self, a0: QtGui.QMouseEvent):
super().mousePressEvent(a0)
self.mStartPoint = a0.pos()
# 如果不是右键点击
if a0.buttons() != Qt.RightButton:
......
else:
self.right_click = True
# 判断是否选中刻度线,未选中:-1
self.selected_line_numble = self.select_line(self.mStartPoint)
# 判断是否选中刻度线
def select_line(self, mStartPoint):
for index, drew_line in enumerate(self.drew_line):
norms = drew_line['norms']
line = drew_line['line']
if norms == "width":
tmp_rect = QRect(line[0], line[1], 3, line[3])
else:
tmp_rect = QRect(line[0], line[1], line[2], 3)
if tmp_rect.contains(mStartPoint):
return index
return -1
# 鼠标施放事件
def mouseReleaseEvent(self, a0: QtGui.QMouseEvent):
super().mouseReleaseEvent(a0)
self.mReleasePoint = a0.pos()
# 如果不是右键点击
if self.right_click is False:
......
else:
# 若选中刻度线,鼠标右键展开策略
if self.selected_line_numble != -1:
self.right_click_strategy() # 右键策略
......
# 右键策略
def right_click_strategy(self):
popMenu = QMenu(self) # 动态菜单
# 添加删除功能
delete_item = popMenu.addAction(u"删除")
atum = popMenu.exec_(QtGui.QCursor.pos())
# 如果鼠标点击的item相等于删除item,执行删除
if atum == delete_item:
del self.drew_line[self.selected_line_numble]
self.repaint()
>>效果展示:
6、完整代码
import sys
from PyQt5 import QtGui
from PyQt5.QtCore import QRect, QPoint, Qt
from PyQt5.QtGui import QPainter, QBrush, QPen, QColor
from PyQt5.QtWidgets import QWidget, QApplication, QMenu
class GraduatedRuler(QWidget):
def __init__(self):
super(GraduatedRuler, self).__init__()
self.gr_width = 800
self.gr_height = 500
self.width_rect = None # 左侧刻度尺的范围,是一个矩形,QRect类型
self.height_rect = None # 上边刻度尺的范围,是一个矩形,QRect类型
self.width_moveLine = False # 判断是否为左侧刻度尺被拉动
self.height_moveLine = False # 判断是否为上边刻度尺被拉动
self.right_click = False # 右键点击
self.selected_line_numble = -1
self.drawing_line = [] # 移动画线保存
self.drew_line = [] # 保存所有画线
self.setFixedSize(self.gr_width, self.gr_height)
# 绘图事件
def paintEvent(self, a0: QtGui.QPaintEvent):
super().paintEvent(a0)
painter = QPainter(self) # 画图
painter.setPen(QPen(QBrush(Qt.black), 1)) # 设置画笔
width = int(self.gr_width)
height = int(self.gr_height)
painter.drawLine(20, 0, 20, height) # 画一条左侧刻度尺线
painter.drawLine(0, 20, width, 20) # 画一条上边刻度尺线
self.width_rect = QRect(0, 40, 20, height) # 保存左侧刻度尺的范围
self.height_rect = QRect(40, 0, width, 20) # 保存上边刻度尺的范围
# 左侧刻度,每10像素为一个小刻度,每40像素为一个大刻度
for i in range(40, height, 10):
if i % 40 == 0:
painter.drawText(QPoint(2, i - 22), str(i))
painter.drawLine(0, i, 20, i)
else:
painter.drawLine(20, i, 15, i)
# 上边刻度,每10像素为一个小刻度,每40像素为一个大刻度
for i in range(40, width, 10):
if i % 40 == 0:
painter.drawText(QPoint(i + 5, 10), str(i))
painter.drawLine(i, 0, i, 20)
else:
painter.drawLine(i, 20, i, 15)
# 更换画笔样式
painter.setPen(QPen(QColor(74, 255, 255), 1, Qt.SolidLine))
# 绘制已保存的画线
if self.drew_line:
for line_norms in self.drew_line:
line = line_norms['line']
painter.drawLine(line[0], line[1], line[2], line[3])
# 绘制“移动画线”,实时显示
if self.drawing_line:
for line in self.drawing_line:
painter.drawLine(line[0], line[1], line[2], line[3])
# 鼠标按压事件
def mousePressEvent(self, a0: QtGui.QMouseEvent):
super().mousePressEvent(a0)
self.mStartPoint = a0.pos()
# 如果不是右键点击
if a0.buttons() != Qt.RightButton:
# 如果鼠标点击位置是否在左侧刻度尺范围
if self.width_rect.contains(self.mStartPoint):
self.width_moveLine = True
else:
self.width_moveLine = False
# 如果鼠标点击位置是否在上边刻度尺范围
if self.height_rect.contains(self.mStartPoint):
self.height_moveLine = True
else:
self.height_moveLine = False
# 将刻度线变成可移动状态
index = 0
for drew_line in self.drew_line:
norms = drew_line['norms']
line = drew_line['line']
# 将线变成矩形,利用contains函数判断点击位置是或否在刻度线范围
if norms == "width":
tmp_rect = QRect(line[0], line[1], 3, line[3])
else:
tmp_rect = QRect(line[0], line[1], line[2], 3)
if tmp_rect.contains(self.mStartPoint):
self.drawing_line.clear()
self.drawing_line.append(line)
if norms == "width":
self.width_moveLine = True
else:
self.height_moveLine = True
break
index += 1
# 可移动的原理是,将已保存的画线取出放到“移动画线”中,删除已保存画线,“移动画线”释放后会再次保存在保存列表中
if index != len(self.drew_line):
del self.drew_line[index]
else:
self.right_click = True
self.selected_line_numble = self.select_line(self.mStartPoint) # 判断是否选中刻度线,未选中:-1
# 判断是否选中刻度线
def select_line(self, mStartPoint):
for index, drew_line in enumerate(self.drew_line):
norms = drew_line['norms']
line = drew_line['line']
if norms == "width":
tmp_rect = QRect(line[0], line[1], 3, line[3])
else:
tmp_rect = QRect(line[0], line[1], line[2], 3)
if tmp_rect.contains(mStartPoint):
return index
return -1
# 鼠标移动事件
def mouseMoveEvent(self, a0: QtGui.QMouseEvent):
super().mouseMoveEvent(a0)
self.mMovePoint = a0.pos()
# 如果不是右键点击
if self.right_click is False:
if self.mStartPoint is not None:
# 如果是点击左侧刻度尺,把竖线保存在“移动画线”列表中,同一时间“移动画线”仅有一个
if self.width_moveLine is True:
self.drawing_line.clear()
self.drawing_line.append([self.mMovePoint.x(), 0, self.mMovePoint.x(), self.height()])
self.repaint()
# 如果是点击上边刻度尺,也把横线保存在“移动画线”列表中,同一时间“移动画线”仅有一个
if self.height_moveLine is True:
self.drawing_line.clear()
self.drawing_line.append([0, self.mMovePoint.y(), self.width(), self.mMovePoint.y()])
self.repaint()
# 鼠标施放事件
def mouseReleaseEvent(self, a0: QtGui.QMouseEvent):
super().mouseReleaseEvent(a0)
self.mReleasePoint = a0.pos()
# 如果不是右键点击
if self.right_click is False:
# 如果是点击左侧刻度尺,鼠标释放后就保存竖线
if self.width_moveLine is True:
for line in self.drawing_line:
self.drew_line.append({"norms": "width", "line": line})
self.repaint()
# 如果是点击上边刻度尺,鼠标释放后就保存横线
if self.height_moveLine is True:
for line in self.drawing_line:
self.drew_line.append({"norms": "height", "line": line})
self.repaint()
else:
# 若选中刻度线,鼠标右键展开策略
if self.selected_line_numble != -1:
self.right_click_strategy() # 右键策略
# 鼠标释放后,初始化动态状态
self.drawing_line.clear()
self.width_moveLine = False
self.height_moveLine = False
self.right_click = False
# 右键策略
def right_click_strategy(self):
popMenu = QMenu(self) # 动态菜单
# 添加删除功能
delete_item = popMenu.addAction(u"删除")
atum = popMenu.exec_(QtGui.QCursor.pos())
# 如果鼠标点击的item相等于删除item,执行删除
if atum == delete_item:
del self.drew_line[self.selected_line_numble]
self.repaint()
if __name__ == '__main__':
app = QApplication(sys.argv)
gr = GraduatedRuler()
gr.show()
sys.exit(app.exec_())