四、PyQt5布局管理(絕對&相對、水平、垂直、格柵、表單)


目錄

一、絕對布局

二、盒布局

三、格柵布局

四、格柵布局跨行跨列顯示

布局管理即設置窗體上各個控件的位置,對於新手來說,這是學習的難點。

布局管理根據絕對坐標是否變動分為絕對布局和相對布局兩大類。采用相對布局的窗口在變大或縮小時,各控件的位置關系會保持固定比例做相應變動。而采用絕對布局的窗口變動時,空間位置不會變動。

而相對布局根據方式不同,又可以分為水平布局(QHBoxLayout)、垂直布局管理(QVBoxLayout)、柵格布局管理(QGridLayout)、表單布局管理(QFormLayout)。

一、絕對布局

絕對布局中以像素為單位區分元素的位置,衡量元素的大小,以設定坐標的方式精准的定位每個控件的位置,但是這種布局方式也有缺點:

  • 窗體控件無法根據窗口的位置和大小而變化;
  • 改變字體大小時可能會破壞布局;
  • 當分辨率有較大改變時,原有布局會破壞;
  • 在設計階段,如果需要添加或刪除控件,如果要調整控件位置,就需要全部調整。

下面是絕對布局的示例:

 1 import sys,os
 2 from PyQt5.QtWidgets import QWidget,QLabel,QApplication
 3 from PyQt5.QtGui import QIcon
 4 
 5 path = os.path.dirname(os.path.dirname( os.path.dirname(__file__)))
 6 
 7 class MyWindow(QWidget):
 8 
 9     def __init__(self):
10         super(MyWindow, self).__init__()
11         self.initUI()
12 
13     def initUI(self):
14         self.setGeometry(300,300,500,400)
15         self.setWindowIcon(QIcon(r'%s\4.圖標素材\chuan.ico' % path))
16         self.setWindowTitle('絕對布局示例')
17 
18         lbl1 = QLabel('這是第一個標簽',self)
19         lbl1.setGeometry(80,80,30,30)
20 
21         lbl2 = QLabel('這是第二個標簽',self)
22         lbl2.move(150,150)
23 
24 
25 if __name__ == '__main__':
26     app = QApplication(sys.argv)
27     win = MyWindow()
28     win.show()
29     sys.exit(app.exec_())
絕對布局示例

效果圖如下:

根據效果圖可以發現:

  1. 在改變窗口長和寬的時候,兩個標簽的位置不會變動;
  2. 兩個標簽用不同的方法創建。第一個標簽不僅設定了位置,還固定了大小,所以內容不能完全展示。

二、盒布局(Box Layout)

采用盒布局的窗口在改變窗體大小時,各控件會按相應比例自動調整。代碼如下:

 1 import sys,os
 2 from PyQt5.QtWidgets import QApplication,QHBoxLayout,QVBoxLayout,QWidget,QPushButton
 3 from PyQt5.QtGui import QIcon
 4 
 5 path = os.path.dirname(os.path.dirname( os.path.dirname(__file__)))
 6 
 7 class MyWindow(QWidget):
 8 
 9     def __init__(self):
10         super(MyWindow, self).__init__()
11         self.initUI()
12 
13     def initUI(self):
14         self.setGeometry(300,300,500,400)
15         self.setWindowIcon(QIcon(r'%s/4.圖標素材/chuan.ico' % path))
16         self.setWindowTitle('盒布局示例')
17 
18         okbutton = QPushButton('確認')  #設置“確認”按鈕
19         cancelbutton = QPushButton('取消')  #設置“取消”按鈕
20 
21         hbox = QHBoxLayout()  #布局實例化對象
22         hbox.addStretch(1)  #設置分配比例
23         hbox.addWidget(okbutton)  #添加“確認”按鈕到窗體
24         hbox.addWidget(cancelbutton)
25 
26         vbox = QVBoxLayout()
27         vbox.addStretch(1)
28         vbox.addLayout(hbox)
29 
30         self.setLayout(vbox) #設置窗體布局
31 
32 if __name__ == '__main__':
33     app = QApplication(sys.argv)
34     win = MyWindow()
35     win.show()
36     sys.exit(app.exec_())
盒布局示例

