Python PyQt拖动控件对齐到网格的方法步骤
作者:@苏丶 发布时间:2022-05-04 19:25:00
实现如下需求:
在PyQt界面上有一个控件,实现其可任意拖动,且鼠标释放时自动对齐到网格。
1.控件任意拖动并对齐到网格
如下按钮(尺寸100×100),可任意拖动,释放时对齐到网格(网格尺寸100×100)
首先给出代码
from PyQt5.QtWidgets import QPushButton, QMainWindow, QApplication
class Button(QPushButton):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(100, 100)
self.pos1 = 0 # 用于拖动时的鼠标位置初始值
def mousePressEvent(self, QMouseEvent):
self.pos1 = QMouseEvent.screenPos()
def mouseReleaseEvent(self, QMouseEvent) -> None:
fx, fy = self.frameGeometry().x(), self.frameGeometry().y() # 相对父控件坐标
tx_index, ty_index = fx // 100 if fx > 99 else 0, fy // 100 if fy > 99 else 0
# 移动到网格上
self.mymove(tx_index, ty_index)
def mouseMoveEvent(self, QMouseEvent):
pos2 = QMouseEvent.screenPos()
tx = int(self.frameGeometry().x() + pos2.x() - self.pos1.x())
ty = int(self.frameGeometry().y() + pos2.y() - self.pos1.y())
self.move(tx, ty)
self.pos1 = pos2
def mymove(self, tx_index, ty_index):
self.move(tx_index * 100, ty_index * 100)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('按钮测试')
self.resize(500, 500)
self.btn = Button(self)
self.btn.setText('ABCD')
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
这里自定义Button类继承QPushButton类,因为我们需要重写鼠标移动的方法来实现所需功能。
要实现任意拖动,按钮必须跟随鼠标,于是我们重写mousePressEvent方法和mouseMoveEvent方法。
当我们按下鼠标时,触发mousePress事件,记录此刻光标位置;
当光标拖动时触发mouseMove事件,获取当前光标位置,计算与之前位置的x和y的差值,然后加到按钮的相对坐标上,获得按钮需要移动到的位置坐标;
调用move方法移动按钮;
更新pos1即按钮位置;
只要光标移动,就会触发mouseMove事件,就会不断移动按钮与更新按钮位置,在视觉上按钮就是在跟着光标任意拖动。
要实现鼠标释放时对齐到网格,需要重写mouseReleaseEvent方法,用来响应鼠标释放动作。
当鼠标释放时,立即读取按钮的当前相对坐标;
将按钮的坐标除以100用来获取其在网格上的位置,如果坐标小于0应令其等于0,同时0-99的坐标除以100也等于0,于是只要小于99就等于0;
然后调用自定义的mymove方法,在这个方法中,将网格位置换算到相对坐标,再调用move方法使其移动到网格。
2.进阶:双击控件使其移动到其他网格
移动并对齐到网格的功能已经在上一部分实现了,这里需要实现鼠标双击动作,首先给出代码
from PyQt5.QtWidgets import QPushButton, QMainWindow, QApplication
from PyQt5.QtCore import Qt
class Button(QPushButton):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(100, 100)
self.pos1 = 0 # 用于拖动时的鼠标位置初始值
self.x_index, self.y_index = 0, 0 # 记录按钮在网格上的位置
def mousePressEvent(self, QMouseEvent):
if QMouseEvent.buttons() == Qt.LeftButton:
print('左键按下')
self.pos1 = QMouseEvent.screenPos()
elif QMouseEvent.buttons() == Qt.RightButton:
print('右键按下')
self.pos1 = QMouseEvent.screenPos()
def mouseReleaseEvent(self, QMouseEvent) -> None:
print('鼠标释放')
fx, fy = self.frameGeometry().x(), self.frameGeometry().y() # 相对父控件坐标
tx_index, ty_index = fx // 100 if fx > 99 else 0, fy // 100 if fy > 99 else 0
# 移动到网格上
self.x_index, self.y_index = tx_index, ty_index
self.mymove(tx_index, ty_index)
def mouseDoubleClickEvent(self, QMouseEvent):
if QMouseEvent.buttons() == Qt.LeftButton:
print('左键双击')
self.x_index += 1
self.y_index += 1
self.mymove(self.x_index, self.y_index)
elif QMouseEvent.buttons() == Qt.RightButton:
print('右键双击')
def mouseMoveEvent(self, QMouseEvent):
if QMouseEvent.buttons() == Qt.LeftButton:
pos2 = QMouseEvent.screenPos()
tx = int(self.frameGeometry().x() + pos2.x() - self.pos1.x())
ty = int(self.frameGeometry().y() + pos2.y() - self.pos1.y())
self.move(tx, ty)
self.pos1 = pos2
def mymove(self, tx_index, ty_index):
self.move(tx_index * 100, ty_index * 100)
print(f'按钮移动到({tx_index}, {ty_index})')
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('按钮测试')
self.resize(500, 500)
self.btn = Button(self)
self.btn.setText('ABCD')
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
在这里多了一些实例属性,如self.x_index, self.y_index用来记录按钮在网格上的位置。
要实现双击动作,必须重写mouseDoubleClickEvent方法,在mouseDoubleClickEvent方法中,我们首先将self.x_index, self.y_index进行修改,以更改按钮要移动到的位置,然后调用mymove方法进行移动。
此外,代码还进行了左键与右键的判断,当左键进行操作时,按钮可以更改位置,右键操作时不可更改。
来源:https://blog.csdn.net/weixin_42147967/article/details/128486736
猜你喜欢
- 以前大家谈了很多有关打开数据库连接安全的问题,现在我再提出一种思路:使用activex dll来保护你的代码。(既可以不用为使用共享的加密软
- 引言分享一些用Python处理yaml和嵌套数据结构的的一些技巧,首先从修改yaml格式文件的问题出发,演变出了各个解决办法,又从最后的解决
- 问题: jsp中想要输出的中文被显示成“?” 解决方法 : 在eclipse-windows- preferences中 搜索jsp , E
- set oSQLServer =server.createobject("SQLDMO.SQLServer"
- 今天一个朋友给个需求: 来来 {'isOK': 1, 'isRunning': None, 'isE
- 微信小程序request请求后台接口php的实例详解后台php接口:http://www.vueyun.com/good/info没有处理数
- 本文实例讲述了Python二叉树的遍历操作。分享给大家供大家参考,具体如下:# coding:utf-8"""
- few-shot learning的采样Few-shot learning 基于任务对模型进行训练,在N-way-K-shot中,一个任务中
- 实例如下:/** * 将数值四舍五入后格式化. * * @pa
- 1、数据驱动介绍:@ddt.ddt(类装饰器,申明当前类使用ddt框架)@ddt.data(函数装饰器,用于给测试用例传递数据),支持传py
- DataFrame 是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。DataFrame 既有行
- 目前全球疫情仍然比较严重,为了能清晰地看到疫情爆发以来至现在全球疫情的变化趋势,我绘制了一张疫情变化地图。 废话不多说,先上图下面就来重点介
- python创建一个类很简单只需要定义它就可以了.class Cat: pass就像这样就可以了,通过创建子类我们可以继承他的父
- 一、概述OLAP的系统(即Online Aanalyse Process)一般用于系统决策使用。通常和数据仓库、数据分析、数据挖掘等概念联系
- 本文实例为大家分享了js实现全选取消效果的具体代码,供大家参考,具体内容如下<!DOCTYPE html><html la
- 熟悉SQL的人都知道,完成同一个任务,SQL可能有多种写法,但不同写法的查询性能可能会有天壤之别,本文列举出五个查询优化的方法,当然,优化的
- 数组:【重点1】implode(分隔,arr) 把数组值数据按指定字符连接起来例如:$arr=array('1','
- MySQL 5.0.16的乱码问题可以用下面的方法解决:1.设置phpMyAdminLanguage:Chinese simplified
- 帮网友小改了一下主题. 任务比较简单, 只是为一个三栏主题添加对 Widget 的支持而已,就先从这次简单的案例开始说吧.单侧边栏funct
- 大家有没有这种感觉,一到国庆、春节这种长假,抢火车票就非常困难?各大互联网公司都推出抢票服务,只要加钱给服务费就可以增加抢到票的几率。有些火