網站首頁 編程語言 正文
實現如下需求:
在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
相關推薦
- 2022-11-15 python運行cmd命令行的3種方法總結_python
- 2022-09-08 redis?lua限流算法實現示例_Redis
- 2022-05-04 詳解Tomcat中查看JVM內存使用情況_Tomcat
- 2022-03-30 Docker?鏡像分層及dockerfile?編寫技巧_docker
- 2022-10-22 C#抽象類的用法介紹_實用技巧
- 2022-06-23 Python+Turtle制作獨特的表白圖_python
- 2021-11-17 Linux配置免密登錄單機和全分布詳細教程_Linux
- 2022-04-28 Python的命令行參數實例詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支