盒布局中使用stretch函數在布局中增加了一個伸縮量,里面的參數表示QSpacerItem的個數,默認值為零(也可以理解為除去控件外,空白部分所占的比例),會將你放在layout中的空間壓縮成默認的大小。而且在窗體縮小時,這個伸縮量也可以變小,直至為零。

 “確認”和“取消”兩個按鈕出現在窗體右下角。示例中實現的方法是首先創建一個垂直布局,按鈕上部伸縮量占比為1,接着把這整個布局放在水平布局里,伸縮量占比為1.於是實現了給出的顯示效果。

下面對addstretch方法做個補充講解:

 1 import sys,os
 2 from PyQt5.QtWidgets import QApplication,QHBoxLayout,QVBoxLayout,QWidget,QPushButton
 3 from PyQt5.QtGui import QIcon
 4 
 5 path = os.path.dirname(os.path.dirname( os.path.dirname(__file__)))
 6 
 7 class MyWindow(QWidget):
 8 
 9     def __init__(self):
10         super(MyWindow, self).__init__()
11         self.initUI()
12 
13     def initUI(self):
14         self.setGeometry(300,300,500,300)
15         self.setWindowIcon(QIcon(r'%s/4.圖標素材/chuan.ico' % path))
16         self.setWindowTitle('addstrtch示例')
17 
18         fir_button = QPushButton('按鈕一')  #設置按鈕一
19         sec_button = QPushButton('按鈕二')  #設置按鈕二
20         thir_button = QPushButton('按鈕三')  #設置按鈕三
21 
22         hbox = QHBoxLayout()
23         hbox.addStretch(1)
24         hbox.addWidget(fir_button)
25         hbox.addStretch(2)
26         hbox.addWidget(sec_button)
27         hbox.addStretch(3)
28         hbox.addWidget(thir_button)
29 
30         # vbox = QVBoxLayout()
31         # vbox.addStretch(1)
32         # vbox.addLayout(hbox)
33 
34         self.setLayout(hbox) #設置窗體布局
35 
36 if __name__ == '__main__':
37     app = QApplication(sys.argv)
38     win = MyWindow()
39     win.show()
40     sys.exit(app.exec_())
addstretch方法示例

使用addstretch方法分別給定了參數1、2、3,即在水平布局上,除去按鈕部分外的空白區域,按照1:2:3的比例分配空間。下過如下圖所示。

三、格柵布局

格柵布局是最常用的布局方式,下面我們通過模擬計算器界面的方式來學習格柵布局。

 1 import sys,os
 2 from PyQt5.QtWidgets import QApplication,QPushButton,QWidget,QGridLayout
 3 from PyQt5.QtGui import QIcon
 4 
 5 path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
 6 
 7 class MyWindow(QWidget):
 8 
 9     def __init__(self):
10         super(MyWindow, self).__init__()
11         self.initUI()
12 
13     def initUI(self):
14         self.setWindowTitle('格柵布局示例')
15         self.setWindowIcon(QIcon(r'%s\4.圖標素材\chuan.ico' % path))
16         self.setGeometry(600,300,500,400)
17 
18         names = ['On','Off','AC','/',
19                  '7','8','9','*',
20                  '4','5','6','-',
21                  '1','2','3','+',
22                  '0','00','.','=']
23 
24         positions = [(i,j) for i in range(5) for j in range(4)]
25 
26         grid = QGridLayout()
27         self.setLayout(grid)
28         for position,name in zip(positions,names):
29             button = QPushButton(name)
30             grid.addWidget(button,*position)
31 
32 
33 
34 if __name__ == '__main__':
35     app = QApplication(sys.argv)
36     win = MyWindow()
37     win.show()
38     sys.exit(app.exec_())
格柵布局示例

顯示效果如下:

下面來分析代碼

names = ['On','Off','AC','/',
                 '7','8','9','*',
                 '4','5','6','-',
                 '1','2','3','+',
                 '0','00','.','=']

names列表是各按鍵的名稱。

