2016-04-02 4 views
0

私は、Python3とPyQt5をOSXに搭載したティータイマー用の簡単なアプリを開発しています。審美的な理由から私は窓フレームを取り除くことにしました。ウィンドウを移動可能に保つために、私はmousePressEvent()およびmouseMoveEvent()ハンドラをオーバーロードしました。PyQt5 Appを移動する - QPushButtonの問題

しかし、マウスがボタンの1つ(QPushButton())の上に移動しているときに、ウィンドウが移動しているときに問題が発生します。カーソルが最後のクリック位置にジャンプし、そこからウィンドウが移動します。誰がなぜこれが起こっているのかについてのアイデアはありますか?興味深いことに、同じ問題がクリックしQLabel()オブジェクトの上に移動したときに表示されません...

あなたはそれを試してみたい場合は、ここでのサンプルコードは、次のとおりです。

#!/usr/bin/python3 
# -*- coding: utf-8 -*- 

## =============================================================== 
## IMPORTS 

from PyQt5.QtCore import * 
from PyQt5.QtWidgets import * 
from PyQt5.QtGui import * 


## =============================================================== 
## CONSTANTS 

WINDOW_WIDTH = 690 
WINDOW_HEIGHT = 435 


## =============================================================== 
## CLASSES 


class Form(QWidget): 
    def __init__(self, parent=None): 
     super().__init__() 

     self.windowPos = QPoint()  # Maybe not necessary when button click and window movement are seperated 

     # Declare and specify UI elements 
     self.timerLabel = QLabel("00:00")  # Might have to change data type here 
     self.timerLabel.setObjectName("timerLabel") 

     self.infoLabel = QLabel("No tea selected") 
     self.infoLabel.setObjectName("infoLabel") 

     self.teaOneButton = QPushButton("Tea One") 
     self.teaOneButton.setObjectName("teaOneButton") 

     self.teaTwoButton = QPushButton("Tea Two") 
     self.teaTwoButton.setObjectName("teaTwoButton") 

     # Arrange UI elements in a layout 
     grid = QGridLayout() 
     self.setLayout(grid)  # Set the QGridLayout as the window's main layout 
     grid.setSpacing(0)  # Spacing between widgets - does not work if window is resized 
     grid.setContentsMargins(4, 4, 4, 4) 
     grid.addWidget(self.timerLabel, 0, 0, 1, -1, Qt.AlignHCenter)  # http://doc.qt.io/qt-5/qgridlayout.html#addWidget 
     grid.addWidget(self.infoLabel, 1, 0, 1, -1, Qt.AlignHCenter) 
     grid.addWidget(self.teaOneButton, 2, 0) 
     grid.addWidget(self.teaTwoButton, 2, 1) 

     self.resize(WINDOW_WIDTH, WINDOW_HEIGHT) 


    # Arranging window in center of the screen by overloading showEvent method 
    def showEvent(self, QShowEvent): 
     self.centerOnScreen() 


    def centerOnScreen(self): 
     screen = QDesktopWidget() 
     screenGeom = QRect(screen.screenGeometry(self)) 

     screenCenterX = screenGeom.center().x() 
     screenCenterY = screenGeom.center().y() 

     self.move(screenCenterX - self.width()/2, 
          screenCenterY - self.height()/2) 


    # Overload mouseEvent handlers to make window moveable 
    def mousePressEvent(self, QMouseEvent): 
     self.windowPos = QMouseEvent.pos() 
     self.setCursor(QCursor(Qt.SizeAllCursor)) 


    def mouseReleaseEvent(self, QMouseEvent): 
     self.setCursor(QCursor(Qt.ArrowCursor)) 


    def mouseMoveEvent(self, QMouseEvent): 
     # print (self.childAt(QMouseEvent.pos()) == QLabel) 
     pos = QPoint(QMouseEvent.globalPos()) 
     self.window().move(pos - self.windowPos) 



## =============================================================== 
## MAIN LOOP 

if __name__ == '__main__': 
    import sys 

    app = QApplication(sys.argv) 

    screen = Form() 
    screen.setWindowFlags(Qt.FramelessWindowHint) 
    screen.show() 

    sys.exit(app.exec_()) 

答えて

0
from PyQt5.QtCore import * 
from PyQt5.QtWidgets import * 
from PyQt5.QtGui import * 

あなたがいますインポートされたメンバーからの名前空間の衝突がないことを確認しますか?

+0

これはあなた自身で実際にテストしましたか? – ekhumoro

+0

私はまだありません。私は最後の行(PyQt5.QtGui import *から)を使わずに行くことができるので、それを狭めることができます...ここで何が起こっていると思いますか? – Michael

+0

