Qt支持程序多点触控,就想使用PyQt5做一个触控画板,经过几番周折,查阅了TouchEvent官方文档,又参考了一篇QT for Android的例子,采用eventfilter过滤器来识别触屏事件和鼠标事件,分别作出处理;

其中鼠标事件(用鼠标绘画)固定宽度,触摸事件呢(触摸屏上绘画)采用ellipseDiameters()获取触摸点的宽度,作为笔触宽度。

具体代码见:GitHub

  1. import sys
  2. import math
  3. from PyQt5.QtWidgets import QApplication, QWidget, QDesktopWidget
  4. from PyQt5.QtGui import QPainter, QPixmap, QPen, QTouchEvent, QColor, QMouseEvent
  5. from PyQt5.QtCore import Qt, QPoint, QEvent, QCoreApplication, QPointF, QLineF
  6. import logging
  7.  
  8. logger = logging.getLogger(__name__)
  9. logger.setLevel(logging.DEBUG)
  10. ch = logging.StreamHandler()
  11. formatter = logging.Formatter('%(levelname)s - %(message)s')
  12. ch.setFormatter(formatter)
  13. logger.addHandler(ch)
  14.  
  15. class Winform(QWidget):
  16. def __init__(self, parent=None):
  17. super(Winform, self).__init__(parent)
  18. # self.setWindowTitle("绘图例子")
  19. self.lastPoint_t = QPointF() # 触屏点前一点
  20. self.endPoint_t = QPointF() # 触屏点后一点
  21. self.lastPoint_m = QPointF() # 鼠标点前一点
  22. self.endPoint_m = QPointF() # 鼠标点后一点
  23.  
  24. self.eraser_width = 30 # 黑板擦默认宽度
  25.  
  26. self.pix = QPixmap() # 画布
  27. self.penWidth_t = 1; # 触摸笔画的原始粗细,会随触点粗细变化
  28. self.penWidth_m = 5; # 鼠标点的粗细固定
  29.  
  30. self.pen = QPen(Qt.black, 6, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) # 画笔
  31. self.pen.setColor(QColor(0, 0, 0)) # 设置初始颜色
  32. self.cp = QDesktopWidget().availableGeometry() # 分辨率
  33. self.init()
  34.  
  35. def init(self):
  36.  
  37. self.setEnabled(True)
  38. # 设置接受触摸屏
  39. self.setAttribute(Qt.WA_AcceptTouchEvents, True)
  40. QCoreApplication.setAttribute(Qt.AA_SynthesizeTouchForUnhandledMouseEvents, True) # 禁用将触摸事件转为鼠标事件
  41. QCoreApplication.setAttribute(Qt.AA_SynthesizeMouseForUnhandledTouchEvents, True)
  42. # 窗口大小设置为800*600
  43. self.resize(self.cp.width() * 0.9, self.cp.height() * 0.9)
  44. self.setWindowOpacity(0.7) # 设置透明度
  45.  
  46. # 画布大小为400*400,背景为白色
  47. self.pix = QPixmap(self.cp.width(), self.cp.height())
  48.  
  49. self.pix.fill(Qt.white)
  50.  
  51. self.pp = QPainter(self.pix)
  52. self.pp.setPen(self.pen)
  53.  
  54. self.lines = []
  55.  
  56. def paintEvent(self):
  57. # logger.debug('开始绘制')
  58. # 根据鼠标指针前后两个位置绘制直线
  59. distance = int(
  60. math.sqrt(
  61. (self.lastPoint_m.x() - self.endPoint_m.x()) ** 2 + (
  62. self.lastPoint_m.y() - self.endPoint_m.y()) ** 2)) + 1
  63.  
  64. # print('distance', distance)
  65. distance = math.sqrt(distance)
  66. if distance > 6:
  67. distance = 6
  68. elif distance < 4:
  69. distance = 4;
  70. # self.pen.setWidthF(25 / distance) # 笔宽与距离成反比
  71. self.pen.setWidthF(self.penWidth_m) # 采用触摸点大小作为笔宽
  72. self.pp.setPen(self.pen)
  73. self.pp.drawLine(self.lastPoint_m, self.endPoint_m)
  74. # self.pix.save('1.png') # 保存图片
  75.  
  76. # self.pp.drawPoints(self.lastPoint,self.endPoint)
  77. self.lastPoint_m = self.endPoint_m
  78.  
  79. painter = QPainter(self)
  80. painter.setPen(self.pen)
  81. painter.drawPixmap(0, 0, self.pix)
  82. # print('画在窗体上')
  83.  
  84. def paintTouchEvent(self):
  85.  
  86. # 根据鼠标指针前后两个位置绘制直线
  87. distance = int(
  88. math.sqrt(
  89. (self.lastPoint_t.x() - self.endPoint_t.x()) ** 2 + (
  90. self.lastPoint_t.y() - self.endPoint_t.y()) ** 2)) + 1
  91.  
  92. print('distance', distance)
  93. distance = math.sqrt(distance)
  94. if distance > 6:
  95. distance = 6
  96. elif distance < 4:
  97. distance = 4;
  98. # self.pen.setWidthF(18 / distance)
  99. self.pen.setWidthF(self.penWidth_t) # 采用触摸点大小作为笔宽
  100. if self.penWidth_t > self.eraser_width:
  101. self.pen.setColor(Qt.white)
  102. else:
  103. self.pen.setColor(Qt.black)
  104. self.pp.setPen(self.pen)
  105.  
  106. self.pp.drawLine(self.lastPoint_t, self.endPoint_t)
  107. # self.pix.save('1.png') # 保存图片
  108.  
  109. # self.pp.drawPoints(self.lastPoint,self.endPoint)
  110.  
  111. painter = QPainter(self)
  112. painter.setPen(self.pen)
  113. painter.drawPixmap(0, 0, self.pix)
  114. # print('画在窗体上')
  115.  
  116. def mousePressEvent(self, event):
  117. # 鼠标左键按下
  118. if event.button() == Qt.LeftButton:
  119. # print('左键按下')
  120. self.lastPoint_m = event.pos()
  121. self.endPoint_m = self.lastPoint_m
  122.  
  123. def mouseMoveEvent(self, event):
  124. # 鼠标左键按下的同时移动鼠标
  125. # print(QEvent.TouchBegin)
  126.  
  127. if event.buttons() and Qt.LeftButton:
  128. self.endPoint_m = event.pos()
  129. # 进行重新绘制
  130. print('鼠标事件源', event.source())
  131. self.update()
  132.  
  133. def mouseReleaseEvent(self, event):
  134. # 鼠标左键释放
  135. if event.button() == Qt.LeftButton:
  136. self.endPoint_m = event.pos()
  137. # 进行重新绘制
  138. self.update()
  139.  
  140. def eventFilter(self, watched, event):
  141. '''
  142. 事件过滤器
  143. :param watched: 监听到的对象
  144. :param event: 事件
  145. :return: 符合条件的事件单独处理,否则交给父类处理
  146. '''
  147. # print(type(watched))
  148. if watched == form:
  149.  
  150. if event.type() == QEvent.TouchBegin:
  151. pass
  152. if event.type() == QEvent.TouchUpdate or event.type() == QEvent.TouchEnd:
  153. # print('触点开始', QTouchEvent(event).touchPoints())
  154. # logger.debug('TouchEvent,触摸点个数:')
  155. self.addline(QTouchEvent(event))
  156. return True
  157. if event.type() == QEvent.MouseButtonDblClick or event.type() == QEvent.MouseMove or event.type() == QEvent.MouseButtonRelease or event.type() == QEvent.MouseButtonPress:
  158.  
  159. mouse_event = QMouseEvent(event)
  160. # logger.debug('鼠标事件!event类型:', event.type())
  161. if mouse_event != None and mouse_event.source() == Qt.MouseEventSynthesizedBySystem:
  162. # 鼠标事件存在并且是有系统将触摸事件整合过来的
  163. # logger.debug('触屏事件合成鼠标事件!event类型:', event.type())
  164. #
  165. # self.addline(QTouchEvent(event))
  166. # mouse_event.ignore()
  167. # return True
  168. pass
  169. if event.type() == QEvent.Paint:
  170. # logger.debug('PaintEvent')
  171. self.paintEvent()
  172. # self.update()
  173. return True
  174. return QWidget.eventFilter(self, watched, event) # 其他情况会返回系统默认的事件处理方法。
  175.  
  176. def addline(self, event):
  177. '''
  178. 获取触摸点
  179. :param event: 触摸事件对象
  180. :return:
  181. '''
  182. logger.debug('获取触摸点!')
  183. touchPoints = event.touchPoints()
  184. for point in touchPoints:
  185. # print(point.ellipseDiameters().width())
  186. self.penWidth_t = point.ellipseDiameters().width()
  187. # logger.debug('触摸点的直径:', self.penWidth_t)
  188.  
  189. self.lastPoint_t = point.lastPos()
  190. self.endPoint_t = point.pos()
  191. self.paintTouchEvent() # 手动调绘图事件
  192. self.update() #
  193.  
  194. def keyPressEvent(self, event):
  195. if event.key() == Qt.Key_C:
  196. self.pix.fill(Qt.white)
  197. self.update()
  198. elif event.key() == Qt.Key_Escape:
  199. self.close()
  200.  
  201. if __name__ == "__main__":
  202. app = QApplication(sys.argv)
  203. form = Winform()
  204. app.installEventFilter(form) # 监听form的所有事件
  205. form.show()
  206. form.showFullScreen()
  207. sys.exit(app.exec_())

  

