GUI學習之四——QWidget控件學習總結


上一章將的QObject是PyQt里所有控件的基類,並不屬於可視化的控件。這一章所講的QWidget,是所有可視化控件的基類。

QWidget包含下面幾點特性

a.控件是用戶界面的最小的元素

b.每個控件都是矩形的,他們按照Z軸順序排序(垂直於桌面),前面的會覆蓋后面的

c.控件由其父控件和前面的控件裁剪

d.沒有父控件的控件就是窗口

功能與作用

1.控件的創建

我們在上一章在創建了控件以后用Obj.setParent()的指定了控件的父子關系,在這里就有更簡單的方法了!

from PyQt5.Qt import *
import sys
app=QApplication(sys.argv)
window = QWidget()
window.resize(800,600)
red = QWidget(window)
red.setStyleSheet('background-color:red;')
red.resize(100,100)
window.show()
sys.exit(app.exec_())
控件的創建

這個方法里就是用繼承的方式在窗口里創建了新的界面。

2.大小和位置

首先我們要理解空間的坐標系統,控件的坐標原點在左上角,向右為x軸正方向,向下為y軸的正方向。頂層窗口的原點為顯示器的左上角,而子控件的原點在父控件的左上角。每個值為一個分辨率。

其次我們看一下大小位置相關的API

a.獲取

window = QWidget()
window.x()            #控件X軸坐標(包含框架窗口)
window.y()            #控件Y軸坐標(包含框架窗口)
window.pos()          #控件X/Y軸坐標集合
window.width()        #控件寬度(不包含窗口框架)
window.height()       #控件高度(不包含窗口框架)
window.size()         #控件寬度和高度的組合
window.geometry()     #用戶區域相對於父控件的位置和尺寸組合
window.rect()         #(0,0,width,height)的組合
window.frameSize()    #整個界面大小(包含框架窗口)
window.frameGeometry()#整個界面(X,Y,Width,height)的集合

用一個圖可以描述一下

b設置

window.move(x,y)                        #控件移動至x,y;包含窗口框架
window.resize(width,height)             #設置寬、高,不包含窗口框架
window.setGeometry(x,y,width,height)    #設置用戶區域的坐標和大小
window.adjustSize()                     #根據內容自適應尺寸
window.setFixedSize(width,height)      #設置固定尺寸 設置后窗口最大化按鈕是灰色的,窗口不可拖放

 用一個案例來演示一下,定義一個界面,上面按每行平均放3個來布局。

from PyQt5.Qt import *
import sys
app=QApplication(sys.argv)
window = QWidget()
window.resize(800,800)
widget_num = 20    #放置控件個數

###########計算寬度##########
widget_width = window.width()/3         #每行有3個控件
###########計算寬度##########

###########計算高度##########
row = (widget_num - 1)//3+1         #每行3個,獲取行數
widget_height = window.height()/row
###########計算高度##########

for i in range(0,widget_num):
    a = QLabel(window)
    a.resize(widget_width,widget_height)
    a.setStyleSheet('background-color:red;border:1px solid yellow;font-size:22px;')
    a.setText(str(i))

