0.目錄 1. "前言" 2. "簡單的畫板1.0" 在定點和移動中的滑鼠所在處畫一條線 3. "簡單的畫板2.0" 在定點和移動中的滑鼠所在處畫一條線 並將畫過的線都保留在窗體上 4. "簡單的畫板3.0" 將按住滑鼠後移動的軌跡保留在窗體上 5. "簡單的畫板4.0" 將按住滑鼠後移動的軌跡保留 ...
0.目錄
1.前言
2.簡單的畫板1.0
- 在定點和移動中的滑鼠所在處畫一條線
3.簡單的畫板2.0
- 在定點和移動中的滑鼠所在處畫一條線
- 並將畫過的線都保留在窗體上
4.簡單的畫板3.0
- 將按住滑鼠後移動的軌跡保留在窗體上
5.簡單的畫板4.0
- 將按住滑鼠後移動的軌跡保留在窗體上
- 並解決二次作畫時與上次痕跡連續的問題
1.前言
版本:Python3.6.1 + PyQt5
寫一個程式的時候需要用到畫板/手寫板,只需要最簡單的那種。原以為網上到處都是,結果找了好幾天,都沒有找到想要的結果。
網上的要麼是非python版的qt程式(要知道qt版本之間差異巨大,還是非同一語言的),改寫難度太大。要麼是PyQt4的老程式,很多都已經不能在PyQt5上運行了。要麼是大神寫的特別複雜的程式,簡直是直接做出了一個Windows自帶的畫圖版,只能膜拜~
於是我只能在眾多代碼中慢慢尋找自己需要的那一小部分,然後不斷地拼湊,不斷地理解大神的代碼,最終做出這麼一個簡單的畫板。望著這個簡單的畫板我真是淚流滿面,中間數十次拼不對拼不全導致程式無數次崩潰,差點就放棄了......
以下是參考網站的名單(名單不分先後順序):
1.PyQt5教程(九)——繪圖https://my.oschina.net/wisedream/blog/549989
2.Qt入門 小程式之畫圖板http://blog.csdn.net/doraemon___/article/details/53026890
3.使用Python編寫簡單的畫圖板程式的示例教程http://www.jb51.net/article/76067.htm
4.qt中函數paintEvent(QPaintEvent*)是不是被系統自動調用的https://zhidao.baidu.com/question/1509518984399472660.html
5.從Qt到PyQthttp://www.cnblogs.com/Finley/p/5268861.html
6.python3+PyQt5 重新實現QT事件處理程式http://blog.sina.com.cn/s/blog_c22e36090102wzxq.html
7.PyQt5入門http://www.docin.com/p-1560265564.html
8.PyQt5教程(一)——第一個PyQt5程式https://my.oschina.net/wisedream/blog/536052
9.PyQt之佈局&無邊框&信號http://www.cnblogs.com/codeAB/p/5019439.html
10.QT界面簡單的圖形移動和滑鼠繪圖http://blog.csdn.net/K54387/article/details/77926313
11.qt滑鼠事件總結(轉)http://blog.sina.com.cn/s/blog_8b97b05e0100v6kk.html
12.一個簡單的畫圖程式http://blog.csdn.net/cutter_point/article/details/43087497
13.Qt雙緩衝機制:實現一個簡單的繪圖工具(純代碼實現)http://blog.csdn.net/rl529014/article/details/51658350
2.簡單的畫板1.0
在簡單的畫板1.0這裡,實現的功能是:在定點和移動中的滑鼠所在處畫一條線
如圖所示:
滑鼠按住移動的話,線也會跟著移動,從這個簡單的程式開始理解PyQt5的運行機制吧。
'''
簡單的畫板1.0
功能:在定點和移動中的滑鼠所在處畫一條線
作者:PyLearn
博客: http://www.cnblogs.com/PyLearn/
最後修改日期: 2017/10/18
'''
import sys
from PyQt5.QtWidgets import (QApplication, QWidget)
from PyQt5.QtGui import (QPainter, QPen)
from PyQt5.QtCore import Qt
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
#resize設置寬高,move設置位置
self.resize(400, 300)
self.move(100, 100)
self.setWindowTitle("簡單的畫板1.0")
#setMouseTracking設置為False,否則不按下滑鼠時也會跟蹤滑鼠事件
self.setMouseTracking(False)
#設置兩個變數接收移動中的點的x、y坐標
self.pos_x = 20
self.pos_y = 20
def paintEvent(self, event):
painter = QPainter()
painter.begin(self)
pen = QPen(Qt.black, 2, Qt.SolidLine)
painter.setPen(pen)
#定點(20, 20) 到 (self.pos_x, self.pos_y)之間畫線
painter.drawLine(20, 20, self.pos_x, self.pos_y)
painter.end()
def mouseMoveEvent(self, event):
'''
按住滑鼠移動事件:更新pos_x和pos_y的值
調用update()函數在這裡相當於調用paintEvent()函數
每次update()時,之前調用的paintEvent()留下的痕跡都會清空
'''
self.pos_x = event.pos().x()
self.pos_y = event.pos().y()
self.update()
if __name__ == "__main__":
app = QApplication(sys.argv)
pyqt_learn = Example()
pyqt_learn.show()
app.exec_()
3.簡單的畫板2.0
從以上的簡單的畫板1.0程式的運行可以發現,按住滑鼠移動的時候,線也會跟著移動,那如何讓之前的線留下痕跡,而不是消失呢?
在簡單的畫板2.0中,使用一個列表保存所有移動過的點,然後要畫線的時候,迴圈遍歷列表,依次畫出列表中點到定點之間的線即可。
效果如圖所示:
'''
簡單的畫板2.0
功能:
在定點和移動中的滑鼠所在處畫一條線
並將畫過的線都保留在窗體上
作者:PyLearn
博客: http://www.cnblogs.com/PyLearn/
最後修改日期: 2017/10/18
'''
import sys
from PyQt5.QtWidgets import (QApplication, QWidget)
from PyQt5.QtGui import (QPainter, QPen)
from PyQt5.QtCore import Qt
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
#resize設置寬高,move設置位置
self.resize(400, 300)
self.move(100, 100)
self.setWindowTitle("簡單的畫板2.0")
#setMouseTracking設置為False,否則不按下滑鼠時也會跟蹤滑鼠事件
self.setMouseTracking(False)
'''
要想將畫過的線都保留在窗體上
需要一個列表來保存所有移動過的點
'''
self.pos_xy = []
def paintEvent(self, event):
painter = QPainter()
painter.begin(self)
pen = QPen(Qt.black, 2, Qt.SolidLine)
painter.setPen(pen)
#迴圈遍歷self.pos_xy中每個點,然後畫點到定點之間的線
for pos_tmp in self.pos_xy:
painter.drawLine(20, 20, pos_tmp[0], pos_tmp[1])
painter.end()
def mouseMoveEvent(self, event):
'''
按住滑鼠移動事件:將當前點添加到pos_xy列表中
調用update()函數在這裡相當於調用paintEvent()函數
每次update()時,之前調用的paintEvent()留下的痕跡都會清空
'''
#中間變數pos_tmp提取當前點
pos_tmp = (event.pos().x(), event.pos().y())
#pos_tmp添加到self.pos_xy中
self.pos_xy.append(pos_tmp)
self.update()
if __name__ == "__main__":
app = QApplication(sys.argv)
pyqt_learn = Example()
pyqt_learn.show()
app.exec_()
4.簡單的畫板3.0
好了,接下來進入正題了。簡單的畫板2.0不過是畫滑鼠所在點到定點的線,那麼如何將按住滑鼠後移動的軌跡保留在窗體上?
這個就需要一個列表來保存所有移動過的點,然後把所有相鄰兩個點之間都畫一條線,就能斷斷續續連成滑鼠的痕跡了。
效果如圖所示:
是不是就畫出滑鼠移動的軌跡了!
不過這也是有缺點的,比如說寫個5看看:
硬生生變成了一個5不是5, 6不是6的數字。這是因為再次提筆畫時,5上面的那一橫跟之前畫的尾巴那裡連起來了。好好想想,這個問題怎麼解決呢?
'''
簡單的畫板3.0
功能:將按住滑鼠後移動的軌跡保留在窗體上
作者:PyLearn
博客: http://www.cnblogs.com/PyLearn/
最後修改日期: 2017/10/18
'''
import sys
from PyQt5.QtWidgets import (QApplication, QWidget)
from PyQt5.QtGui import (QPainter, QPen)
from PyQt5.QtCore import Qt
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
#resize設置寬高,move設置位置
self.resize(400, 300)
self.move(100, 100)
self.setWindowTitle("簡單的畫板3.0")
#setMouseTracking設置為False,否則不按下滑鼠時也會跟蹤滑鼠事件
self.setMouseTracking(False)
'''
要想將按住滑鼠後移動的軌跡保留在窗體上
需要一個列表來保存所有移動過的點
'''
self.pos_xy = []
def paintEvent(self, event):
painter = QPainter()
painter.begin(self)
pen = QPen(Qt.black, 2, Qt.SolidLine)
painter.setPen(pen)
'''
首先判斷pos_xy列表中是不是至少有兩個點了
然後將pos_xy中第一個點賦值給point_start
利用中間變數pos_tmp遍歷整個pos_xy列表
point_end = pos_tmp
畫point_start到point_end之間的線
point_start = point_end
這樣,不斷地將相鄰兩個點之間畫線,就能留下滑鼠移動軌跡了
'''
if len(self.pos_xy) > 1:
point_start = self.pos_xy[0]
for pos_tmp in self.pos_xy:
point_end = pos_tmp
painter.drawLine(point_start[0], point_start[1], point_end[0], point_end[1])
point_start = point_end
painter.end()
def mouseMoveEvent(self, event):
'''
按住滑鼠移動事件:將當前點添加到pos_xy列表中
調用update()函數在這裡相當於調用paintEvent()函數
每次update()時,之前調用的paintEvent()留下的痕跡都會清空
'''
#中間變數pos_tmp提取當前點
pos_tmp = (event.pos().x(), event.pos().y())
#pos_tmp添加到self.pos_xy中
self.pos_xy.append(pos_tmp)
self.update()
if __name__ == "__main__":
app = QApplication(sys.argv)
pyqt_learn = Example()
pyqt_learn.show()
app.exec_()
5.簡單的畫板4.0
簡單的畫板3.0中有一個致命的問題,那就是連續的問題,比如說要寫一個三位數123:
很難看對不對?
解決這個問題的方法應該是有很多種的,我也沒有深入想,就直接用了這個麻煩點的方法。
我的辦法是當滑鼠按住移動然後鬆開的時候,往保存所有移動過的點的列表中添加一個斷點(-1, -1)。然後在每次畫線的時候,都判斷一下是不是斷點,如果是斷點的話就想辦法跳過去,並且不連續的開始接著畫線。
效果如圖所示:
以下是具體實現代碼:
'''
簡單的畫板4.0
功能:
將按住滑鼠後移動的軌跡保留在窗體上
並解決二次作畫時與上次痕跡連續的問題
作者:PyLearn
博客: http://www.cnblogs.com/PyLearn/
最後修改日期: 2017/10/18
'''
import sys
from PyQt5.QtWidgets import (QApplication, QWidget)
from PyQt5.QtGui import (QPainter, QPen)
from PyQt5.QtCore import Qt
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
#resize設置寬高,move設置位置
self.resize(400, 300)
self.move(100, 100)
self.setWindowTitle("簡單的畫板4.0")
#setMouseTracking設置為False,否則不按下滑鼠時也會跟蹤滑鼠事件
self.setMouseTracking(False)
'''
要想將按住滑鼠後移動的軌跡保留在窗體上
需要一個列表來保存所有移動過的點
'''
self.pos_xy = []
def paintEvent(self, event):
painter = QPainter()
painter.begin(self)
pen = QPen(Qt.black, 2, Qt.SolidLine)
painter.setPen(pen)
'''
首先判斷pos_xy列表中是不是至少有兩個點了
然後將pos_xy中第一個點賦值給point_start
利用中間變數pos_tmp遍歷整個pos_xy列表
point_end = pos_tmp
判斷point_end是否是斷點,如果是
point_start賦值為斷點
continue
判斷point_start是否是斷點,如果是
point_start賦值為point_end
continue
畫point_start到point_end之間的線
point_start = point_end
這樣,不斷地將相鄰兩個點之間畫線,就能留下滑鼠移動軌跡了
'''
if len(self.pos_xy) > 1:
point_start = self.pos_xy[0]
for pos_tmp in self.pos_xy:
point_end = pos_tmp
if point_end == (-1, -1):
point_start = (-1, -1)
continue
if point_start == (-1, -1):
point_start = point_end
continue
painter.drawLine(point_start[0], point_start[1], point_end[0], point_end[1])
point_start = point_end
painter.end()
def mouseMoveEvent(self, event):
'''
按住滑鼠移動事件:將當前點添加到pos_xy列表中
調用update()函數在這裡相當於調用paintEvent()函數
每次update()時,之前調用的paintEvent()留下的痕跡都會清空
'''
#中間變數pos_tmp提取當前點
pos_tmp = (event.pos().x(), event.pos().y())
#pos_tmp添加到self.pos_xy中
self.pos_xy.append(pos_tmp)
self.update()
def mouseReleaseEvent(self, event):
'''
重寫滑鼠按住後鬆開的事件
在每次鬆開後向pos_xy列表中添加一個斷點(-1, -1)
然後在繪畫時判斷一下是不是斷點就行了
是斷點的話就跳過去,不與之前的連續
'''
pos_test = (-1, -1)
self.pos_xy.append(pos_test)
self.update()
if __name__ == "__main__":
app = QApplication(sys.argv)
pyqt_learn = Example()
pyqt_learn.show()
app.exec_()
至此,終於完成了簡單的畫板程式的實現!
另外,如果在使用這個代碼的過程中有遇到什麼問題,也歡迎向我反饋。