3
3
在一个GUI程序里,布局是一个很重要的方面。布局就是如何管理应用中的元素和窗口。有两种方式可以搞定:绝对定位和PyQt5的layout类
4
4
5
5
## 绝对定位
6
+
6
7
每个程序都是以像素为单位区分元素的位置,衡量元素的大小。所以我们完全可以使用绝对定位搞定每个元素和窗口的位置。但是这也有局限性:
7
8
8
- - 元素不会随着我们更改窗口的位置和大小而变化。
9
- - 不能适用于不同的平台和不同分辨率的显示器
10
- - 更改应用字体大小会破坏布局
11
- - 如果我们决定重构这个应用,需要全部计算一下每个元素的位置和大小
9
+ * 元素不会随着我们更改窗口的位置和大小而变化。
10
+ * 不能适用于不同的平台和不同分辨率的显示器
11
+ * 更改应用字体大小会破坏布局
12
+ * 如果我们决定重构这个应用,需要全部计算一下每个元素的位置和大小
12
13
13
14
下面这个就是绝对定位的应用
14
15
@@ -31,48 +32,51 @@ import sys
31
32
from PyQt5.QtWidgets import QWidget, QLabel, QApplication
32
33
33
34
class Example (QWidget ):
34
-
35
+
35
36
def __init__ (self ):
36
37
super ().__init__ ()
37
-
38
+
38
39
self .initUI()
39
-
40
-
40
+
41
+
41
42
def initUI (self ):
42
-
43
+
43
44
lbl1 = QLabel(' Zetcode' , self )
44
45
lbl1.move(15 , 10 )
45
46
46
47
lbl2 = QLabel(' tutorials' , self )
47
48
lbl2.move(35 , 40 )
48
-
49
+
49
50
lbl3 = QLabel(' for programmers' , self )
50
51
lbl3.move(55 , 70 )
51
-
52
+
52
53
self .setGeometry(300 , 300 , 250 , 150 )
53
54
self .setWindowTitle(' Absolute' )
54
55
self .show()
55
-
56
-
56
+
57
+
57
58
if __name__ == ' __main__' :
58
-
59
+
59
60
app = QApplication(sys.argv)
60
61
ex = Example()
61
62
sys.exit(app.exec_())
62
63
```
63
- 我们使用move()方法定位了每一个元素,使用x、y坐标。x、y坐标的原点是程序的左上角。
64
+
65
+ 我们使用move\(\) 方法定位了每一个元素,使用x、y坐标。x、y坐标的原点是程序的左上角。
64
66
65
67
```
66
68
lbl1 = QLabel('Zetcode', self)
67
69
lbl1.move(15, 10)
68
70
```
69
- 这个元素的左上角就在这个程序的左上角开始的(15, 10)的位置。
71
+
72
+ 这个元素的左上角就在这个程序的左上角开始的\( 15, 10\) 的位置。
70
73
71
74
程序展示:
72
75
73
76
![ Absolute positioning] ( ./images/3-absolute.png )
74
77
75
78
## 盒布局
79
+
76
80
使用盒布局能让程序具有更强的适应性。这个才是布局一个应用的更合适的方式。` QHBoxLayout ` 和` QVBoxLayout ` 是基本的布局类,分别是水平布局和垂直布局。
77
81
78
82
如果我们需要把两个按钮放在程序的右下角,创建这样的布局,我们只需要一个水平布局加一个垂直布局的盒子就可以了。再用弹性布局增加一点间隙。
@@ -99,15 +103,15 @@ from PyQt5.QtWidgets import (QWidget, QPushButton,
99
103
100
104
101
105
class Example (QWidget ):
102
-
106
+
103
107
def __init__ (self ):
104
108
super ().__init__ ()
105
-
109
+
106
110
self .initUI()
107
-
108
-
111
+
112
+
109
113
def initUI (self ):
110
-
114
+
111
115
okButton = QPushButton(" OK" )
112
116
cancelButton = QPushButton(" Cancel" )
113
117
@@ -119,21 +123,22 @@ class Example(QWidget):
119
123
vbox = QVBoxLayout()
120
124
vbox.addStretch(1 )
121
125
vbox.addLayout(hbox)
122
-
126
+
123
127
self .setLayout(vbox)
124
-
128
+
125
129
self .setGeometry(300 , 300 , 300 , 150 )
126
130
self .setWindowTitle(' Buttons' )
127
131
self .show()
128
-
129
-
132
+
133
+
130
134
if __name__ == ' __main__' :
131
-
135
+
132
136
app = QApplication(sys.argv)
133
137
ex = Example()
134
138
sys.exit(app.exec_())
135
139
```
136
- 上面的例子完成了在应用的右下角放了两个按钮的需求。当改变窗口大小的时候,它们能依然保持在相对的位置。我们同时使用了` HBoxLayout ` 和` QVBoxLayout ` 。
140
+
141
+ 上面的例子完成了在应用的右下角放了两个按钮的需求。当改变窗口大小的时候,它们能依然保持在相对的位置。我们同时使用了` QHBoxLayout ` 和` QVBoxLayout ` 。
137
142
138
143
```
139
144
okButton = QPushButton("OK")
@@ -148,18 +153,21 @@ hbox.addStretch(1)
148
153
hbox.addWidget(okButton)
149
154
hbox.addWidget(cancelButton)
150
155
```
156
+
151
157
创建一个水平布局,增加两个按钮和弹性空间。stretch函数在两个按钮前面增加了一些弹性空间。下一步我们把这些元素放在应用的右下角。
152
158
153
159
```
154
160
vbox = QVBoxLayout()
155
161
vbox.addStretch(1)
156
162
vbox.addLayout(hbox)
157
163
```
164
+
158
165
为了布局需要,我们把这个水平布局放到了一个垂直布局盒里面。弹性元素会把所有的元素一起都放置在应用的右下角。
159
166
160
167
```
161
168
self.setLayout(vbox)
162
169
```
170
+
163
171
最后,我们就得到了我们想要的布局。
164
172
165
173
程序预览:
@@ -191,50 +199,52 @@ from PyQt5.QtWidgets import (QWidget, QGridLayout,
191
199
192
200
193
201
class Example (QWidget ):
194
-
202
+
195
203
def __init__ (self ):
196
204
super ().__init__ ()
197
-
205
+
198
206
self .initUI()
199
-
200
-
207
+
208
+
201
209
def initUI (self ):
202
-
210
+
203
211
grid = QGridLayout()
204
212
self .setLayout(grid)
205
-
213
+
206
214
names = [' Cls' , ' Bck' , ' ' , ' Close' ,
207
215
' 7' , ' 8' , ' 9' , ' /' ,
208
216
' 4' , ' 5' , ' 6' , ' *' ,
209
217
' 1' , ' 2' , ' 3' , ' -' ,
210
218
' 0' , ' .' , ' =' , ' +' ]
211
-
219
+
212
220
positions = [(i,j) for i in range (5 ) for j in range (4 )]
213
-
221
+
214
222
for position, name in zip (positions, names):
215
-
223
+
216
224
if name == ' ' :
217
225
continue
218
226
button = QPushButton(name)
219
227
grid.addWidget(button, * position)
220
-
228
+
221
229
self .move(300 , 150 )
222
230
self .setWindowTitle(' Calculator' )
223
231
self .show()
224
-
225
-
232
+
233
+
226
234
if __name__ == ' __main__' :
227
-
235
+
228
236
app = QApplication(sys.argv)
229
237
ex = Example()
230
238
sys.exit(app.exec_())
231
239
```
240
+
232
241
这个例子里,我们创建了栅格化的按钮。
233
242
234
243
```
235
244
grid = QGridLayout()
236
245
self.setLayout(grid)
237
246
```
247
+
238
248
创建一个QGridLayout实例,并把它放到程序窗口里。
239
249
240
250
```
@@ -244,28 +254,32 @@ names = ['Cls', 'Bck', '', 'Close',
244
254
'1', '2', '3', '-',
245
255
'0', '.', '=', '+']
246
256
```
257
+
247
258
这是我们将要使用的按钮的名称。
248
259
249
260
```
250
261
positions = [(i,j) for i in range(5) for j in range(4)]
251
262
```
263
+
252
264
创建按钮位置列表。
253
265
254
266
```
255
267
for position, name in zip(positions, names):
256
-
268
+
257
269
if name == '':
258
270
continue
259
271
button = QPushButton(name)
260
272
grid.addWidget(button, *position)
261
273
```
274
+
262
275
创建按钮,并使用` addWidget() ` 方法把按钮放到布局里面。
263
276
264
277
程序预览:
265
278
266
279
![ Calculator skeleton] ( ./images/3-calculator.png )
267
280
268
281
## 制作提交反馈信息的布局
282
+
269
283
组件能跨列和跨行展示,这个例子里,我们就试试这个功能。
270
284
271
285
``` python
@@ -289,15 +303,15 @@ from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit,
289
303
QTextEdit, QGridLayout, QApplication)
290
304
291
305
class Example (QWidget ):
292
-
306
+
293
307
def __init__ (self ):
294
308
super ().__init__ ()
295
-
309
+
296
310
self .initUI()
297
-
298
-
311
+
312
+
299
313
def initUI (self ):
300
-
314
+
301
315
title = QLabel(' Title' )
302
316
author = QLabel(' Author' )
303
317
review = QLabel(' Review' )
@@ -317,33 +331,37 @@ class Example(QWidget):
317
331
318
332
grid.addWidget(review, 3 , 0 )
319
333
grid.addWidget(reviewEdit, 3 , 1 , 5 , 1 )
320
-
334
+
321
335
self .setLayout(grid)
322
-
336
+
323
337
self .setGeometry(300 , 300 , 350 , 300 )
324
338
self .setWindowTitle(' Review' )
325
339
self .show()
326
-
327
-
340
+
341
+
328
342
if __name__ == ' __main__' :
329
-
343
+
330
344
app = QApplication(sys.argv)
331
345
ex = Example()
332
346
sys.exit(app.exec_())
333
347
```
348
+
334
349
我们创建了一个有三个标签的窗口。两个行编辑和一个文版编辑,这是用` QGridLayout ` 模块搞定的。
335
350
336
351
```
337
352
grid = QGridLayout()
338
353
grid.setSpacing(10)
339
354
```
355
+
340
356
创建标签之间的空间。
341
357
342
358
```
343
359
grid.addWidget(reviewEdit, 3, 1, 5, 1)
344
360
```
361
+
345
362
我们可以指定组件的跨行和跨列的大小。这里我们指定这个元素跨5行显示。
346
363
347
364
程序预览:
348
365
349
366
![ review example] ( ./images/3-review.png )
367
+
0 commit comments