###########移動位位置##########
    a.move(i % 3 * widget_width, i // 3 * widget_height)     #i%3是列號,i//3為行號
###########移動位位置##########

window.show()
sys.exit(app.exec_())
位置大小案例

要注意的是在移動的時候是計算了行號和列號,在乘以控件大小即可實現。

3.最大尺寸和最小尺寸

a.獲取

window = QWidget()
window.minimumWidth()   #最小寬度
window.minimumHeight()  #最小高度
window.minimumSize()    #最小尺寸
window.maximumWidth()   #最大寬度
window.maximumHeight()  #最大高度
window.maximumSize()    #最大尺寸

b.設置

window = QWidget()
window.setMaximumWidth(width)           #最大寬度
window.setMaximumHeight(height)         #最大高度
window.setMaximumSize(width,height)     #最大尺寸
window.setMinimumWidth(width)           #最小寬度
window.setMinimumHeight(height)         #最小高度
window.setMinimumSize(width,height)     #最小尺寸

 設定完最大/小尺寸,用鼠標拖拽尺寸時會被限制,還有一點,

window.setMaximumSize(500,800)
window.resize(1000,1000)

運行后的尺寸還是500*800。並且手動拖拽限制了最大尺寸。

 4.內容邊距

先看一下內容邊距的相關API

label.contentsRect()                            #獲取標簽內容可以顯示的范圍
label.getContentsMargins()                      #獲取內容左上右下邊距(未定義邊距時為(0,0,0,0)
label.setContentsMargins(up,down,left,right)    #設定內容區域(左上右下)

 距離的定義是這樣的

 5.鼠標操作

a.設置鼠標形狀

window.setCursor(鼠標類型)

 鼠標類型有定義好的枚舉值,只要根據需求輸入就可以了

Qt.UpArrowCursor     #候選
Qt.CrossCursor       #精准選擇
Qt.IBeamCursor       #文本選擇
Qt.BusyCursor        #后台運行
Qt.WaitCursor        #
Qt.ForbiddenCursor   #不可用
Qt.PointingHandCursor#連接選擇
Qt.WhatsThisCurso    #幫助選擇
Qt.SizeVerCursor     #垂直調整大小
Qt.SizeHorCursor     #水平調整大小
Qt.SizeBDiagCursor   #延對角線調整大小2
Qt.SizeAllCursor     #移動
Qt.SplitVCursor      #垂直分割(無圖示)
Qt.SplitHCursor      #水平分割(無圖示)
Qt.OpenHandCursor    #伸開的手掌(無圖示)
Qt.ClosedHandCursor  #縮緊的拳頭(無圖示).
Qt.BlankCursor       #空白
常用鼠標圖標枚舉值

上面對應的圖是Win10的常規鼠標設置

 b.自定義鼠標

出了默認的鼠標圖像,還可以用自定義圖片(位圖)

pic = QPixmap(r'C:\Users\Aaron\Desktop\111.bmp')     #加載位圖路徑
pic2 = pic.scaled(10,10)                             #對圖片進行縮放
cursor = QCursor(pic2)                               #自定義鼠標圖片
label.setCursor(cursor)

這里有個要注意的地方,常規的鼠標是有個小箭頭的,比如一個按鈕,必須是箭頭的尖尖指到了才可以點擊,而不是只要這個箭頭在按鈕上就能使用。所以,我們在定義是有兩個參數是可以設置的

QCursor(bitmap,hotX,hotY)

bitmap就是位圖的地址,絕對路徑或相對路徑都是可以的。而hotX和hotY就是上面說鼠標尖尖的位置。如果鼠標的圖像是10*10的,把hotX,hotY設置成(10,10)就是鼠標的右下角在按鈕上才可以點擊按鈕。

c.鼠標恢復到初始狀態

label.setCursor(cursor)

d.鼠標獲取

current_cursor = label.cursor()
current_cursor.pos()             #獲取鼠標位置
current_cursor.setPos(x,y)       #設定鼠標位置

這里獲取的鼠標坐標對應的原點是桌面,而不是父控件。

e.鼠標跟蹤

from PyQt5.Qt import *
import sys
app=QApplication(sys.argv)
class MyWidget(QWidget):
    def mouseMoveEvent(self, a0):
        print(self.cursor().pos())
window = MyWidget()
window.setMouseTracking(True)   #開啟鼠標追蹤
print(window.hasMouseTracking())
window.show()
sys.exit(app.exec_())
鼠標追蹤

如果不啟動鼠標追蹤,只有改變了鼠標按鍵狀態(左右鍵和滾輪)才啟動了追蹤

演示一個鼠標追蹤的案例,在window里定義一個label,label的位置隨着鼠標的移動而改變

from PyQt5.Qt import *
import sys
app=QApplication(sys.argv)
class MyWindow(QWidget):
    def mouseMoveEvent(self, a0):
        label = self.findChild(QLabel)
        label.move(a0.localPos().x(),a0.localPos().y())  #localPos()是控件內坐標
        label.setText(str(a0.localPos().x())+'\n'+str(a0.localPos().y()))
window = MyWindow()
window.resize(800,800)
window.move(200,200)
window.setMouseTracking(True) #啟動鼠標追蹤
label = QLabel(window)
label.resize(100,100)
label.setStyleSheet('background-color:red;font-size:24px')
鼠標追蹤案例

 6.事件機制

事件機制的API

from PyQt5.Qt import *
import sys
app=QApplication(sys.argv)
class MyWindow(QWidget):
    def showEvent(self, a0):
        print('窗口被展開',a0)
    def closeEvent(self, a0):
        print('窗口關閉')
    def moveEvent(self, a0):
        print('窗口移動')
    def resizeEvent(self, a0):
        print('改變窗口尺寸')
    def mousePressEvent(self, a0):
        print('鼠標按下')
    def mouseReleaseEvent(self, a0):
        print('鼠標彈起')
    def mouseDoubleClickEvent(self, a0):
        print('鼠標雙擊')               #雙擊時候會觸發鼠標彈起
    def enterEvent(self,a0):
        print('鼠標進入控件')
    def leaveEvent(self,a0):
        print('鼠標離開控件')
    def keyPressEvent(self, a0):
        print('鍵盤上有按鍵被按下')
    def keyReleaseEvent(self, a0):\
        print('鍵盤上有按鍵彈起')
    def focusInEvent(self, a0):
        print('獲取焦點')
    def focusOutEvent(self, a0):
        print('失去焦點')
    def dragEnterEvent(self, a0):
        print('拖拽進入控件')
    def dragLeaveEvent(self, a0):
        print('拖拽離開控件')
    def dragMoveEvent(self, a0):
        print('在控件中拖拽')
    def dropEvent(self, a0):
        print('拖拽放下')
    def paintEvent(self, a0):
        print('繪制事件')
    def changeEvent(self, a0):
        print('改變事件')
    def contextMenuEvent(self, a0):
        print('右鍵菜單')
    def inputMethodEvent(self, a0):
        print('輸入法調用')
window = MyWindow()


window.show()
sys.exit(app.exec_())
事件API

事件里的鼠標、鍵盤事件只是觸發了事件,至於是哪個鍵的響應這里還沒說,后期再細說

7.事件轉發機制

Widget的控件有自己的事件轉發機制:如果一個控件沒有處理該事件,則該事件會自動傳遞給父級控件進行處理

例如上圖,一個頂層窗口,一個中間窗口還有一個標簽是依次繼承的,我們定義一個事件,鼠標點擊控件,打印’控件被點擊‘,點擊中間界面打印’中間界面被點擊‘,點擊頂層窗口打印’頂層窗口被點擊’我們把標簽的事件忽略掉,那么事件是會傳遞給中間界面的。所以,這里要引出一個方法

class MyLabel(QLabel):
    def mousePressEvent(self, a0):
        a0.ignore()     #忽略事件,把事件傳遞給父級控件
        a0.isAccepted() #獲取是否處理事件
        a0.accept()     #處理事件
import sys
from PyQt5.Qt import *
class MyWindow(QWidget):
    def mousePressEvent(self, a0):
        print('頂層鼠標按下')

class MidWindow(QWidget):
    def mousePressEvent(self, a0):
        print('中間界面被鼠標按下')
class MyLabel(QLabel):
    def mousePressEvent(self, a0):
        print('標簽控件鼠標按下')
        print(a0.isAccepted())
        a0.ignore()              #忽略事件
app = QApplication(sys.argv)

window = MyWindow()
window.resize(800,600)
midwindow = MidWindow(window)
midwindow.resize(500,500)
midwindow.setAttribute(Qt.WA_StyledBackground,True)
midwindow.setStyleSheet('background-color:cyan')
midwindow.move(50,50)
label = MyLabel(midwindow)
label.resize(200,100)
label.move(100,100)
label.setStyleSheet('background-color:green;font-size:22px')
label.setText('這是個標簽')
window.show()
sys.exit(app.exec_())
事件轉發機制演示

 8.父子關系補充

API

window = QWidget()
label = QLabel(window)
window.childAt(x,y)    #獲取window內x、y坐標位置存在的控件,無控件返回None
label.parentWidget()     #獲取控件的父控件
window.childrenRect()  #window內所有控件組成的矩形區域(位置、尺寸)(左上角——右下角)

9層級控制

由於界面上的控件是按層級顯示的,就有可能存在被遮擋的可能。先看下層級控制的API

obj.lower()     #控件放在最底層
obj.raise_()    #控件放在最頂層
a.stackUnder(b) #a放在b下面

上面所說的控件操作必須是同級的控件。一般情況后定義的控件比先定義的控件層級靠前。

下面的案例就是兩個Label,鼠標點擊哪個哪個顯示在前面

import sys
from PyQt5.Qt import *
app = QApplication(sys.argv)
class MyLabel(QLabel):
    def mousePressEvent(self, ev:QMouseEvent):
        self.raise_()
window = QWidget()
window.resize(800,600)
label1 = MyLabel(window)
label1.resize(300,300)
label1.setStyleSheet('background-color:red')
label2 = MyLabel(window)
label2.resize(300,300)
label2.move(50,50)
label2.setStyleSheet('background-color:green')
window.show()
sys.exit(app.exec_())
層級控制案例

10.頂層窗口相關操作

 a.設定程序圖標

可以改變這個程序圖標

icon = QIcon(r'圖片路徑')
window.setWindowIcon(icon)

b.標題

window.setWindowTitle('')

如果是空字符串了,標題展示的字符串就是默認的Python(像上面的圖一樣)如果像不現實,設定空格就行了( ‘ ’)

c.不透明度

window.setWindowOpacity(0.9)  #0-1對應透明——不透明
window.windowOpacity()        #返回值是個浮點數

獲取的不透明度是個浮點數,和設定的值有些許差異,比如設定值為設定值為0.9,獲取的值為0.8980392156862745

c.窗口狀態

window.setWindowState(Qt.WindowNoState)         #無狀態
window.setWindowState(Qt.WindowMaximized)       #窗口最大化
window.setWindowState(Qt.WindowMinimized)       #窗口最小化
window.setWindowState(Qt.WindowFullScreen)      #窗口全屏
window.setWindowState(Qt.WindowActive)          #活動窗口

window.windowState()                            #獲取控件狀態

活動窗口指的是比如有兩個程序,顯示在前面的那個就是活動窗口

d.最大化和最小化

和上面效果的差不多,設置API

window.showFullScreen()        #全屏
window.showMaximized()         #最大化
window.showMinimized()         #最小化
window.showNormal()            #正常顯示

判定

window.isMinimized()
window.isMaximized()
window.isFullScreen()

有一點,用這個設置的方法,可以不用show(),直接能顯示窗口。

e.窗口外觀標志

window.setWindowFlags()

用這個窗口的標志位設定能修改出很多的效果,下面就列舉了標志 的枚舉值。

Qt.MSWindowsFixedSizeDialogHint         #窗口大小無法調整
Qt.FramelessWindowHint                  #窗口無邊框,不可拖動大小,移動位置
Qt.CustomizeWindowHint                  #無邊框,可以拖動大小,不可移動
Qt.WindowTitleHint                      #標題欄只有關閉按鈕(且不可用?)
Qt.WindowSystemMenuHint                 #效果同上?
Qt.WindowMaximizeButtonHint             #標題欄內只激活最大化按鈕
Qt.WindowMinimizeButtonHint             #標題欄內只激活最小化按鈕
Qt.WindowCloseButtonHint                #標題欄只有關閉按鈕(可用)
Qt.WindowContextHelpButtonHint          #標題欄只有關閉按鈕(不可用)問號按鈕(可用)
Qt.WindowStaysOnTopHint                 #窗口始終顯示在最前
Qt.WindowStaysOnBottomHint              #窗口始終顯示在最后
窗口標志枚舉值

 11.交互狀態

控件顯示/禁用

btn.setEnabled()      #設定是否可用
btn.isEnabled()       #獲取是否可用
btn.setVisible()      #設定是否可見
btn.setHidden()       #設置隱藏
btn.isHidden()        #基於父控件是否被隱藏(父控件不顯示,子控件是可能不被隱藏的)
btn.isVisible()       #最終狀態是否可見
btn.isVisibleTo()     #一個控件是否隨着另一個控件的顯示而顯示

這里要引入幾個知識點:

a我們先運行一下這個程序

import sys
from PyQt5.Qt import *
app = QApplication(sys.argv)
class MyWindow(QWidget):
    def paintEvent(self, evt):
        print('窗口被繪制')
        return super().paintEvent(evt)   #不截取繪制的方法,由父類進行繪制

window = MyWindow()
window.resize(800,600)
class Btn(QPushButton):
    def paintEvent(self,evt):
        print('按鈕被繪制')
        return super().paintEvent(evt)

btn = Btn(window)
btn.setText('按鈕')
btn.clicked.connect(lambda :btn.setVisible(False))

window.show()
sys.exit(app.exec_())

在一個窗口里繪制一個按鈕,點擊按鈕后按鈕消失

運行一下看看會發生什么?

在運行程序時打印“窗口被繪制”“按鈕被繪制”,鼠標指向按鈕時按鈕顏色發生變化,再次打印“窗口被繪制”“按鈕被繪制”,點擊按鈕后打印“窗口被繪制”

所以,在每次界面發生改變時,所有的控件都是被依次繪制的。

b控件的顯示時基於父控件的(先畫父控件)如果父控件沒有被展示,即便將子控件設置visable也不會被展示的。

c用ishidden()獲取狀態時,如果父控件沒有顯示,但是有沒有隱藏子控件,返回值是True。

窗口相關

被編輯狀態

window.setWindowTitle('調試[*]')
window.setWindowModified(True)
print( window.isWindowModified())

這個有什么用呢?

看看是不是顯示的沒有那個中括號了!如果程序被修改可以顯示個星星。(貌似用處不大)

是否為活躍窗口

window.isActiveWindow()

注意的是,並不是哪個在前面哪個一定就是活躍窗口

import sys
from PyQt5.Qt import *
app = QApplication(sys.argv)
w1 = QWidget()
w2 = QWidget()
w1.show()
w2.show()
w1.raise_()
print(w1.isActiveWindow())
print(w2.isActiveWindow())
sys.exit(app.exec_())

運行以后可以發現通過w1.raise_()把界面提至最前,但返回值依舊為false,所以只有獲取了焦點才能是活躍窗口。

關閉控件

btn =QPushButton(window)
btn.setAttribute(Qt.WA_DeleteOnClose,True)  #釋放內存
btn.close()     #只是不顯示,不釋放內存

釋放內存的設置要放在關閉的前面。

12.信息提示

a.工具提示:鼠標懸停在控件上一段時間后展示在旁邊

btn.setToolTip('這是個按鈕')      #定義提示信息
btn.setToolTipDuration(1000)    #提示顯示時長(ms)
btn.toolTip()                   #獲取控件提示信息
import sys
from PyQt5.Qt import *
app = QApplication(sys.argv)
window = QWidget()
window.resize(800,600)
btn = QPushButton(window)
btn.setText('按鈕')
btn.setToolTip('這是個按鈕')   #定義提示信息
btn.setToolTipDuration(1000)    #提示顯示時長(ms)
btn.toolTip()                   #獲取控件提示信息
window.show()
sys.exit(app.exec_())
工具提示案例

b.狀態提示:鼠標停在控件上時,展示在狀態欄上,頂層窗口需要帶狀態欄並且激活

btn.setStatusTip('這是個按鈕')   #設定提示信息
btn.statusTip()                  #獲取控件提示信息
import sys
from PyQt5.Qt import *
app = QApplication(sys.argv)
window = QMainWindow()    #組合窗口
window.resize(800,600)
window.statusBar()       #激活狀態欄
btn = QPushButton(window)
btn.setStatusTip('這是個按鈕')   #設定提示信息
print(btn.statusTip())            #獲取控件提示信息
window.show()
sys.exit(app.exec_())
window.setWindowFlags(Qt.WindowContextHelpButtonHint)
btn.setWhatsThis('這是個按鈕')
btn.whatsThis()
btn.setStatusTip('提示信息')
狀態欄提示案例

c."這是啥?"提示:利用幫助按鈕顯示提示

window.setWindowFlags(Qt.WindowContextHelpButtonHint)  #先要啟用幫助按鈕
btn.setWhatsThis('這是個按鈕')                           #設定提示信息
btn.whatsThis()                                         #獲取提示信息
import sys
from PyQt5.Qt import *
app = QApplication(sys.argv)
window = QWidget()
window.resize(800,600)
btn = QPushButton(window)
window.setWindowFlags(Qt.WindowContextHelpButtonHint)  #先要啟用幫助按鈕
btn.setWhatsThis('這是個按鈕')  #設定提示信息
btn.whatsThis()                 #獲取提示信息
window.show()
sys.exit(app.exec_())
幫助按鈕提示案例

 13.焦點控制

首先要明白焦點的定義,比如一個窗口有兩個文本輸入的控件,鍵盤輸入字符,一個控件顯示出輸入的字符,那么這個控件就是獲取焦點的控件。或者通過tab鍵切換按鈕,也就是切換焦點

從單個控件角度來看,先看看API

obj.setFocus()         #獲取焦點
obj.setFocusPolicy()   #設定焦點策略(枚舉值)
obj.clearFocus()       #取消焦點
Qt.TabFocus   #只能通過Tab鍵獲取焦點
Qt.ClickFocus #只能通過單擊獲取焦點
Qt.StrongFocus#通過上述兩種方式獲取焦點
Qt.NoFocus    #禁止通過上述兩種方式獲取焦點
焦點獲取策略

 還可以從父控件角度來看焦點的控制

window.focusWidget()                #獲取子控件中當前獲得焦點的控件
window.focusNextChild()             #聚焦到下個子控件
window.focusPreviousChild()         #聚焦到上一個子控件
window.focusNextPrevChild()         #Ture:下一個   False :上一個
window.setTabOrder(第一個,第二個)    #設置Tab鍵獲取焦點順序
from PyQt5.Qt import *
import sys
app=QApplication(sys.argv)
class Window(QWidget):
    def mousePressEvent(self, a0:QMouseEvent):
        if a0.button() == 1:self.focusNextChild()
        else:self.focusPreviousChild()
window = Window()
le1 = QLineEdit(window)
le2 = QLineEdit(window)
le3 = QLineEdit(window)

le1.move(100,200)
le2.move(150,250)
le3.move(200,300)

window.show()
sys.exit(app.exec_())
獲取焦點案例二

案例二就是在界面里有三個文本框,按鼠標左鍵下一個獲得焦點,點擊右鍵上一個獲得焦點。

以上就是QWidget的學習筆記


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM