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


猜你喜欢
- 最近在学习python著名的绘图包matplotlib时发现,有时候图例等设置无法正常显示中文,于是就想把这个问题解决了。PS:本文仅针对W
- 如果MySQL服务器启用了二进制日志,你可以使用mysqlbinlog工具来恢复从指定的时间点开始 (例如,从你最后一次备份)直到现在或另一
- 1.简介celery(芹菜)是一个异步任务队列/基于分布式消息传递的作业队列。它侧重于实时操作,但对调度支持也很好。celery用于生产系统
- 编写一个prod()函数,可以接受一个list并利用reduce()求积。from functools import reducedef p
- 核心代码是 getCookie()部分,控制弹框的显示隐藏则在 created()中。<template> <div v-
- 我们首先来看下python的全部代码,大家可以直接复制后测试:#-*- encoding: utf-8 -*- import l
- 大家好,之前我们使用 WechatPCAPI 做了获取微信好友信息以及查看撤回消息,本文我们再使用 WechatPCAPI 来实现微信自动回
- 前言lambda是表达式,用于创建匿名函数,可以和filter、map、reduce配合使用。本文环境Python3.7。一、lambda表
- 检查所使用的语句是否标准 /* 标准SQL和T-SQL之间有很多区别——太多了,这里就不说了。还有,如果你在SQL Server上工作, 那
- 作者:做梦的人(小姐姐)出处:https://www.cnblogs.com/chongyou/1.所有元素都在PageElement下的.
- 进入智联招聘官网,在搜索界面输入‘数据分析师',界面跳转,按F12查看网页源码,点击network 选中XHR,然后刷新网
- 先看效果图 GY-85.py:#!/usr/bin/python3# -*- coding: utf-8 -*-import cursesf
- 这两个均是 python 的内建函数,通过读取控制台的输入与用户实现交互。但他们的功能不尽相同。举两个小例子。 >>> r
- 1.准备工作: 准备相关的软件(Eclipse除外,开源软件可以从官网下载)<1>.Microsoft SQL server 2
- 一、简单的多表联查(inner join,left join,right join)1、 两表联查user_table表department
- 现在看小说已经有了听书这个功能了,但是有时候你想看的书的听书功能收费,这时候可能大家就只能老老实实选择看或者付费听。(还能拿来练英语听力欸嘿
- 直接上代码了import smtplibmsg = MIMEMultipart()#构造附件1att1 = MIMEText(open(
- 一、生成日期数据import pandas as pdpd.date_range( )同生成随机数的思想类似,使用pandas库中的函数pd
- 独立 fmt Log输出重定向golang的fmt包的输出函数 Println、Printf、PrintStack等,默认将打印输出到os.
- (本章节主要是一些python的基础语法,具体内容不够详细,以pycharm下调试产生的部分代码为主)(python语法的详细内容请参考官方