positions = [(i,j) for i in range(5) for j in range(4)]

 這個列表生成式生成的列表類似一個矩陣,各元素的數值恰好是按鈕在格柵布局中位置

        for position,name in zip(positions,names):
            button = QPushButton(name)
            grid.addWidget(button,*position)

 這里使用的zip函數。python3中為了減少內存,zip函數返回的是一個對象。如果要展示列表,可通過 list() 轉換。

names = ['On','Off','AC','/',
                 '7','8','9','*',
                 '4','5','6','-',
                 '1','2','3','+',
                 '0','00','.','=']
positions = [(i,j) for i in range(5) for j in range(4)]
a = zip(names,positions)

print(a)
print(list(a))

顯示效果如下:
<zip object at 0x0000020EFF489508>
[('On', (0, 0)), ('Off', (0, 1)), ('AC', (0, 2)), ('/', (0, 3)), ('7', (1, 0)), ('8', (1, 1)), ('9', (1, 2)), ('*', (1, 3)), ('4', (2, 0)), ('5', (2, 1)), ('6', (2, 2)), ('-', (2, 3)), ('1', (3, 0)), ('2', (3, 1)), ('3', (3, 2)), ('+', (3, 3)), ('0', (4, 0)), ('00', (4, 1)), ('.', (4, 2)), ('=', (4, 3))]

 四、格柵布局跨行跨列顯示

雖然格柵布局最常用,但是實際窗口的控件往往是大小不一的,單個控件跨行跨列很常見,下面來介紹下跨行跨列的情況。

 1 import sys,os
 2 from PyQt5.QtWidgets import QWidget,QPushButton,QLabel,QLineEdit,QApplication,QGridLayout
 3 from PyQt5.QtGui import QIcon, QPixmap
 4 
 5 path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
 6 
 7 class MyWindow(QWidget):
 8 
 9     def __init__(self):
10         super().__init__()
11         self.initUI()
12 
13     def initUI(self):
14         self.setWindowTitle('跨行跨列布局示例')
15         self.setWindowIcon(QIcon(r'%s\4.圖標素材\chuan.ico' % path))
16         self.setGeometry(600,300,450,300)
17 
18         lbl_image = QLabel() 
19         png = QPixmap(r'%s\4.圖標素材\cartoon1.ico' % path)
20         lbl_image.setPixmap(png)
21         lbl_image.setScaledContents(True) #圖片自適應標簽大小
22 
23         lbl_user = QLabel('賬號:')  #設置標簽
24         lbl_pwd = QLabel('密碼:')
25         okbutton = QPushButton('確認')  #設置按鈕
26         cancelbutton = QPushButton('取消')
27         lineedit_user = QLineEdit()  #設置單行文本框
28         lineedit_pwd = QLineEdit()
29 
30         grid = QGridLayout()
31         self.setLayout(grid)
32         grid.setSpacing(10)   #間距為10
33 
34         grid.addWidget(lbl_image,1,1,3,1)
35         grid.addWidget(lineedit_user,1,2,1,2)
36         grid.addWidget(lineedit_pwd,2,2,1,2)
37         grid.addWidget(lbl_user,1,4)
38         grid.addWidget(lbl_pwd,2,4)
39         grid.addWidget(okbutton,3,2,1,1)
40         grid.addWidget(cancelbutton,3,3,1,1)
41 
42 if __name__ == '__main__':
43     app = QApplication(sys.argv)
44     win = MyWindow()
45     win.show()
46     sys.exit(app.exec_())
跨行跨列示例

顯示效果如下:

下面來分析代碼:

grid.addWidget(lbl_image,1,1,3,1)

 addwidget方法第一個參數是添加的控件對象,后面的(1,1)表示位置坐標為(1,1),即控件左上角坐標為(1,1)。這里的1並不是以像素為單位,而是以行和列為單位,(1,1)即第一行第一列。最后的(3,1)意思是這個控件占三行1列。下面用表格和圖片來表示布局方式

圖片

(3行1列)

單行文本框1 “賬號”標簽
單行文本框2 “密碼”標簽
“確認”按鈕 “取消”按鈕  
grid.setSpacing(10)

 即各控件之間的上下間距為10(以像素為單位)。同理還有grid.setMargin(int)為設置控件之間的左右間距。


 


免責聲明!

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



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