QPushButtonはQWidget {http://doc.qt.io/qt-5/qwidget.html}のサブクラスであり、QPushButtonはQtGui {http://pyqt.sourceforge.net/Docsのクラスメンバーです/PyQt4/qpushbutton.html}、私の最初の質問です。 QtGuiを削除してみて、何が起こるか見てみましょう! –

0

私は、この問題を回避する方法を見つけた可能性があります。

QPushButtonsがmouseMoveEventsを、たとえばQLabelオブジェクトとは異なる方法で処理するという問題があるようです。私にとっては、ボタンオブジェクトは、他のクリック不可能なオブジェクトとは異なるマウスイベント処理を必要とするかもしれないので直感的に意味があります。

私がしたことは、mouseMoveEventハンドラをオーバーロードするQPushButtonのサブクラスを実装しようとしたことでした。最初は、親ウィジェットに委譲するためにイベントを無視するようにハンドラーを設定すると考えました。それは何も変わらなかった。それは実際には何かが起こっているかもしれません。なぜなら、イベント処理関数にある種のコードを実装すると、ボタンはウィンドウ移動のソースとして機能しなくなるからです。

#!/usr/bin/python3 
# -*- coding: utf-8 -*- 

## =============================================================== 
## IMPORTS 

from PyQt5.QtCore import * 
from PyQt5.QtWidgets import * 
from PyQt5.QtGui import * 


## =============================================================== 
## CONSTANTS 

WINDOW_WIDTH = 690 
WINDOW_HEIGHT = 435 


## =============================================================== 
## CLASSES 

class UnmoveableButton(QPushButton): 
    def __init__(self, text=""): 
     super().__init__(text) 

    # This event function is overloaded in order to avoid the widget from delegating the event up to the parent. 
    # This way, the pre-existing functionality is skipped, i.e. the window can no longer be moved while hovering over a button. 
    def mouseMoveEvent(self, QMouseEvent): 
     pass 

class Form(QWidget): 
    def __init__(self, parent=None): 
     super().__init__() 

     self.windowPos = QPoint()  # Maybe not necessary when button click and window movement are seperated 

     # Declare and specify UI elements 
     self.timerLabel = QLabel("00:00")  # Might have to change data type here 
     self.timerLabel.setObjectName("timerLabel") 

     self.infoLabel = QLabel("No tea selected") 
     self.infoLabel.setObjectName("infoLabel") 

     self.teaOneButton = UnmoveableButton("Tea One") 
     self.teaOneButton.setObjectName("teaOneButton") 

     self.teaTwoButton = UnmoveableButton("Tea Two") 
     self.teaTwoButton.setObjectName("teaTwoButton") 

     # Arrange UI elements in a layout 
     grid = QGridLayout() 
     self.setLayout(grid)  # Set the QGridLayout as the window's main layout 
     grid.setSpacing(0)  # Spacing between widgets - does not work if window is resized 
     grid.setContentsMargins(4, 4, 4, 4) 
     grid.addWidget(self.timerLabel, 0, 0, 1, -1, Qt.AlignHCenter)  # http://doc.qt.io/qt-5/qgridlayout.html#addWidget 
     grid.addWidget(self.infoLabel, 1, 0, 1, -1, Qt.AlignHCenter) 
     grid.addWidget(self.teaOneButton, 2, 0) 
     grid.addWidget(self.teaTwoButton, 2, 1) 

     self.resize(WINDOW_WIDTH, WINDOW_HEIGHT) 


    # Arranging window in center of the screen by overloading showEvent method 
    def showEvent(self, QShowEvent): 
     self.centerOnScreen() 


    def centerOnScreen(self): 
     screen = QDesktopWidget() 
     screenGeom = QRect(screen.screenGeometry(self)) 

     screenCenterX = screenGeom.center().x() 
     screenCenterY = screenGeom.center().y() 

     self.move(screenCenterX - self.width()/2, 
          screenCenterY - self.height()/2) 


    # Overload mouseEvent handlers to make window moveable 
    def mousePressEvent(self, QMouseEvent): 
     self.windowPos = QMouseEvent.pos() 
     self.setCursor(QCursor(Qt.SizeAllCursor)) 


    def mouseReleaseEvent(self, QMouseEvent): 
     self.setCursor(QCursor(Qt.ArrowCursor)) 


    def mouseMoveEvent(self, QMouseEvent): 
     # print (self.childAt(QMouseEvent.pos()) == QLabel) 
     pos = QPoint(QMouseEvent.globalPos()) 
     self.window().move(pos - self.windowPos) 



## =============================================================== 
## MAIN LOOP 

if __name__ == '__main__': 
    import sys 

    app = QApplication(sys.argv) 

    screen = Form() 
    screen.setWindowFlags(Qt.FramelessWindowHint) 
    screen.show() 

    sys.exit(app.exec_()) 

私はそれがその問題に関して最もエレガントで正しい解決策ではないかもしれないと思っていますが、今は私にとってはうまくいきます。誰かがこれを改善する方法についてアイデアを持っている場合、私に知らせてください:)

関連する問題