1. 程式人生 > >PyQt4中無邊框視窗的移動(拖動)

PyQt4中無邊框視窗的移動(拖動)

搜尋了很多文章,有關於Qt的C++版本無邊框視窗的拖動:

其中主要講到兩種方法,但是PyQt(Qt的Python版本)實現就沒有找到,以下主要講PyQt4中的實現

方法1:在QWidget/QDialog中重寫mousePressEvent和mouseMoveEvent方法,利用move方法移動視窗

這種方法相對簡單,但是缺陷在於會在滑鼠按下移動過程中,整個視窗是實時移動,實時重繪,移動快了會出現重影(由於多次重繪)。

#!/usr/bin/python  
#-*-coding:utf-8-*-
from PyQt4.QtGui import *
from PyQt4.Qt import
* from PyQt4.QtCore import * class AboutUsDialog(QDialog): def __init__(self, parent=None): super(AboutUsDialog, self).__init__(parent) self.setWindowFlags(Qt.FramelessWindowHint | Qt.Dialog) def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.dragPosition = event.globalPos() - self.frameGeometry().topLeft() QApplication.postEvent(self, QEvent(174
)) event.accept() def mouseMoveEvent(self, event): if event.buttons() == Qt.LeftButton: self.move(event.globalPos() - self.dragPosition) event.accept() if __name__ == '__main__': import sys app = QApplication(sys.argv) aboutus = AboutUsDialog() aboutus.show() sys.exit(app.exec_())

而正常的windows窗體移動都會在滑鼠按下後呈現虛線邊框,只移動虛線邊框,滑鼠放開後才會將窗體真正移動

方法二:使用winEvent處理訊息,將滑鼠點選窗體內的事件WM_NCHITTEST,模擬成為點選原生標題欄的事件HTCAPTION。在無邊框的視窗中增加isInTitle方法來判斷滑鼠位置是否在視窗中自定義的標題欄中。

此方法可以實現滑鼠在自定義欄中的滑鼠拖動,但是暫時不支援滑鼠雙擊進行最大化切換和還原。

#!/usr/bin/python  
#-*-coding:utf-8-*-
from PyQt4.QtGui import *
from PyQt4.Qt import *
from PyQt4.QtCore import *


class AboutUsDialog(QWidget):

    def __init__(self, parent=None):
        super(AboutUsDialog, self).__init__(parent)
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Dialog)

    def isInTitle(self, xPos, yPos):
        return yPos < 30


class MyApplication(QApplication):

    def __init__(self, args):
        super(MyApplication, self).__init__(args)

    def GET_X_LPARAM(self, param):
        #define LOWORD(l)           ((WORD)((DWORD_PTR)(l) & 0xffff))
        #define HIWORD(l)           ((WORD)((DWORD_PTR)(l) >> 16))
        #define GET_X_LPARAM(lp)                        ((int)(short)LOWORD(lp))
        #define GET_Y_LPARAM(lp)                        ((int)(short)HIWORD(lp))
        return param & 0xffff

    def GET_Y_LPARAM(self, param):
        return param >> 16

    def winEventFilter(self, msg):
        if msg.message == 0x84: #WM_NCHITTEST 
            form = self.activeWindow()
            if form:
                xPos = self.GET_X_LPARAM(msg.lParam) - form.frameGeometry().x()
                yPos = self.GET_Y_LPARAM(msg.lParam) - form.frameGeometry().y()
#                滑鼠在窗體自定義標題範圍內,窗體自定義一個isInTitle的方法判斷 
#                if yPos < 30 and xPos < 456:
                if not form.isMaximized() and hasattr(form, 'isInTitle') and form.isInTitle(xPos, yPos):
                    return True, 0x2 #HTCAPTION 

        return False, 0

if __name__ == '__main__':

    import sys
    app = MyApplication(sys.argv)
    aboutus = AboutUsDialog()
    aboutus.showNormal()
    sys.exit(app.exec_())