我的困惑:系统默认会把单点触控事件转为鼠标事件,即一点触控就是再用鼠标绘画,这样获取不到鼠标的宽度,就不能自动设置笔画粗细,采用各种方法尝试之后仍无效!

上图中黑板擦的实现加了一点作弊,原来的黑板擦会把识别为鼠标,所以在擦的过程中,我的另一只手指按住屏幕,这时候黑板擦再擦时就被认为是黑板擦(检测触摸点的宽度)

这种方法并不适用,用没有其他方法能避免将单点触控转换为鼠标左键呢?

PyQt5多点触控写字板实现及困惑的更多相关文章

  1. [示例] Firemonkey OnTouch 多点触控应用

    说明:Firemonkey OnTouch 多点触控应用,可同时多指移动多个不同控件 原码下载:[原创]TestMultitouchMove_多点触控应用_by_Aone.zip 运行展示:

  2. ccc 多点触控2

    经过不断的思考发现,如果是两个sprite都添加触控的时候,往往直接成单点触控, 但是如果是两个node的时候在node上面点击就会变成多点触控的形式 cc.Class({ extends: cc.C ...

  3. ccc 多点触控

    研究了一天,多点触控的点无法保存,只能模拟多点触控了 cc.Class({ extends: cc.Component, properties: { wheelStick:{ default:null ...

  4. Cocos2dx 多点触控

    1 最容易忽略的东西,对于ios平台,须得设置glView的属性: [__glView setMultipleTouchEnabled:YES]; 2 如果调用CCLayer的方法setTouchEn ...

  5. Android 多点触控与简单手势(一)

    现在一般的Android手机都会使用电容触摸屏最少可以支持两点触摸,多的可能是七八个,所以基本上都会支持多点触控, android系统中应用程序可以使用多点触控的事件来完成各种手势和场景需求. And ...

  6. Android多点触控技术实战,自由地对图片进行缩放和移动

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11100327 在上一篇文章中我带着大家一起实现了Android瀑布流照片墙的效果, ...

  7. MultiTouch————多点触控,伸缩图片,变换图片位置

    前言:当今的手机都支持多点触控功能(可以进行图片伸缩,变换位置),但是我们程序员要怎样结合硬件去实现这个功能呢? 跟随我一起,来学习这个功能 国际惯例:先上DEMO免费下载地址:http://down ...

  8. windows8 开发教程 教你制作 多点触控Helper可将任意容器内任意对象进行多点缩放

    http://blog.csdn.net/wangrenzhu2011/article/details/7732907 (转) 实现方法: 对Manipulation进行抽象化 使不同容器可共用多点缩 ...

  9. cocos2d-x 在xcode IOS模拟器中 开启IOS多点触控

    在初始化代码中,开启当前层接受触摸 this->setTouchEnabled(true); 在AppController.mm文件中,设置开启多点触控 在- (BOOL)application ...

随机推荐

  1. 跨域资源共享 CORS 详解(转)

    add by zhj: 公司在一个web产品上,做前后端分离,前后端提供独立的服务,使用不同的域名,通过http进行交互,在 前端,会涉及到跨域访问的问题,前端使用了CORS,后端同时需要做相应修改, ...

  2. 小白的.Net Core 2.0 ConsoleApp入门(keng)指南(一)

    一.准备工作 准备工作很简单,甚至可以不用Visual Studio,一只.NET CORE和Runtime即可(你有考虑过世界第一IDE的感受吗) 下载:https://www.microsoft. ...

  3. Mysql高可用架构(主从同步)

    做高可用的优势 1.成本低 2.解决单点故障 3.不容易遇到性能瓶颈 一 .Mysql主从同步架构搭建案例 优点如下:·在业务繁忙阶段,在从服务器上可以执行查询工作(即我们常说的读写分离),降低主服务 ...

  4. Sizeof的三种作用

    一.计算常量占用的字节数 例如:int num=sizeof(10); printf("%i",num); 二.计算变量占用的字节数 例如:int num2=3; int resu ...

  5. Python函数可变参数*args及**kwargs详解

    初学Python的同学们看到代码中类似func(*args, **kwargs)这样的函数参数定义时,经常感到一头雾水. 下面通过一个简单的例子来详细解释下Python函数可变参数*args及**kw ...

  6. Spring源码情操陶冶-DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

    前言-阅读源码有利于陶冶情操,本文承接前文Spring源码情操陶冶-AbstractApplicationContext#obtainFreshBeanFactory 前文提到最关键的地方是解析bea ...

  7. [Sdoi2017]新生舞会 [01分数规划 二分图最大权匹配]

    [Sdoi2017]新生舞会 题意:沙茶01分数规划 貌似\(*10^7\)变成整数更科学 #include <iostream> #include <cstdio> #inc ...

  8. Python tutorial阅读之Python基本运算与基本变量

    将 Python 当做计算器 除法运算 用/表示除法运算时,一般得到的是浮点数,如果我们需要得到整数,可以用运算符// 余数计算 % 幂乘方 系统内置变量_ 内置变量_,存储了最近的结果.如图 字符串 ...

  9. 应用负载均衡之LVS(一):基本概念和三种模式

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  10. VS2012编译log4cpp1.1.1版本

    1.起因 看到官方网站上的log4cpp的代码已经更新到了1.1.1,而我目前使用的1.0.3版本,所以想使用下最新版本.在使用过程中发现相对于老版本,新版本的变化还是比较大的,特写下此文记录下. 2 ...