You are on page 1of 100

Translated from English to Vietnamese - www.onlinedoctranslator.

com
Tạo ứng dụng GUI với Python & Qt5
Hướng dẫn thực hành để tạo ứng dụng bằng Python

Martin Fitzpatrick

Phiên bản 4.0, 2020-06-26


Mục lục
Giới thiệu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
1. A rất lịch sử ngắn gọn của GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3
2. Một chút về Qt. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5
3. Thankyou . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7
4. Bản quyền. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .số 8
Các tính năng cơ bản của PyQt5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9
5. Ứng dụng đầu tiên của tôi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .10
6. Tín hiệu & khe cắm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21
7. Vật dụng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .32
8. Bố cục . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .63
9. Hành động, Thanh công cụ & Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .91

10. Hộp thoại . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .114


11. Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .130
12. Sự kiện . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .139
Qt Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148
13. Cài đặt Qt Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149
14. Bắt đầu với Qt Designer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .153
15. Hệ thống tài nguyên Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172
Chủ đề . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .182
16. Phong cách . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .183
17. Bảng màu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .186
18. Các biểu tượng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .197

19. Trang tính kiểu Qt (QSS). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .205


Kiến trúc Chế độ xem Mô hình . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .259
20. Kiến trúc Chế độ xem Mô hình - Bộ điều khiển Chế độ xem Mô hình . . . . . . . . . . . . . .260
21. Chế độ xem Mô hình đơn giản - Danh sách Todo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .263

22. Dữ liệu dạng bảng trong ModelViews, với numpy & gấu trúc . . . . . . . . . . . . . . . . . .279
23. Truy vấn cơ sở dữ liệu SQL với mô hình Qt. . . . . . . . . . . . . . . . . . . . . . . . . . . . .304
Các tính năng khác của PyQt5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .335
24. Tín hiệu mở rộng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .336
25. Định tuyến . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .348
26. Làm việc với các đối số dòng lệnh. . . . . . . . . . . . . . . . . . . . . . . . . . . . .353
27. Khay hệ thống & menu macOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .358
28. Enums & không gian tên Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .368
Tiện ích tùy chỉnh. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .378
29. Đồ họa Bitmap trong Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .379
30. Tạo các widget tùy chỉnh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .411
Thực hiện đồng thời . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .444
31. Giới thiệu về Luồng & Quy trình . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .445
32. Sử dụng nhóm chủ đề . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .451
33. Các ví dụ về luồng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .460
34. Chạy các lệnh và quy trình bên ngoài. . . . . . . . . . . . . . . . . . . . . . . . . . . .525
Âm mưu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .535
35. Lập kế hoạch với PyQtGraph. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .536
36. Lập kế hoạch với Matplotlib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557
Đóng gói & Phân phối . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .573
37. Bao bì với fbs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .574
Ứng dụng mẫu. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .594
38. Mozzarella Ashbadger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .595
39. Moonsweeper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .614
Phụ lục A: Cài đặt PyQt5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .637 Phụ
lục B: Dịch các ví dụ C ++ sang Python. . . . . . . . . . . . . . . . . . . . . . . . . .640 Phụ lục C: PyQt5
và PySide2 - Sự khác biệt là gì? . . . . . . . . . . . . . . . . .652 Phụ lục D: Tiếp theo là gì?
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Chỉ số 663
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .664
Giới thiệu
Nếu bạn muốn tạo các ứng dụng GUI bằng Python, bạn có thể khó biết bắt đầu từ đâu. Có
rất nhiều khái niệm mới bạn cần hiểu để có được bất cứ điều gì làm việc. Tuy nhiên, giống
như bất kỳ vấn đề mã hóa nào, bước đầu tiên là học cách tiếp cận vấn đề theo đúng cách.
Trong cuốn sách này, tôi sẽ hướng dẫn bạn ngay từ các nguyên tắc cơ bản của phát triển
GUI đến việc tạo các ứng dụng dành cho máy tính để bàn, đầy đủ chức năng của riêng bạn
với PyQt5.

Ấn bản đầu tiên của cuốn sách này được phát hành vào năm 2016. Kể từ đó đến nay nó đã
được cập nhật 4 lần, bổ sung và mở rộng các chương để đáp lại phản hồi của độc giả. Hiện
tại, có nhiều tài nguyên PyQt5 hơn so với khi tôi bắt đầu, nhưng vẫn còn thiếu các hướng
dẫn chuyên sâu, thiết thực để xây dựng các ứng dụng hoàn chỉnh. Cuốn sách này lấp đầy
khoảng trống đó!

Cuốn sách được định dạng thành một chuỗi các chương lần lượt khám phá các khía
cạnh khác nhau của PyQt5. Chúng được sắp xếp để đưa các chương đơn giản hơn vào
phần đầu, nhưng nếu bạn có yêu cầu cụ thể cho dự án của mình, đừng ngại nhảy xung
quanh! Mỗi chương sẽ hướng dẫn bạn tìm hiểu các khái niệm cơ bản trước khi đưa bạn
đi qua một loạt các ví dụ mã hóa để dần dần khám phá và học cách tự áp dụng các ý
tưởng đó.

Bạn có thể tải về mã nguồn và tài nguyên cho tất cả các ví dụ trong cuốn sách này.
Nhưng đừng bị cám dỗ chỉ để đọc mã và tiếp tục — bạn sẽ học được nhiều hơn nếu
bạn thử nghiệm trong suốt quá trình.

Nó không thể cung cấp cho bạn một hoàn chỉnh tổng quan về hệ thống Qt trong một
cuốn sách cỡ này, vì vậy có các liên kết đến các tài nguyên bên ngoài — cả trên trang
web LearnPyQt.com và các nơi khác. Nếu bạn thấy mình đang nghĩ "Tôi tự hỏi liệu tôi
có thể làmđiều đó? "Điều tốt nhất bạn có thể làm là đặt cuốn sách này xuống, sau đó đi
và tìm hiểu! Chỉ cần giữ các bản sao lưu thường xuyên mã của bạn trong suốt quá trình
để bạn luôn có thứ gì đó để quay lại nếu bạn làm hỏng nó.

1
Xuyên suốt cuốn sách này có các hộp như thế này, cung cấp thông

-
tin, mẹo và cảnh báo. Tất cả chúng có thể được bỏ qua một cách an
toàn nếu bạn đang vội, nhưng đọc chúng sẽ cung cấp cho bạn kiến
thức sâu hơn và đầy đủ hơn về khung Qt.

Cuối cùng, cuốn sách này được viết để tương thích với Python 3.4+. Python 3 là tương
lai của ngôn ngữ và nếu bạn đang bắt đầu thì đây là nơi bạn nên tập trung nỗ lực của
mình. Tuy nhiên, nhiều ví dụ có thể được thay đổi với nỗ lực tối thiểu để làm việc với
Python 2.7.

2
1. A rất lịch sử ngắn gọn của GUI
Các Giao diện đồ họa người dùng có một lịch sử lâu đời và đáng kính kể từ những
năm 1960. NLS (oN-Line System) của Stanford đã giới thiệu khái niệm chuột và cửa sổ,
lần đầu tiên được giới thiệu công khai vào năm 1968. Tiếp theo là GUI 1973 của hệ
thống Xerox PARC Smalltalk, là nền tảng của hầu hết các GUI đa năng hiện đại.

Các hệ thống ban đầu này đã có nhiều tính năng mà chúng tôi cho phép trong GUI trên
máy tính để bàn hiện đại, bao gồm cửa sổ, menu, nút radio, hộp kiểm và các biểu
tượng mới hơn. Sự kết hợp các tính năng này — đã cho chúng tôi từ viết tắt ban đầu
được sử dụng cho các loại giao diện này: WIMP (cửa sổ, biểu tượng, menu, thiết bị trỏ
— một con chuột).

Năm 1979, hệ thống thương mại đầu tiên có GUI được phát hành - máy trạm PERQ.
Điều này đã thúc đẩy một số nỗ lực GUI khác, bao gồm cả Apple Lisa (1983), bổ sung
khái niệm về thanh menu và các điều khiển cửa sổ. Cũng như nhiều hệ thống khác từ
Atari ST (GEM), Amiga. Trên UNIX (và sau đó là Linux), Hệ thống cửa sổ X xuất hiện vào
năm 1984. Phiên bản đầu tiên của Windows dành cho PC được phát hành vào năm
1985.

Hình 1. Màn hình nền trên Microsoft Windows 3.1 (1992) và Apple System 7 (1991)

Các GUI ban đầu không phải là tác động tức thì mà chúng ta có thể cho là do thiếu
phần mềm tương thích khi khởi chạy và các yêu cầu phần cứng đắt tiền - đặc biệt là đối
với người dùng gia đình. Từ từ, nhưng ổn định, GUI

3
giao diện trở thành cách ưa thích để tương tác với máy tính và phép ẩn dụ WIMP đã trở
thành tiêu chuẩn vững chắc. Điều đó không có nghĩa là chưa cócố gắng để thay thế
phép ẩn dụ WIMP trên máy tính để bàn. Ví dụ, Microsoft Bob (1995) là nỗ lực vô cùng
ác ý của Microsoft trong việc thay thế máy tính để bàn bằng một ngôi nhà.

Hình 2. Microsoft Bob — Loại bỏ phép ẩn dụ trên máy tính để bàn cho một ngôi nhà hoạt hình.

Không thiếu các GUI khác được ca ngợi là cách mạng vào thời của họ, từ khi ra mắt
Windows 95 (1995) đến Mac OS X (2001), GNOME Shell (2011) và Windows 10 (2015).
Mỗi người trong số này đều đại tu giao diện người dùng của các hệ thống máy tính để
bàn tương ứng của chúng, thường có nhiều sự phô trương. Nhưng về cơ bản thì không
có gì thực sự thay đổi. Những giao diện người dùng mới này vẫn còn rất nhiều hệ
thống WIMP và hoạt động giống hệt như GUI từ những năm 1980.

Khi cuộc cách mạng đến, đó là thiết bị di động — chuột đã được thay thế bằng cảm ứng và
cửa sổ bằng các ứng dụng toàn màn hình. Nhưng ngay cả trong một thế giới mà tất cả
chúng ta đều đi quanh quẩn với điện thoại thông minh trong túi, một lượng lớn công việc
hàng ngày vẫn được thực hiện trên máy tính để bàn. WIMP đã tồn tại được 40 năm đổi mới
và có vẻ sẽ tồn tại nhiều hơn nữa.

4
2. Một chút về Qt
Qt là một nguồn mở và miễn phí bộ công cụ widget để tạo các ứng dụng GUI đa nền
tảng, cho phép các ứng dụng nhắm mục tiêu đến nhiều nền tảng từ Windows, macOS,
Linux và Android với một cơ sở mã duy nhất. Nhưng Qt lànhiều hơn nữa không chỉ là
một bộ công cụ widget và các tính năng được tích hợp sẵn để hỗ trợ đa phương tiện,
cơ sở dữ liệu, đồ họa vector và giao diện MVC, chính xác hơn là coi nó như một sự phát
triển ứng dụng khuôn khổ.

Qt được bắt đầu bởi Eirik Chambe-Eng và Haavard Nord vào năm 1991, thành lập công
ty Qt đầu tiên Trolltech vào năm 1994. Qt hiện được phát triển bởi Công ty Qt và tiếp
tục được cập nhật thường xuyên, bổ sung các tính năng và mở rộng hỗ trợ di động và
đa nền tảng.

Qt và PyQt5
PyQt5 là một Python ràng buộc của bộ công cụ Qt, được phát triển bởi Riverbank
Computing. Khi bạn viết ứng dụng bằng PyQt5, lĩnh vực của bạnThực ra đang làm là
viết ứng dụng trong Qt. Thư viện PyQt5 chỉ đơn giản là.[1] một trình bao bọc xung
quanh thư viện C ++ Qt, để cho phép nó được sử dụng trong Python.

Vì đây là giao diện Python với thư viện C ++ nên các quy ước đặt tên được sử dụng trong
PyQt5 không tuân theo các tiêu chuẩn PEP8. Đáng chú ý nhất là các hàm và biến được đặt
tên bằng cách sử dụnghỗn hợp còn hơn là solid_case. Việc bạn có tuân thủ tiêu chuẩn này
trong các ứng dụng của riêng mình hay không là hoàn toàn phụ thuộc vào bạn, tuy nhiên,
tôi thấy việc tuân theo các tiêu chuẩn Python cho mã của riêng tôi đã giúp làm rõ, để giúp
làm rõ nơi mã PyQt5 kết thúc và mã của bạn bắt đầu.

Cuối cùng, mặc dù có sẵn tài liệu cụ thể về PyQt5, nhưng bạn thường sẽ thấy mình tự
đọc tài liệu Qt vì nó đầy đủ hơn. Nếu bạn làm như vậy, bạn sẽ cần dịch cú pháp đối
tượng và một số phương thức chứa tên hàm dành riêng cho Python như sau:

5
Qt PyQt5

Qt :: SomeValue Qt.SomeValue

object.exec () object.exec_ ()

object.print () object.print_ ()

-
Nếu bạn cần chuyển đổi toàn bộ ví dụ mã Qt sang Python, hãy xem
Dịch các ví dụ C ++ sang Python.

Cuốn sách này được viết để làm việc với phiên bản mới nhất của Qt (và PyQt5). Khi viết
đây là Qt 5,14. Tuy nhiên, nhiều ví dụ sẽ hoạt động tốt với các phiên bản trước và sau
của Qt.

[1] Không hẳn điều đó giản dị.

6
3. Thankyou
Cuốn sách này tiếp tục được mở rộng và cập nhật để đáp ứng phản hồi của độc giả. Xin
cảm ơn những độc giả sau vì những đóng góp của họ đã giúp tạo nên ấn bản này!

• James Battat, Phó Giáo sư Vật lý, Cao đẳng Wellesley

• Andries Broekema

• Richard Hohlfield

• Olivier Girard, Blog

• Alex Lombardi

• Cody Jackson, Cố vấn, Code-a-Mom

• John E Kadwell

• Jeffrey R Kennedy

• Juan Pablo Donayre Quintana

• Guido Tognan

Nếu bạn có phản hồi hoặc đề xuất cho các ấn bản trong tương lai, chỉ cần cho tôi biết.

7
4. Bản quyền
Cuốn sách này được cấp phép theo Giấy phép Phi thương mại Creative Commons Ghi nhận
tác giả Chia sẻ tương tự (CC BY-NC-SA) © 2020 Martin Fitzpatrick.

• Bạn có thể tự do chia sẻ các bản sao chưa thay đổi của cuốn sách này với bất kỳ ai bạn
chọn.

• Nếu bạn sửa đổi cuốn sách này và phân phối phiên bản đã thay đổi của mình, nó phải được

phân phối theo cùng một giấy phép.

• Bạn không được phép bán cuốn sách này hoặc các dẫn xuất dưới bất kỳ hình thức nào.

• Nếu muốn ủng hộ tác giả bạn có thể hợp pháp mua một bản sao trực tiếp từ (các)
tác giả.

Chúng tôi hoan nghênh những đóng góp và chỉnh sửa của độc giả (CC BY-NC-SA).

số 8
Các tính năng cơ bản của PyQt5
Đã đến lúc thực hiện các bước đầu tiên của bạn trong việc tạo các ứng dụng GUI với PyQt5!

Trong chương này, bạn sẽ được giới thiệu những kiến thức cơ bản về PyQt5 là nền tảng
của bất kỳ ứng dụng nào bạn tạo. Chúng tôi sẽ phát triển một ứng dụng cửa sổ đơn giản
trên màn hình của bạn. Chúng tôi sẽ thêm các widget, sắp xếp chúng bằng cách sử dụng bố
cục và kết nối các widget này với các chức năng, cho phép bạn kích hoạt hành vi ứng dụng
từ GUI của mình.

Sử dụng mã được cung cấp làm hướng dẫn cho bạn, nhưng hãy luôn thoải mái thử nghiệm. Đó

là cách tốt nhất để học cách mọi thứ hoạt động.

-
Trước khi bắt đầu, bạn cần cài đặt PyQt5 hoạt động. Nếu bạn chưa
có, hãy xemCài đặt PyQt5.

-
Đừng quên tải xuống mã nguồn đi kèm với cuốn sách này.

9
5. Ứng dụng đầu tiên của tôi
Hãy tạo ứng dụng đầu tiên của chúng tôi! Để bắt đầu tạo một tệp Python mới - bạn có thể gọi nó bất cứ thứ

gì bạn thích (ví dụ:myapp.py) và lưu nó ở nơi nào đó có thể truy cập được. Chúng tôi sẽ viết ứng dụng đơn

giản của chúng tôi trong tệp này.

Chúng tôi sẽ chỉnh sửa trong tệp này khi chúng tôi tiếp tục và bạn có thể

- muốn quay lại các phiên bản mã trước đó của mình, vì vậy hãy nhớ giữ
các bản sao lưu thường xuyên.

Tạo ứng dụng của bạn

Mã nguồn cho ứng dụng đầu tiên của bạn được hiển thị bên dưới. Nhập nguyên văn và
cẩn thận để không mắc lỗi. Nếu bạn làm sai, Python sẽ cho bạn biết điều gì sai. Nếu
bạn không muốn nhập tất cả, tệp được bao gồm trong mã nguồn của cuốn sách này.

10
Liệt kê 1. basic / create_a_window_1.py

từ PyQt5.QtWidgets nhập khẩu QApplication, QWidget

# Chỉ cần thiết để truy cập vào các đối số dòng lệnh nhập
khẩu sys

# Bạn cần một (và chỉ một) phiên bản QApplication cho mỗi ứng dụng.
# Chuyển vào sys.argv để cho phép đối số dòng lệnh cho ứng dụng của bạn.
# Nếu bạn biết bạn sẽ không sử dụng đối số dòng lệnh QApplication ([]) cũng hoạt
động.
app = QApplication (sys.argv)

# Tạo một widget Qt, đây sẽ là cửa sổ của chúng ta.


window = QWidget ()
window.show () # QUAN TRỌNG!!!!! Windows bị ẩn theo mặc định.

# Bắt đầu vòng lặp sự kiện.


app.exec_ ()

# Ứng dụng của bạn sẽ không đến được đây cho đến khi bạn thoát và sự kiện
# vòng lặp đã dừng.

Đầu tiên, khởi chạy ứng dụng của bạn. Bạn có thể chạy nó từ dòng lệnh như bất kỳ tập lệnh
Python nào khác, chẳng hạn như—

python MyApp.py

Hoặc, đối với Python 3—

python3 MyApp.py

Từ bây giờ, bạn sẽ thấy hộp sau đây như một gợi ý để chạy ứng dụng của bạn và thử
nghiệm nó, cùng với chỉ báo về những gì bạn sẽ thấy.

11
- Chạy nó! Bây giờ bạn sẽ thấy cửa sổ của mình. Qt tự động tạo một cửa sổ với các
trang trí cửa sổ bình thường và bạn có thể kéo nó xung quanh và thay đổi kích
thước giống như bất kỳ cửa sổ nào.

Những gì bạn sẽ thấy sẽ phụ thuộc vào nền tảng bạn đang chạy ví dụ này. Hình ảnh
bên dưới cho thấy cửa sổ được hiển thị trên Windows, macOS và Linux (Ubuntu).

Hình 3. Cửa sổ của chúng ta, như đã thấy trên Windows, macOS và Linux.

Bước qua mã

Hãy xem từng dòng mã, để chúng ta hiểu chính xác điều gì đang xảy ra.

Đầu tiên, chúng tôi nhập các lớp PyQt5 mà chúng tôi cần cho ứng dụng. Đây chúng tôi
đang nhậpQApplication, trình xử lý ứng dụng và QWidget, một cơ bản trống GUI
widget, cả hai từ QtWidgets mô-đun.

từ PyQt5.QtWidgets nhập khẩu QApplication, QWidget

Các mô-đun chính cho Qt là QtWidgets, QtGui và QtCore.

Bạn có thể làm từ <module> nhập * nhưng loại nhập toàn cầu này

- thường không được sử dụng trong Python, vì vậy chúng tôi sẽ tránh nó ở
đây.

Tiếp theo, chúng tôi tạo một phiên bản của QApplication, đi qua sys.arg, đó là

12
Python danh sách chứa các đối số dòng lệnh được truyền cho ứng dụng.

app = QApplication (sys.argv)

Nếu bạn biết mình sẽ không sử dụng các đối số dòng lệnh để điều khiển Qt, bạn có thể chuyển

vào danh sách trống thay vào đó, ví dụ:

app = QApplication ([])

Tiếp theo, chúng tôi tạo một phiên bản của một QWidget sử dụng tên biến cửa sổ.

window = QWidget ()
window.show ()

Trong Qt tất cả tiện ích con cấp cao nhất là cửa sổ — nghĩa là, chúng không có cha mẹ và không

được lồng trong một widget hoặc bố cục khác. Điều này có nghĩa là bạn có thể tạo một cửa sổ về

mặt kỹ thuật bằng bất kỳ tiện ích nào bạn thích.

Tôi không thể nhìn thấy cửa sổ của mình!

Vật dụng không có cha mẹ được ẩn theo mặc định. Vì vậy, sau khi tạocửa sổ

- đối tượng, chúng ta phải luôn gọi .buổi bieu diễn() để làm cho nó hiển thị.

Bạn có thể loại bỏ.buổi bieu diễn() và chạy ứng dụng, nhưng bạn sẽ không

có cách nào để thoát khỏi nó!

Cửa sổ là gì?

• Giữ giao diện người dùng của ứng dụng của bạn

- • Mỗi ứng dụng cần ít nhất một (… nhưng có thể có nhiều hơn)

• Ứng dụng sẽ (theo mặc định) thoát khi đóng cửa sổ cuối cùng

Cuối cùng, chúng tôi gọi app.exec_ () để bắt đầu vòng lặp sự kiện.

13
Vòng lặp sự kiện là gì?
Trước khi hiển thị cửa sổ trên màn hình, có một vài khái niệm chính cần giới thiệu về
cách các ứng dụng được tổ chức trong thế giới Qt. Nếu bạn đã quen với các vòng lặp
sự kiện, bạn có thể chuyển sang phần tiếp theo một cách an toàn.

Cốt lõi của mọi Ứng dụng Qt là QApplication lớp học. Mọi ứng dụng đều cần một - và
chỉ một -QApplication đối tượng để hoạt động. Đối tượng này giữvòng lặp sự kiện ứng
dụng của bạn - vòng lặp cốt lõi điều chỉnh tất cả tương tác của người dùng với GUI.

Hình 4. Vòng lặp sự kiện trong Qt.

Mỗi tương tác với ứng dụng của bạn - cho dù là một lần nhấn phím, nhấp chuột hay di
chuyển chuột - đều tạo ra một biến cố được đặt trên hàng đợi sự kiện. Trong vòng lặp
sự kiện, hàng đợi được kiểm tra trên mỗi lần lặp và nếu tìm thấy sự kiện đang chờ, sự
kiện và điều khiển sẽ được chuyển cho cụ thểxử lý sự kiện dành cho sự kiện. Trình xử lý
sự kiện xử lý sự kiện, sau đó chuyển quyền điều khiển trở lại vòng lặp sự kiện để chờ
thêm sự kiện. Chỉ cómột chạy vòng lặp sự kiện cho mỗi ứng dụng.

14
Các QApplication lớp học

• QApplication giữ vòng lặp sự kiện Qt

• Một QApplication trường hợp bắt buộc


- • Ứng dụng của bạn ngồi đợi trong vòng lặp sự kiện cho đến khi một hành

động được thực hiện

• Chỉ có một vòng lặp sự kiện bất cứ lúc nào

Dấu gạch dưới ở đó bởi vì người điều hành là một từ dành riêng trong Python 2.7. PyQt5 xử
lý điều này bằng cách thêm dấu gạch dưới vào tên được sử dụng trong thư viện C ++. Bạn
cũng sẽ thấy.in_() các phương pháp trên widget chẳng hạn.

QMainWindow
Như chúng ta đã khám phá ở phần trước, trong Qt bất kì vật dụng có thể là cửa sổ. Ví
dụ, nếu bạn thay thếQtWidget với QPushButton. Trong ví dụ dưới đây, bạn sẽ nhận
được một cửa sổ với một nút nhấn có thể trong đó.

Liệt kê 2. basic / create_a_window_2.py

từ PyQt5.QtWidgets nhập khẩu QApplication, QPushButton


window = QPushButton ( "Đẩy tôi" )
window.show ()

Điều này là gọn gàng, nhưng không thực sự rất có ích—Thật hiếm khi bạn cần một giao diện người

dùng chỉ bao gồm một điều khiển duy nhất! Tuy nhiên, như chúng ta sẽ khám phá sau, khả năng lồng

các tiện ích con trong các tiện ích con khác bằng cách sử dụngbố cục nghĩa là bạn có thể tạo giao diện

người dùng phức tạp bên trong QWidget.

Tuy nhiên, Qt đã có một giải pháp cho bạn — QMainWindow. Đây là một tiện ích được tạo sẵn cung

cấp rất nhiều tính năng cửa sổ tiêu chuẩn mà bạn sẽ sử dụng trong ứng dụng của mình, bao gồm

thanh công cụ, menu, thanh trạng thái, tiện ích con có thể gắn và hơn thế nữa. Chúng ta sẽ xem xét

các tính năng nâng cao này sau, nhưng hiện tại, chúng ta sẽ thêm một khoảng trống đơn giản

QMainWindow vào ứng dụng của chúng tôi.

15
Liệt kê 3. basic / create_a_window_3.py

từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow

nhập khẩu sys

app = QApplication (sys.argv)

window = QMainWindow ()
window.show () # QUAN TRỌNG!!!!! Windows bị ẩn theo mặc định.

# Bắt đầu vòng lặp sự kiện.


app.exec_ ()

- Chạy nó! Bây giờ bạn sẽ thấy cửa sổ chính của mình. Nó trông giống hệt như
trước đây!

Nên chung tôi QMainWindow không phải là rất thú vị vào lúc này. Chúng tôi có thể khắc
phục điều đó bằng cách thêm một số nội dung. Nếu bạn muốn tạo một cửa sổ tùy chỉnh,
cách tiếp cận tốt nhất là phân lớpQMainWindow và sau đó bao gồm thiết lập cho cửa sổ
trong __trong đó__ khối. Điều này cho phép hành vi cửa sổ được tự động. Chúng tôi có thể
thêm lớp con của riêng mìnhQMainWindow - gọi nó đi Cửa sổ chính để giữ mọi thứ đơn
giản.

16
Liệt kê 4. basic / create_a_window_4.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu QSize, Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow, QPushButton ①

# Lớp con QMainWindow để tùy chỉnh cửa sổ chính của ứng dụng của bạn lớp
học Cửa sổ chính(QMainWindow):
phản đối __trong đó__(bản thân):

siêu().__trong đó__() ②

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

button = QPushButton ( "Nhấn vào tôi!" )

# Đặt tiện ích trung tâm của Cửa sổ. bản


thân.setCentralWidget (nút) ③

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

① Các vật dụng Qt chung luôn được nhập từ QtWidgets không gian tên.

② Chúng ta phải luôn luôn gọi __trong đó__ phương pháp của siêu() lớp học.

③ Sử dụng .setCentralWidget để đặt một widget trong QMainWindow.

-
Khi bạn phân lớp một lớp Qt, bạn phải luôn gọi siêu __trong đó__
chức năng cho phép Qt thiết lập đối tượng.

Trong của chúng tôi __trong đó__ khối chúng tôi sử dụng đầu tiên .setWindowTitle () để thay
đổi tiêu đề của cửa sổ chính của chúng tôi. Sau đó, chúng tôi thêm tiện ích con đầu tiên của
mình - aQPushButton - ở giữa cửa sổ. Đây là một trong những widget cơ bản có sẵn trong
Qt. Khi tạo nút, bạn có thể chuyển văn bản mà bạn muốn nút hiển thị.

17
Cuối cùng, chúng tôi gọi .setCentralWidget () trên cửa sổ. Đây là mộtQMainWindow
chức năng cụ thể cho phép bạn đặt tiện ích con ở giữa cửa sổ.

- Chạy nó! Bây giờ bạn sẽ thấy lại cửa sổ của mình, nhưng lần này với
QPushButton widget ở giữa. Nhấn nút sẽ không làm gì cả, chúng tôi sẽ sắp xếp
điều đó tiếp theo.

Hình 5. Của chúng tôi QMainWindow với một QPushButton trên Windows, macOS và
Linux.

Đói cho vật dụng?

Chúng tôi sẽ trình bày chi tiết hơn về các widget trong thời gian ngắn

- nhưng nếu bạn thiếu kiên nhẫn và muốn tiếp tục, bạn có thể xem
qua Tài liệu QWidget. Hãy thử thêm các widget khác nhau vào cửa sổ
của bạn!

Định kích thước cửa sổ và widget

Cửa sổ hiện có thể thay đổi kích thước một cách tự do — nếu bạn lấy chuột vào bất kỳ góc nào, bạn có

thể kéo và thay đổi kích thước của nó thành bất kỳ kích thước nào bạn muốn. Mặc dù việc cho phép

người dùng thay đổi kích thước ứng dụng của bạn là điều tốt, nhưng đôi khi bạn có thể muốn đặt giới

hạn về kích thước tối thiểu hoặc tối đa hoặc khóa cửa sổ ở một kích thước cố định.

Trong Qt, kích thước được xác định bằng cách sử dụng QSize sự vật. Điều này chấp nhậnchiều rộng và

Chiều cao các tham số theo thứ tự đó. Ví dụ, phần sau sẽ tạo ra mộtkích thước cố định

18
cửa sổ 400x300 pixel.

Liệt kê 5. basic / create_a_window_end.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu QSize, Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow, QPushButton

# Lớp con QMainWindow để tùy chỉnh cửa sổ chính của ứng dụng của bạn lớp
học Cửa sổ chính(QMainWindow):
phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

button = QPushButton ( "Nhấn vào tôi!" )

bản thân.setFixedSize (QSize (400, 300)) ①

# Đặt tiện ích trung tâm của Cửa sổ. bản


thân.setCentralWidget (nút)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

① Đặt kích thước trên cửa sổ.

- Chạy nó! Bạn sẽ thấy một cửa sổ có kích thước cố định — hãy thử và thay đổi kích thước, nó sẽ không hoạt

động.

19
Hình 6. Cửa sổ kích thước cố định của chúng tôi, lưu ý rằng kiểm soát tối đa bị tắt trên Windows &
Linux. Trên macOS, bạn có thể phóng to ứng dụng để lấp đầy màn hình, nhưng tiện ích trung tâm sẽ
không thay đổi kích thước.

Cũng như .setFixedSize () bạn cũng có thể gọi .setMinimumSize () và


. setMaximumSize ()để đặt kích thước tối thiểu và tối đa tương ứng. Hãy tự mình thử
nghiệm điều này!

- Bạn có thể sử dụng các phương pháp kích thước này trên bất kì tiện ích con.

Trong phần này, chúng tôi đã đề cập đến QApplication lớp học, QMainWindow lớp,
vòng lặp sự kiện và thử nghiệm với việc thêm một widget đơn giản vào một cửa sổ.
Trong phần tiếp theo, chúng ta sẽ xem xét các cơ chế mà Qt cung cấp cho các widget
và cửa sổ để giao tiếp với nhau và mã của riêng bạn.

- Lưu bản sao tệp của bạn dưới dạng myapp.py vì chúng ta sẽ cần nó một lần nữa sau này.

20
6. Tín hiệu & khe cắm
Cho đến nay, chúng tôi đã tạo một cửa sổ và thêm một nút ấn tiện ích cho nó, nhưng
nút không làm bất cứ điều gì. Điều đó không hữu ích chút nào — khi bạn tạo các ứng
dụng GUI, bạn thường muốn chúng làm điều gì đó! Những gì chúng ta cần là một cách
để kết nối hành động củanhấn nút để làm cho một cái gì đó xảy ra. Trong Qt, điều này
được cung cấp bởitín hiệu và khe cắm.

Tín hiệu là những thông báo do các widget phát ra khi thứ gì đó xảy ra. Điều gì đó có
thể là bất kỳ thứ gì, từ việc nhấn một nút, đến văn bản của hộp nhập liệu thay đổi, đến
văn bản của cửa sổ thay đổi. Nhiều tín hiệu được khởi tạo bởi hành động của người
dùng, nhưng đây không phải là một quy tắc.

Ngoài việc thông báo về điều gì đó đang xảy ra, các tín hiệu cũng có thể gửi dữ liệu để
cung cấp thêm ngữ cảnh về những gì đã xảy ra.

-
Bạn cũng có thể tạo các tín hiệu tùy chỉnh của riêng mình, mà chúng ta
sẽ khám phá sau Mở rộng tín hiệu.

Slots là tên mà Qt sử dụng cho các bộ thu tín hiệu. Trong Python, bất kỳ hàm (hoặc
phương thức) nào trong ứng dụng của bạn đều có thể được sử dụng làm vị trí — đơn
giản bằng cách kết nối tín hiệu với nó. Nếu tín hiệu gửi dữ liệu, thì chức năng nhận
cũng sẽ nhận dữ liệu đó. Nhiều tiện ích Qt cũng có các khe cắm tích hợp riêng, nghĩa là
bạn có thể kết nối trực tiếp các tiện ích Qt với nhau.

Hãy cùng xem xét các khái niệm cơ bản về tín hiệu Qt và cách bạn có thể sử dụng chúng để kết nối các tiện

ích con nhằm biến mọi thứ thành hiện thực trong ứng dụng của bạn.

-
Tải lên một bản sao mới của myapp.py và lưu nó dưới một tên mới
cho phần này.

QPushButton Tín hiệu


Ứng dụng đơn giản của chúng tôi hiện có QMainWindow với một QPushButton đặt làm tiện ích

con trung tâm. Hãy bắt đầu bằng cách kết nối nút này với một phương thức Python tùy chỉnh. Ở

đây chúng tôi tạo một vị trí tùy chỉnh đơn giản có tênthe_button_was_clicked

21
chấp nhận đã nhấp vào tín hiệu từ QPushButton.

Liệt kê 6. basic / signal_and_slots_1.py

từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow, QPushButton ① từ


PyQt5.QtCore nhập khẩu Qt

nhập khẩu sys

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__() ②

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

button = QPushButton ( "Nhấn vào tôi!" )


button.setCheckable (Đúng vậy) button.clicked.connect (bản
thân.the_button_was_clicked)

# Đặt tiện ích trung tâm của Cửa sổ. bản


thân.setCentralWidget (nút)

phản đối the_button_was_clicked(bản thân):


in( "Đã nhấp!" )

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Nếu bạn nhấp vào nút, bạn sẽ thấy dòng chữ "Đã nhấp!" trên bảng điều
khiển.

22
Liệt kê 7. Đầu ra của bảng điều khiển

Đã nhấp chuột!

Đã nhấp chuột!

Đã nhấp chuột!

Đã nhấp chuột!

Nhận dữ liệu

Đó là một khởi đầu tốt! Chúng tôi đã nghe nói rằng các tín hiệu cũng có thể gửidữ liệu để cung

cấp thêm thông tin về những gì vừa xảy ra. Các.đã nhấp vào tín hiệu không phải là ngoại lệ, cũng

cung cấp một đã kiểm tra (hoặc bật tắt) trạng thái cho nút. Đối với các nút bình thường, điều này

luônSai, vì vậy vị trí đầu tiên của chúng tôi đã bỏ qua dữ liệu này. Tuy nhiên, chúng tôi có thể làm

cho nút của mìnhcó thể kiểm tra được và xem hiệu quả.

Trong ví dụ sau, chúng tôi thêm một vị trí thứ hai xuất ra giấy kiểm tra.

23
Liệt kê 8. basic / signal_and_slots_1b.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow, QPushButton ①

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__() ②

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

button = QPushButton ( "Nhấn vào tôi!" )


button.setCheckable (Đúng vậy) button.clicked.connect (bản
thân.the_button_was_clicked) button.clicked.connect (bản thân
.the_button_was_toggled)

# Đặt tiện ích trung tâm của Cửa sổ. bản


thân.setCentralWidget (nút)

phản đối the_button_was_clicked(bản thân):


in( "Đã nhấp!" )

phản đối the_button_was_toggled(bản thân, đã kiểm tra):


in( "Đã kiểm tra?" , đã kiểm tra)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Nếu bạn nhấn nút, bạn sẽ thấy nó được đánh dấu là đã kiểm tra. Nhấn nó một

lần nữa để giải phóng nó. Tìm kiếmkiểm tra trạng thái trong bảng điều khiển.

24
Liệt kê 9. Đầu ra của bảng điều khiển

Đã nhấp chuột!

Đã kiểm tra? Đúng vậy

Đã nhấp chuột!

Đã kiểm tra? Sai


Đã nhấp chuột!

Đã kiểm tra? Đúng vậy

Đã nhấp chuột!

Đã kiểm tra? Sai


Đã nhấp chuột!

Đã kiểm tra? Đúng vậy

Bạn có thể kết nối nhiều vị trí với một tín hiệu tùy thích và có thể phản hồi các phiên
bản tín hiệu khác nhau cùng một lúc trên các vị trí của bạn.

Lưu trữ dữ liệu

Thường thì rất hữu ích khi lưu trữ dòng điện trạng thái của một tiện ích con trong một biến

Python. Điều này cho phép bạn làm việc với các giá trị giống như bất kỳ biến Python nào khác và

không cần truy cập vào widget gốc. Bạn có thể lưu trữ các giá trị này dưới dạng các biến riêng lẻ

hoặc sử dụng từ điển nếu muốn. Trong ví dụ tiếp theo, chúng tôi lưu trữđã kiểm tra giá trị của

nút của chúng tôi trong một biến được gọi là button_is_checked trên bản thân.

25
Liệt kê 10. basic / signal_and_slots_1c.py

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.button_is_checked = Đúng vậy ①

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

button = QPushButton ( "Nhấn vào tôi!" )


button.setCheckable (Đúng vậy) button.clicked.connect (bản
thân.the_button_was_toggled) button.setChecked (bản thân
.button_is_checked) ②

# Đặt tiện ích trung tâm của Cửa sổ. bản


thân.setCentralWidget (nút)

phản đối the_button_was_toggled(bản thân, đã kiểm tra):


bản thân.button_is_checked = đã kiểm tra ③

in(bản thân.button_is_checked)

① Đặt giá trị mặc định cho biến của chúng tôi.

② Sử dụng giá trị mặc định để đặt trạng thái ban đầu của tiện ích.

③ Khi trạng thái tiện ích thay đổi, hãy cập nhật biến để phù hợp.

Bạn có thể sử dụng cùng một mẫu này với bất kỳ tiện ích PyQt5 nào. Nếu tiện ích con
không cung cấp tín hiệu gửi trạng thái hiện tại, bạn sẽ cần truy xuất giá trị từ tiện ích
con trực tiếp trong trình xử lý của mình. Ví dụ: ở đây, chúng tôi đang kiểm tra trạng
thái đã kiểm tra trong mộtép người xử lý.

26
Liệt kê 11. basic / signal_and_slots_1d.py

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.button_is_checked = Đúng vậy

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

bản thân.button = QPushButton ( bản


"Nhấn vào tôi!" ) ①
thân.button.setCheckable (Đúng vậy)
bản thân.button.released.connect (bản thân.the_button_was_released) bản ②
thân.button.setChecked (bản thân.button_is_checked)

# Đặt tiện ích trung tâm của Cửa sổ. bản thân
.setCentralWidget (bản thân.cái nút)

phản đối the_button_was_released(bản thân):


bản thân.button_is_checked = bản thân.button.isChecked () ③

in(bản thân.button_is_checked)

① Chúng ta cần tham chiếu đến nút bật bản thân vì vậy chúng tôi có thể truy cập nó trong vị trí của chúng
tôi.

② Các giải thoát tín hiệu kích hoạt khi nút được nhả ra, nhưng không gửi trạng thái
kiểm tra.

③. isChecked () trả về trạng thái kiểm tra của nút.

Thay đổi giao diện

Cho đến nay, chúng ta đã thấy cách chấp nhận tín hiệu và in đầu ra ra bảng điều khiển.
Nhưng làm thế nào về việc làm cho một cái gì đó xảy ra trong giao diện khi chúng ta nhấp
vào nút? Hãy cập nhật phương pháp vị trí của chúng tôi để sửa đổi nút, thay đổi văn bản và
vô hiệu hóa nút để nó không thể nhấp được nữa. Chúng tôi cũng sẽ tắtcó thể kiểm tra được
trạng thái cho bây giờ.

27
Liệt kê 12. basic / signal_and_slots_2.py

từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow, QPushButton ① từ


PyQt5.QtCore nhập khẩu Qt

nhập khẩu sys

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__() ②

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

bản thân.button = QPushButton ( "Nhấn vào tôi!" ) ①


bản thân.button.clicked.connect (bản thân.the_button_was_clicked)

# Đặt tiện ích trung tâm của Cửa sổ. bản thân
.setCentralWidget (bản thân.cái nút)

phản đối the_button_was_clicked(bản thân):


bản thân.button.setText ( "Bạn đã nhấp vào tôi." ) ②
bản thân.button.setEnabled (Sai) ③

# Cũng thay đổi tiêu đề cửa sổ.


bản thân.setWindowTitle ( "Ứng dụng Oneshot của tôi" )

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

① Chúng tôi cần có thể truy cập vào cái nút trong của chúng tôi the_button_was_clicked , vì vậy
chúng tôi giữ tham chiếu đến nó trên bản thân.

② Bạn có thể thay đổi văn bản của một nút bằng cách chuyển str đến .setText ().

③ Để tắt một cuộc gọi nút .setEnabled () với Sai.

28
- Chạy nó! Nếu bạn nhấp vào nút, văn bản sẽ thay đổi và nút sẽ không thể nhấp
được.

Bạn không bị giới hạn trong việc thay đổi nút kích hoạt tín hiệu, bạn có thể làm bất cứ
thứ gì bạn muốn trong các phương pháp khe cắm của bạn. Ví dụ: hãy thử thêm dòng
sau vàothe_button_was_clicked để thay đổi tiêu đề cửa sổ.

bản thân.setWindowTitle ( "Tiêu đề cửa sổ mới" )

Hầu hết các tiện ích con đều có tín hiệu riêng của chúng — và QMainWindow chúng tôi đang sử dụng

cho cửa sổ của chúng tôi cũng không ngoại lệ. Trong ví dụ phức tạp hơn sau đây, chúng tôi kết nối.

windowTitleChanged tín hiệu trên QMainWindow theo một phong tục

Trong ví dụ sau, chúng tôi kết nối .windowTitleChanged tín hiệu trên QMainWindow
đến một vị trí phương pháp the_window_title_changed. Khe này cũng nhận được tiêu
đề cửa sổ mới.

Liệt kê 13. basic / signal_and_slots_3.py

từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow, QPushButton từ


PyQt5.QtCore nhập khẩu Qt

nhập khẩu sys


từ ngẫu nhiên nhập khẩu sự lựa chọn

window_titles = [ ①
'Ứng dụng của tôi' ,

'Ứng dụng của tôi' ,

'Vẫn là ứng dụng của tôi' ,


'Vẫn là ứng dụng của tôi' ,
'Những gì trên trái đất' ,
'Những gì trên trái đất' ,
'Điều này thật đáng ngạc nhiên' ,
'Điều này thật đáng ngạc nhiên' ,
'Đã xảy ra lỗi'
]

29
lớp học Cửa sổ chính(QMainWindow):
phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.n_times_clicked = 0

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

bản thân.button = QPushButton ( "Nhấn vào tôi!" )


bản thân.button.clicked.connect (bản thân.the_button_was_clicked)

bản thân.windowTitleChanged.connect (bản thân.the_window_title_changed)


# Đặt tiện ích trung tâm của Cửa sổ. bản thân
.setCentralWidget (bản thân.cái nút)

phản đối the_button_was_clicked(bản thân):


in( "Đã nhấp." )
new_window_title = choice (window_titles) in(
"Đặt tiêu đề:% s" % new_window_title)
bản thân.setWindowTitle (new_window_title) ③

phản đối the_window_title_changed(bản thân, tiêu đề cửa sổ):


in( "Tiêu đề cửa sổ đã thay đổi:% s" % tiêu đề cửa sổ) ④

nếu như window_title == 'Đã xảy ra lỗi' :


bản thân.button.setDisabled (Đúng vậy)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

① Danh sách các tiêu đề cửa sổ mà chúng tôi sẽ chọn để sử dụng random.choice ().

30
② Kết nối phương pháp vị trí tùy chỉnh của chúng tôi the_window_title_changed đến cửa sổ
. windowTitleChangedtín hiệu.

③ Đặt tiêu đề cửa sổ thành tiêu đề mới.

④ Nếu tiêu đề cửa sổ mới bằng "Đã xảy ra sự cố", hãy tắt nút này.

- Chạy nó! Nhấp vào nút liên tục cho đến khi tiêu đề thay đổi thành "Đã xảy ra sự
cố" và nút sẽ bị vô hiệu hóa.

Có một số điều cần lưu ý trong ví dụ này.

Thứ nhất, windowTitleChanged tín hiệu không luôn phát ra khi đặt tiêu đề cửa sổ. Tín
hiệu chỉ kích hoạt nếu họ có tiêu đề mới làbiến đổi từ cái trước. Điều quan trọng là phải
biết chính xác điều kiện nào báo hiệu cháy, để tránh bị bất ngờ!

Thứ hai, lưu ý cách chúng tôi có thể chuỗi mọi thứ với nhau bằng cách sử dụng các tín hiệu.
Một điều đang xảy ra — một lần nhấn nút — có thể kích hoạt nhiều điều khác lần lượt xảy
ra. Những tác động sau này không cần biếtgì đã gây ra chúng, nhưng chỉ đơn giản tuân
theo như một hệ quả của các quy tắc đơn giản. Điều nàytách ra của các hiệu ứng từ trình
kích hoạt của chúng là một trong những khái niệm chính cần hiểu khi xây dựng các ứng
dụng GUI. Chúng tôi sẽ tiếp tục trở lại điều này trong suốt cuốn sách!

Trong phần này, chúng tôi đã đề cập đến các tín hiệu và vị trí. Chúng tôi đã trình bày một số tín

hiệu đơn giản và cách sử dụng chúng để chuyển dữ liệu và trạng thái xung quanh ứng dụng của

bạn. Tiếp theo, chúng ta sẽ xem xét các widget mà Qt cung cấp để sử dụng trong các ứng dụng

của bạn — cùng với các tín hiệu mà chúng cung cấp.

31
7. Vật dụng
Trong Qt phụ tùng là tên được đặt cho một thành phần của giao diện người dùng mà người
dùng có thể tương tác. Giao diện người dùng được tạo thành từ nhiều tiện ích con, được
sắp xếp trong cửa sổ. Qt đi kèm với một số lượng lớn các vật dụng có sẵn và thậm chí cho
phép bạn tạo các vật dụng tùy chỉnh của riêng mình.

Trong các ví dụ mã cho cuốn sách có một tệp widgets_list.py mà bạn có thể chạy để
hiển thị một bộ sưu tập các widget trong một cửa sổ. Nó sử dụng một số thủ thuật
phức tạp mà chúng tôi sẽ đề cập sau, vì vậy đừng lo lắng về mã vừa rồi.

- Chạy nó! Bạn sẽ thấy một cửa sổ với nhiều widget tương tác.

Hình 7. Ứng dụng widget ví dụ được hiển thị trên Windows, macOS và Linux
(Ubuntu).

32
Các widget hiển thị trong ví dụ được đưa ra bên dưới, từ trên xuống dưới.

Widget Những gì nó làm

QCheckbox Một hộp kiểm

QComboBox Hộp danh sách thả xuống

QDateEdit Để chỉnh sửa ngày và giờ

QDateTimeEdit Để chỉnh sửa ngày và giờ

QDial Quay số có thể xoay

QDoubleSpinbox Một con quay số cho phao

QFontComboBox Một danh sách các phông chữ

QLCDNumber Một màn hình LCD khá xấu

QLabel Chỉ là một nhãn, không tương tác

QLineEdit Nhập một dòng văn bản

QProgressBar Một thanh tiến trình

QPushButton Một nut bâm

QRadioButton Một nhóm chỉ có một lựa chọn đang hoạt động

QSlider Một thanh trượt

QSpinBox Một con quay số nguyên

QTimeEdit Để biết thời gian chỉnh sửa

Có nhiều vật dụng hơn thế này, nhưng chúng không phù hợp lắm! Để có danh sách đầy
đủ, hãy xemTài liệu Qt. Sau đây, chúng ta sẽ xem xét kỹ hơn một số điều hữu ích nhất.

-
Tải lên một bản sao mới của myapp.py và lưu nó dưới một tên mới
cho phần này.

33
QLabel
Chúng ta sẽ bắt đầu chuyến tham quan với QLabel, được cho là một trong những widget đơn giản

nhất có sẵn trong hộp công cụ Qt. Đây là một đoạn văn bản một dòng đơn giản mà bạn có thể đặt

trong ứng dụng của mình. Bạn có thể đặt văn bản bằng cách chuyển vào một chuỗi khi bạn tạo nó—

widget = QLabel ( "Xin chào" )

Hoặc, bằng cách sử dụng .setText () phương pháp-

widget = QLabel ( "1" ) # Nhãn được tạo với văn bản 1


widget.setText ( "2" ) # Nhãn hiện hiển thị 2

Bạn cũng có thể điều chỉnh các thông số phông chữ, chẳng hạn như kích thước hoặc căn chỉnh của văn bản trong

tiện ích con.

34
Liệt kê 14. basic / widgets_1.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QLabel, QMainWindow

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

widget = QLabel ( "Xin chào" )


font = widget.font () ①
font.setPointSize (30)
widget.setFont (phông chữ)
widget.setAlignment (Qt.AlignHCenter | Qt.AlignVCenter) ②

bản thân.setCentralWidget (tiện ích con)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

① Chúng tôi nhận được hiện hành phông chữ, sử dụng <widget> .font (), sửa đổi nó và sau đó
áp dụng nó trở lại. Điều này đảm bảo mặt phông chữ vẫn phù hợp với các quy ước trên máy

tính để bàn.

② Căn chỉnh được chỉ định bằng cách sử dụng một cờ từ Qt. không gian tên.

- Chạy nó! Điều chỉnh các thông số phông chữ và xem hiệu ứng.

35
Hình 8. A QLabel trên Windows, macOS và Ubuntu

Không gian tên Qt (Qt.) có đầy đủ các loại thuộc tính mà bạn có thể sử dụng

- để tùy chỉnh và kiểm soát các widget Qt. Chúng tôi sẽ trình bày chi tiết về vấn

đề đó ở phần sauEnums & không gian tên Qt.

36
Các cờ có sẵn để căn chỉnh theo chiều ngang là—

Lá cờ Hành vi

Qt.AlignLeft Căn với cạnh trái.

Qt.AlignRight Căn chỉnh với cạnh bên phải.

Qt.AlignHCenter Căn giữa theo chiều ngang trong không gian

có sẵn.

Qt.AlignJustify Căn chỉnh văn bản trong không gian


có sẵn.

Các cờ có sẵn để căn chỉnh theo chiều dọc là—

Lá cờ Hành vi

Qt.AlignTop Căn chỉnh với đầu.

Qt.AlignBottom Căn chỉnh với phía dưới.

Qt.AlignVCenter Căn giữa theo chiều dọc trong không gian

có sẵn.

Bạn có thể kết hợp các cờ với nhau bằng cách sử dụng các đường ống (|), tuy nhiên lưu ý rằng bạn chỉ

có thể sử dụng một cờ căn chỉnh dọc hoặc ngang tại một thời điểm.

align_top_left = Qt.AlignLeft | Qt.AlignTop

- Chạy nó! Hãy thử kết hợp các cờ căn chỉnh khác nhau và xem ảnh hưởng của vị
trí văn bản.

37
Cờ Qt

Lưu ý rằng bạn sử dụng một HOẶC LÀ đường ống (|) để kết hợp hai cờ
theo quy ước. Các cờ không chồng chéomặt nạ. ví dụ Qt.AlignLeft có giá
trị nhị phân 0b0001, trong khi Qt.AlignBottom Là 0b0100. Bằng cách
- ORing cùng nhau, chúng tôi nhận được giá trị0b0101 đại diện cho 'dưới
cùng bên trái'.

Chúng tôi sẽ xem xét chi tiết hơn về Qt không gian tên và cờ Qt sau
này trong Enums & không gian tên Qt.

Cuối cùng, cũng có một cờ tốc ký xoay tâm đồng thời theo cả hai hướng—

Lá cờ Hành vi

Qt.AlignCenter Căn giữa theo chiều ngang và theo chiều dọc

Thật kỳ lạ, bạn cũng có thể sử dụng QLabel để hiển thị một hình ảnh bằng cách sử dụng .

setPixmap () phương pháp. Điều này chấp nhận mộtbản đồ (một mảng pixel), bạn có thể tạo

bằng cách chuyển tên tệp hình ảnh tới QPixmap. Trong các tệp ví dụ được cung cấp cùng với

cuốn sách này, bạn có thể tìm thấy một tệpotje.jpg mà bạn có thể hiển thị trong cửa sổ của mình

như sau:

widget.setPixmap (QPixmap ( 'otje.jpg' ))

Hình 9. Otje. Thật là một khuôn mặt đáng yêu.

38
- Chạy nó! Thay đổi kích thước cửa sổ và hình ảnh sẽ được bao quanh bởi không
gian trống.

Theo mặc định, hình ảnh chia tỷ lệ trong khi vẫn giữ nguyên tỷ lệ khung hình. Nếu bạn
muốn nó kéo dài và chia tỷ lệ để vừa với cửa sổ hoàn toàn, bạn có thể đặt
. setScaledContents (Đúng)trên QLabel.

widget.setScaledContents (Đúng vậy)

Ví dụ-

Liệt kê 15. basic / widgets_2.py

nhập khẩu sys

từ PyQt5.QtGui nhập khẩu QPixmap


từ PyQt5.QtWidgets nhập khẩu QApplication, QLabel, QMainWindow

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

widget = QLabel ( "Xin chào" )


widget.setPixmap (QPixmap "otje.jpg" ))
(widget.setScaledContents (Đúng vậy)

bản thân.setCentralWidget (tiện ích con)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

39
- Chạy nó! Thay đổi kích thước cửa sổ và hình ảnh sẽ biến dạng để vừa vặn.

Hình 10. Hiển thị một bản đồ ảnh với QLabel trên Windows, macOS và Ubuntu

40
QCheckBox
Tiện ích tiếp theo để xem xét là QCheckBox mà, như tên cho thấy, hiển thị một hộp có
thể kiểm tra cho người dùng. Tuy nhiên, như với tất cả các widget Qt, có một số tùy
chọn có thể định cấu hình để thay đổi các hành vi của widget.

Liệt kê 16. basic / widgets_3.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QCheckBox, QMainWindow

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

widget = QCheckBox ( "Đây là một hộp kiểm" )


widget.setCheckState (Qt.Check)

# Đối với tristate: widget.setCheckState (Qt.PartiallyChecked)


# Hoặc: widget.setTriState (Đúng)
widget.stateChanged.connect (bản thân.show_state)

bản thân.setCentralWidget (tiện ích con)

phản đối show_state(bản thân, s):


in(s == Qt.Checked) in(S)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

41
- Chạy nó! Bạn sẽ thấy một hộp kiểm có văn bản nhãn.

Hình 11. QCheckBox trên Windows, macOS và Ubuntu

Bạn có thể đặt trạng thái hộp kiểm theo chương trình bằng cách sử dụng .setChecked hoặc là

. setCheckState. Người trước đây chấp nhận một trong haiĐúng vậy hoặc là Sai đại diện cho được chọn

hoặc không được chọn tương ứng. Tuy nhiên, với.setCheckState bạn cũng chỉ định một trạng thái

được kiểm tra cụ thể bằng cách sử dụng Qt. cờ vùng tên—

Lá cờ Hành vi

Qt.Unchecked Mục không được chọn

Qt.PartiallyChecked Mục được kiểm tra một phần

Qt.Checked Mục không được chọn

Hộp kiểm hỗ trợ đánh dấu một phần (Qt.PartiallyChecked) trạng thái thường được gọi
là 'tri-state', trạng thái không bật cũng không tắt. Hộp kiểm ở trạng thái này thường
được hiển thị dưới dạng hộp kiểm chuyển sang màu xám và thường được sử dụng
trong các sắp xếp hộp kiểm phân cấp nơi các mục con được liên kết với hộp kiểm
chính.

Nếu bạn đặt giá trị thành Qt.PartiallyChecked hộp kiểm sẽ trở thành bộ ba — nghĩa là
có ba các trạng thái có thể. Bạn cũng có thể đặt hộp kiểm thành ba trạng thái mà
không cần đặt trạng thái hiện tại thành chọn một phần bằng cách sử dụng
. setTriState (Đúng)

42
Bạn có thể nhận thấy rằng khi tập lệnh đang chạy, số trạng thái hiện
tại được hiển thị dưới dạng int với đã kiểm tra = 2, bỏ chọn = 0và

-
được kiểm tra một phần = 1. Bạn không cần phải nhớ những giá trị
này,Qt.Checked biến không gian tên == 2 Ví dụ. Đây là giá trị của các
cờ tương ứng của các tiểu bang này. Điều này có nghĩa là bạn có thể
kiểm tra trạng thái bằng cách sử dụngstate == Qt.Checked.

43
QComboBox

Các QComboBox là một danh sách thả xuống, được đóng theo mặc định bằng một mũi tên
để mở. Bạn có thể chọn một mục từ danh sách, với mục hiện đang chọn sẽ được hiển thị
dưới dạng nhãn trên tiện ích. Hộp kết hợp phù hợp để lựa chọn một lựa chọn từ một danh
sách dài các tùy chọn.

Bạn có thể đã thấy hộp tổ hợp được sử dụng để lựa chọn các mặt hoặc

-
kích thước phông chữ trong các ứng dụng xử lý văn bản. Mặc dù Qt thực
sự cung cấp một hộp kết hợp chọn phông chữ cụ thể như
QFontComboBox.

Bạn có thể thêm các mục vào một QComboBox bằng cách chuyển một danh sách các chuỗi tới .thêm các mục(). Các

mục sẽ được thêm vào theo thứ tự mà chúng được cung cấp.

44
Liệt kê 17. basic / widgets_4.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QComboBox, QMainWindow

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

widget = QComboBox ()
widget.addItems ([ "Một" , "Hai" , "Ba" ])

widget.currentIndexChanged.connect (bản thân.index_changed)


widget.currentTextChanged.connect (bản thân.text_changed)

bản thân.setCentralWidget (tiện ích con)

phản đối index_changed(bản thân, tôi): # tôi là int


in(tôi)

phản đối text_changed(bản thân, s): # s là một str


in(S)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Bạn sẽ thấy một hộp tổ hợp có 3 mục nhập. Chọn một và nó sẽ được
hiển thị trong hộp.

45
Hình 12. QComboBox trên Windows, macOS và Ubuntu

Các .currentIndexChanged tín hiệu được kích hoạt khi mục hiện được chọn được cập
nhật, theo mặc định, chuyển chỉ mục của mục đã chọn trong danh sách. Tuy nhiên, khi
kết nối với tín hiệu, bạn cũng có thể yêu cầu phiên bản thay thế của tín hiệu bằng cách
thêm[str] (nghĩ về tín hiệu như một mệnh lệnh). Thay vào đó, giao diện thay thế này
cung cấp nhãn của mục hiện được chọn, thường hữu ích hơn.

QComboBox cũng có thể chỉnh sửa được, cho phép người dùng nhập các giá trị hiện không có trong

danh sách và đã chèn chúng hoặc chỉ đơn giản là được sử dụng làm giá trị. Để làm cho hộp có thể

chỉnh sửa:

widget.setEditable (Đúng vậy)

Bạn cũng có thể đặt cờ để xác định cách xử lý chèn. Các cờ này được lưu trữ trên
QComboBox chính nó và được liệt kê bên dưới—

Lá cờ Hành vi

QComboBox.NoInsert Không chèn

QComboBox.InsertAtTop Chèn làm mục đầu tiên

QComboBox.InsertAtCurrent Thay thế mục hiện được chọn

QComboBox.InsertAtBottom Chèn sau mục cuối cùng

QComboBox.InsertAfterCurrent Chèn sau mục hiện tại

QComboBox.InsertBeforeCurrent Chèn trước mục hiện tại

46
Lá cờ Hành vi

QComboBox.InsertAlphabeently Chèn theo thứ tự bảng chữ cái

Để sử dụng những điều này, hãy áp dụng cờ như sau:

widget.setInsertPolicy (QComboBox.InsertAlphabenged)

Bạn cũng có thể giới hạn số lượng mục được phép trong hộp bằng cách sử dụng
. setMaxCount, ví dụ

widget.setMaxCount (10)

47
QListBox
Tiếp theo là QListBox. Tiện ích này tương tự nhưQComboBox, ngoại trừ các tùy chọn
được trình bày dưới dạng danh sách các mục có thể cuộn được. Nó cũng hỗ trợ lựa
chọn nhiều mục cùng một lúc. MỘTQListBox cung cấp một currentItemChanged tín
hiệu gửi QListItem (phần tử của hộp danh sách) và currentTextChanged tín hiệu gửi
văn bản của mục hiện tại.

48
Liệt kê 18. basic / widgets_5.py

nhập khẩu sys

từ PyQt5.QtWidgets nhập khẩu QApplication, QListWidget, QMainWindow

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

widget = QListWidget ()
widget.addItems ([ "Một" , "Hai" , "Ba" ])

# Trong QListWidget có hai tín hiệu riêng biệt cho mặt hàng,
và str
widget.currentItemChanged.connect (bản thân.index_changed)
widget.currentTextChanged.connect (bản thân.text_changed)

bản thân.setCentralWidget (tiện ích con)

phản đối index_changed(bản thân, tôi): # Không phải là chỉ mục, tôi là QListItem
in(i.text ())

phản đối text_changed(bản thân, s): # s là một str


in(S)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Bạn sẽ thấy ba mục giống nhau, bây giờ trong một danh sách. Mục đã chọn

(nếu có) được tô sáng.

49
Hình 13. A QListBox trên Windows, macOS và Ubuntu

50
QLineEdit
Các QLineEdit widget là một hộp soạn thảo văn bản một dòng đơn giản, trong đó
người dùng có thể gõ đầu vào. Chúng được sử dụng cho các trường biểu mẫu hoặc cài
đặt không có danh sách hạn chế các đầu vào hợp lệ. Ví dụ: khi nhập địa chỉ email hoặc
tên máy tính.

Liệt kê 19. basic / widgets_6.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QLineEdit, QMainWindow

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

widget = QLineEdit ()
widget.setMaxLength (10)
widget.setPlaceholderText ( "Nhập văn bản của bạn" )

# widget.setReadOnly (True) # bỏ ghi chú điều này để chỉ đọc

widget.returnPressed.connect (bản thân.return_pressed)


widget.selectionChanged.connect (bản thân.selection_changed)
widget.textChanged.connect (bản thân.text_changed)
widget.textEdited.connect (bản thân.text_edited)

bản thân.setCentralWidget (tiện ích con)

phản đối return_pressed(bản thân):


in( "Trả lại ép!" )
bản thân.centralWidget (). setText ( "BÙM!" )

phản đối select_changed(bản thân):


in( "Lựa chọn đã thay đổi" )
in(bản thân.centralWidget (). selectText ())

51
phản đối text_changed(bản thân, s):
in( "Văn bản đã thay đổi ..." )
in(S)

phản đối text_edited(bản thân, s):


in( "Đã chỉnh sửa văn bản ..." )
in(S)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Bạn sẽ thấy một hộp nhập văn bản đơn giản với gợi ý.

Hình 14. QLineEdit trên Windows, macOS và Ubuntu

Như đã trình bày trong đoạn mã trên, bạn có thể đặt độ dài tối đa cho trường văn bản bằng
cách sử dụng .setMaxLength. Văn bản giữ chỗ, là văn bản được hiển thị cho đến khi người
dùng có thể thêm nội dung nào đó vào bằng cách sử dụng.setPlaceholderText.

Các QLineEdit có sẵn một số tín hiệu cho các sự kiện chỉnh sửa khác nhau, bao gồm cả
khi người dùng nhấn trả lại (bởi người dùng), khi lựa chọn của người dùng được thay
đổi. Ngoài ra còn có hai tín hiệu chỉnh sửa, một cho khi văn bản trong hộp đã được
chỉnh sửa và một cho khi nó đã được thay đổi. Sự khác biệt ở đây là giữa các chỉnh sửa
của người dùng và các thay đổi có lập trình. CáctextEdited tín hiệu chỉ là

52
được gửi khi người dùng chỉnh sửa văn bản.

Ngoài ra, có thể thực hiện xác thực đầu vào bằng cách sử dụng mặt nạ để xác định ký
tự nào được hỗ trợ và ở đâu. Điều này có thể được áp dụng cho lĩnh vực này như sau:

widget.setInputMask ( '000.000.000.000; _' )

Ở trên sẽ cho phép một chuỗi các số có 3 chữ số được phân tách bằng dấu chấm và do
đó có thể được sử dụng để xác thực địa chỉ IPv4.

53
QSpinBox và QDoubleSpinBox
QSpinBox cung cấp một hộp nhập số nhỏ với các mũi tên để tăng và giảm giá trị.
QSpinBox hỗ trợ số nguyên trong khi tiện ích con liên quan QDoubleSpinBox hỗ trợ
phao.

54
Liệt kê 20. basic / widgets_7.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow, QSpinBox

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

widget = QSpinBox ()
# Hoặc: widget = QDoubleSpinBox ()

widget.setMinimum (-10)
widget.setMaximum (3)
# Hoặc: widget.setRange (-10,3)

widget.setPrefix ( "$" )
widget.setSuffix ( "C" )
widget.setSingleStep (3) widget.valueChanged.connect (bản thân
# Hoặc ví dụ: 0,5 cho QDoubleSpinBox
.value_changed) widget.valueChanged [str].liên kết(bản thân
.value_changed_str)

bản thân.setCentralWidget (tiện ích con)

phản đối value_changed(bản thân, tôi):


in(tôi)

phản đối value_changed_str(bản thân, s):


in(S)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

55
- Chạy nó! Bạn sẽ thấy một hộp nhập số. Giá trị hiển thị các đơn vị sửa chữa trước và
sau và được giới hạn trong phạm vi +3 đến -10.

Hình 15. QSpinBox trên Windows, macOS và Ubuntu

Đoạn mã trình diễn ở trên hiển thị các tính năng khác nhau có sẵn cho tiện ích con.

Để đặt phạm vi giá trị có thể chấp nhận được, bạn có thể sử dụng setMinimum và
setMaximum, hoặc sử dụng cách khác Đặt dải để đặt đồng thời cả hai. Chú thích của
các loại giá trị được hỗ trợ với cả tiền tố và hậu tố có thể được thêm vào số, ví dụ: đối
với các dấu tiền tệ hoặc đơn vị sử dụng.setPrefix và .setSuffix tương ứng.

Nhấp vào mũi tên lên và xuống trên tiện ích con sẽ tăng hoặc giảm giá trị trong tiện ích
con một lượng, có thể được đặt bằng cách sử dụng .setSingleStep. Lưu ý rằng điều này
không ảnh hưởng đến các giá trị được chấp nhận đối với tiện ích con.

Cả hai QSpinBox và QDoubleSpinBox có một .valueChanged báo hiệu kích hoạt bất cứ
khi nào giá trị của chúng bị thay đổi. Sống.valueChanged tín hiệu gửi giá trị số (một int
hoặc một trôi nổi) trong khi str tín hiệu thay thế, có thể truy cập qua .valueChanged
[str] gửi giá trị dưới dạng một chuỗi, bao gồm cả ký tự tiền tố và hậu tố.

56
QSlider
QSlider cung cấp một tiện ích thanh trượt, hoạt động bên trong giống như một
QDoubleSpinBox. Thay vì hiển thị giá trị hiện tại bằng số, nó được biểu thị bằng vị trí
của tay cầm thanh trượt dọc theo chiều dài của tiện ích. Điều này thường hữu ích khi
cung cấp sự điều chỉnh giữa hai điểm cực trị, nhưng không yêu cầu độ chính xác tuyệt
đối. Việc sử dụng phổ biến nhất của loại tiện ích này là để điều khiển âm lượng.

Có một bổ sung .slider tín hiệu được kích hoạt bất cứ khi nào thanh trượt di chuyển vị
trí và .sliderPressed tín hiệu phát ra bất cứ khi nào thanh trượt được nhấp vào.

Liệt kê 21. basic / widgets_8.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow, QSlider

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

widget = QSlider ()

widget.setMinimum (-10)
widget.setMaximum (3)
# Hoặc: widget.setRange (-10,3)

widget.setSingleStep (3)

widget.valueChanged.connect (bản thân.value_changed)


widget.sliderMoved.connect (bản thân.slider_position)
widget.sliderPressed.connect (bản thân.slider_pressed)
widget.sliderReleased.connect (bản thân.slider_released)

bản thân.setCentralWidget (tiện ích con)

57
phản đối value_changed(bản thân, tôi):
in(tôi)

phản đối slider_position(bản thân, P):


in( "Chức vụ" , P)

phản đối slider_pressed(bản thân):


in( "Bị ép!" )

phản đối slider_released(bản thân):


in( "Giải thoát" )

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Bạn sẽ thấy một tiện ích con trượt. Kéo thanh trượt để thay đổi giá trị.

Hình 16. QSlider trên Windows, macOS và Ubuntu. Trên Windows, tay cầm mở rộng
đến kích thước của tiện ích.

Bạn cũng có thể tạo một thanh trượt với hướng dọc hoặc ngang bằng cách chuyển
hướng vào khi bạn tạo nó. Các cờ định hướng được xác định trongQt. không gian tên.
Ví dụ-

58
widget.QSlider (Qt.Vertical)

Hoặc là-

widget.QSlider (Qt. ngang)

59
QDial
cuối cùng QDial là một tiện ích con có thể xoay được hoạt động giống như thanh trượt, nhưng xuất hiện

dưới dạng một mặt số tương tự. Điều này trông đẹp, nhưng từ góc độ giao diện người dùng thì không thân

thiện với người dùng. Tuy nhiên, chúng thường được sử dụng trong các ứng dụng âm thanh như đại diện

cho các mặt số tương tự trong thế giới thực.

Liệt kê 22. basic / widgets_9.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QDial, QMainWindow

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

widget = QDial ()
widget.setRange (-10, 100)
widget.setSingleStep (0,5)

widget.valueChanged.connect (bản thân.value_changed)


widget.sliderMoved.connect (bản thân.slider_position)
widget.sliderPressed.connect (bản thân.slider_pressed)
widget.sliderReleased.connect (bản thân.slider_released)

bản thân.setCentralWidget (tiện ích con)

phản đối value_changed(bản thân, tôi):


in(tôi)

phản đối slider_position(bản thân, P):


in( "Chức vụ" , P)

phản đối slider_pressed(bản thân):


in( "Bị ép!" )

phản đối slider_released(bản thân):

60
in( "Giải thoát" )

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Bạn sẽ thấy một mặt số, xoay nó để chọn một số từ phạm vi.

Hình 17. QDial trên Windows, macOS và Ubuntu

Các tín hiệu giống như đối với QSlider và giữ lại các tên giống nhau (ví dụ:
. slider).

Phần này kết thúc chuyến tham quan ngắn của chúng tôi thông qua các tiện ích Qt có sẵn
trong PyQt5. Để xem danh sách đầy đủ các tiện ích có sẵn, bao gồm tất cả các tín hiệu và
thuộc tính của chúng, hãy xemTài liệu Qt.

61
QWidget
Đây là một QWidget trong bản demo của chúng tôi, nhưng bạn không thể nhìn thấy nó. Trước đây

chúng tôi đã sử dụng QWidget trong ví dụ đầu tiên của chúng tôi để tạo một cửa sổ trống. Nhưng

QWidget cũng có thể được sử dụng như một thùng đựng hàng cho các tiện ích con khác, cùng với Bố

cục, để xây dựng các cửa sổ hoặc các widget phức hợp. Chúng tôi sẽ bao gồmTạo tiện ích con tùy

chỉnh chi tiết hơn sau.

Giữ cho QWidget trong tâm trí, vì bạn sẽ thấy rất nhiều điều đó!

62
8. Bố cục
Cho đến nay, chúng tôi đã tạo thành công một cửa sổ và chúng tôi đã thêm một tiện ích vào
đó. Tuy nhiên, bạn thường sẽ muốn thêm nhiều tiện ích con vào một cửa sổ và có một số
quyền kiểm soát đối với vị trí kết thúc của các tiện ích con mà bạn thêm vào. Để sắp xếp các
widget với nhau trong Qt, chúng tôi sử dụngbố cục. Có 4 bố cục cơ bản có sẵn trong Qt,
được liệt kê trong bảng sau.

Bố trí Hành vi

QHBoxLayout Bố cục ngang tuyến tính

QVBoxLayout Bố cục dọc tuyến tính

QGridLayout Trong lưới có thể lập chỉ mục XxY

QStackedLayout Xếp chồng (z) trước mặt nhau

Có ba bố cục 2 chiều có sẵn trong Qt. CácQVBoxLayout, QHBoxLayout và QGridLayout.


Ngoài ra còn cóQStackedLayout cho phép bạn đặt tiện ích con này lên trên tiện ích con
khác trong cùng một không gian, nhưng chỉ hiển thị một bố cục tại một thời điểm.

Trong chương này, chúng ta sẽ lần lượt xem xét từng bố cục này, chỉ ra cách chúng ta có thể sử

dụng chúng để định vị các widget trong ứng dụng của mình.

Qt Designer

Bạn thực sự có thể thiết kế và bố trí giao diện của mình bằng đồ họa

- bằng Qt Designer mà chúng tôi sẽ trình bày ở phần sau. Ở đây chúng
tôi đang sử dụng mã, vì nó đơn giản hơn để hiểu và thử nghiệm với
hệ thống cơ bản.

63
Tiện ích giữ chỗ

-
Tải lên một bản sao mới của myapp.py và lưu nó dưới một tên mới
cho phần này.

Để dễ hình dung các bố cục, trước tiên chúng ta sẽ tạo một widget tùy chỉnh đơn giản
hiển thị một màu đồng nhất do chúng ta chọn. Điều này sẽ giúp phân biệt các widget
mà chúng tôi thêm vào bố cục. Thêm mã sau vào tệp của bạn dưới dạng một lớp mới ở
cấp cao nhất—

Liệt kê 23. basic / layout_colorwidget.py

từ PyQt5.QtGui nhập khẩu QColor, QPalette từ


PyQt5.QtWidgets nhập khẩu QWidget

lớp học Màu sắc(QWidget):


phản đối __trong đó__(bản thân, màu sắc):

siêu().__trong đó__()
bản thân.setAutoFillBackground (Đúng vậy)

bảng màu = bản thân.palette () Palette.setColor


(QPalette.Window, QColor (màu)) bản thân.setPalette (bảng
màu)

Trong mã này, chúng tôi phân lớp QWidget để tạo tiện ích tùy chỉnh của riêng chúng tôi
Màu sắc. Chúng tôi chấp nhận một tham số duy nhất khi tạo tiện ích con -màu sắc (Một str).
Lần đầu tiên chúng tôi đặt.setAutoFillBackground đến Đúng vậy để yêu cầu tiện ích tự động
tô nền bằng màu cửa sổ. Tiếp theo, chúng tôi thay đổi tiện ích con QPalette.Window màu
sắc mới QColor được mô tả bởi giá trị màu sắc chúng tôi đã vượt qua. Cuối cùng chúng tôi
áp dụng bảng màu này trở lại widget. Kết quả cuối cùng là một widget được tô bằng một
màu đồng nhất mà chúng tôi chỉ định khi chúng tôi tạo nó.

Nếu bạn thấy những điều trên khó hiểu thì cũng đừng quá lo lắng! Chúng tôi bao gồm
Tạo tiện ích con tùy chỉnh và Bảng màu chi tiết sau. Bây giờ, bạn đã đủ hiểu rằng bạn
có thể tạo một tiện ích con màu đỏ được tô đậm bằng mã sau—

64
Màu sắc( 'màu đỏ' )

Đầu tiên, hãy thử nghiệm cái mới của chúng tôi Màu sắc bằng cách sử dụng nó để tô toàn bộ cửa sổ bằng

một màu duy nhất. Sau khi hoàn tất, chúng tôi có thể thêm nó vào cửa sổ chính bằng cách sử dụng

. setCentralWidgetvà chúng tôi nhận được một cửa sổ màu đỏ đặc.

Liệt kê 24. basic / layout_1.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow

từ layout_colorwidget nhập khẩu Màu sắc

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

widget = Màu ( "màu đỏ" )


bản thân.setCentralWidget (tiện ích con)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Cửa sổ sẽ xuất hiện, được tô hoàn toàn bằng màu đỏ. Lưu ý cách tiện
ích mở rộng để lấp đầy tất cả không gian có sẵn.

65
Hình 18. Của chúng tôi Màu sắc widget, được tô bằng màu đỏ đặc.

Tiếp theo, chúng ta sẽ lần lượt xem xét từng bố cục Qt có sẵn. Lưu ý rằng để thêm bố cục
của chúng tôi vào cửa sổ, chúng tôi sẽ cần một hình nộmQWidget để giữ bố cục.

66
QVBoxLayout vật dụng được sắp xếp theo chiều dọc

Với QVBoxLayout bạn sắp xếp widget này một cách tuyến tính. Thêm một tiện ích sẽ
thêm nó vào cuối cột.

Hình 19. Một QVBoxLayout, được điền từ trên xuống dưới.

Cho phép thêm tiện ích của chúng tôi vào một bố cục. Lưu ý rằng để thêm bố cục vào QMainWindow chúng

ta cần áp dụng nó cho một hình nộm QWidget. Điều này cho phép chúng tôi sau đó sử dụng

. setCentralWidgetđể áp dụng tiện ích (và bố cục) cho cửa sổ. Các vật dụng có màu của
chúng tôi sẽ tự sắp xếp theo bố cục, được chứa trong QWidget trong cửa sổ. Đầu tiên,
chúng ta chỉ cần thêm tiện ích màu đỏ như trước.

67
Liệt kê 25. basic / layout_2a.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow, QVBoxLayout,
QWidget

từ layout_colorwidget nhập khẩu Màu sắc

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

layout = QVBoxLayout ()

layout.addWidget (Màu ( "màu đỏ" ))

widget = QWidget ()
widget.setLayout (bố cục) bản thân
.setCentralWidget (tiện ích con)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Lưu ý rằng đường viền hiện có thể nhìn thấy xung quanh widget màu đỏ. Đây là

khoảng cách bố cục - chúng ta sẽ xem cách điều chỉnh điều đó sau.

68
Hình 20. Của chúng tôi Màu sắc widget, trong một bố cục.

Tiếp theo, thêm một vài widget màu khác vào bố cục:

69
Liệt kê 26. basic / layout_2b.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QMainWindow, QVBoxLayout,
QWidget

từ layout_colorwidget nhập khẩu Màu sắc

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

layout = QVBoxLayout ()

layout.addWidget (Màu "màu đỏ" ))


(layout.addWidget (Màu "màu xanh lá" ))
(layout.addWidget (Màu ( "màu xanh lam"))

widget = QWidget ()
widget.setLayout (bố cục) bản thân
.setCentralWidget (tiện ích con)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

Khi chúng tôi thêm các widget, chúng sẽ tự xếp hàng dọc theo thứ tự được thêm vào.

70
Hình 21. Ba Màu sắc vật dụng được sắp xếp theo chiều dọc trong một QVBoxLayout.

71
QHBoxLayout các vật dụng được sắp xếp theo chiều ngang

QHBoxLayout giống nhau, ngoại trừ di chuyển theo chiều ngang. Thêm một widget sẽ thêm nó

vào phía bên tay phải.

Hình 22. Một QHBoxLayout, được điền từ trái sang phải.

Để sử dụng nó, chúng ta có thể chỉ cần thay đổi QVBoxLayout đến một QHBoxLayout. Các hộp bây giờ

chảy từ trái sang phải.

72
Liệt kê 27. basic / layout_3.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QHBoxLayout, QLabel,
QMainWindow, QWidget

từ layout_colorwidget nhập khẩu Màu sắc

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

layout = QHBoxLayout ()

layout.addWidget (Màu "màu đỏ" ))


(layout.addWidget (Màu "màu xanh lá" ))
(layout.addWidget (Màu ( "màu xanh lam"))

widget = QWidget ()
widget.setLayout (bố cục) bản thân
.setCentralWidget (tiện ích con)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Các vật dụng nên tự sắp xếp theo chiều ngang.

73
Hình 23. Ba Màu sắc vật dụng được sắp xếp theo chiều ngang trong một QHBoxLayout.

74
Bố cục lồng nhau
Đối với các bố cục phức tạp hơn, bạn có thể lồng các bố cục vào bên trong nhau bằng cách sử dụng

. addLayouttrên một bố cục. Dưới đây chúng tôi thêm mộtQVBoxLayout vào chính QHBoxLayout. Nếu

chúng tôi thêm một số tiện ích vàoQVBoxLayout, chúng sẽ được sắp xếp theo chiều dọc trong vị trí

đầu tiên của bố cục mẹ.

Liệt kê 28. basic / layout_4.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt từ


PyQt5.QtWidgets nhập khẩu (
QApplication,
QHBoxLayout,
QLabel,
QMainWindow,
QVBoxLayout,
QWidget,
)

từ layout_colorwidget nhập khẩu Màu sắc

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

layout1 = QHBoxLayout ()
layout2 = QVBoxLayout ()
layout3 = QVBoxLayout ()

layout2.addWidget (Màu "màu đỏ" ))


(layout2.addWidget (Màu "màu vàng" ))
(layout2.addWidget (Màu ( "màu tía" ))

layout1.addLayout (layout2)

layout1.addWidget (Màu ( "màu xanh lá" ))

75
layout3.addWidget (Màu "màu đỏ" ))
(layout3.addWidget (Màu ( "màu tía" ))

layout1.addLayout (layout3)

widget = QWidget ()
widget.setLayout (layout1) bản thân
.setCentralWidget (tiện ích con)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Các widget nên tự sắp xếp thành 3 cột theo chiều ngang, với cột đầu
tiên cũng chứa 3 widget được xếp chồng lên nhau theo chiều dọc. Thí nghiệm!

Hình 24. lồng nhau QHBoxLayout và QVBoxLayout bố cục.

Bạn có thể đặt khoảng cách xung quanh bố cục bằng cách sử dụng .setContentMargins hoặc đặt khoảng

cách giữa các phần tử bằng cách sử dụng .setSpacing.

layout1.setContentsMargins (0,0,0,0)
layout1.setSpacing (20)

Đoạn mã sau đây cho thấy sự kết hợp của các tiện ích con lồng nhau và lề bố cục và
khoảng cách.

76
Liệt kê 29. basic / layout_5.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt từ


PyQt5.QtWidgets nhập khẩu (
QApplication,
QHBoxLayout,
QLabel,
QMainWindow,
QVBoxLayout,
QWidget,
)

từ layout_colorwidget nhập khẩu Màu sắc

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

layout1 = QHBoxLayout ()
layout2 = QVBoxLayout ()
layout3 = QVBoxLayout ()

layout1.setContentsMargins (0, 0, 0, 0)
layout1.setSpacing (20)

layout2.addWidget (Màu "màu đỏ" ))


(layout2.addWidget (Màu "màu vàng" ))
(layout2.addWidget (Màu ( "màu tía" ))

layout1.addLayout (layout2)

layout1.addWidget (Màu ( "màu xanh lá" ))

layout3.addWidget (Màu "màu đỏ" ))


(layout3.addWidget (Màu ( "màu tía" ))

layout1.addLayout (layout3)

77
widget = QWidget ()
widget.setLayout (layout1) bản thân
.setCentralWidget (tiện ích con)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Bạn sẽ thấy ảnh hưởng của khoảng cách và lề. Thử nghiệm với các con
số cho đến khi bạn cảm nhận được chúng.

Hình 25. lồng nhau QHBoxLayout và QVBoxLayout bố cục với khoảng cách và lề xung
quanh các widget.

78
QGridLayout vật dụng được sắp xếp trong một lưới

Chúng hữu ích như vậy, nếu bạn thử và sử dụng QVBoxLayout và QHBoxLayout để bố trí nhiều

phần tử, ví dụ như cho một biểu mẫu, bạn sẽ thấy rất khó để đảm bảo các widget có kích thước

khác nhau được xếp thành hàng. Giải pháp cho điều này làQGridLayout.

Hình 26. Một QGridLayout hiển thị các vị trí lưới cho mỗi vị trí.

QGridLayout cho phép bạn định vị các mục cụ thể trong một lưới. Bạn chỉ định vị trí
hàng và cột cho mỗi tiện ích con. Bạn có thể bỏ qua các phần tử và chúng sẽ bị bỏ
trống.

Hình 27. Một QGridLayout với các vị trí chưa được lấp đầy.

79
Liệt kê 30. basic / layout_6.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QGridLayout, QLabel,
QMainWindow, QWidget

từ layout_colorwidget nhập khẩu Màu sắc

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

layout = QGridLayout ()

layout.addWidget (Màu "màu đỏ" ), 0, 0)


(layout.addWidget (Màu "màu xanh lá" ), 1, 0)
(layout.addWidget) (Màu "màu xanh lam"), 1, 1)
(layout.addWidget (Màu ( "màu tía" ), 2, 1)

widget = QWidget ()
widget.setLayout (bố cục) bản thân
.setCentralWidget (tiện ích con)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Bạn sẽ thấy các widget được sắp xếp trong một lưới, được căn chỉnh mặc dù bị thiếu

các mục nhập.

80
Hình 28. Bốn Màu sắc vật dụng trong một QGridLayout.

81
QStackedLayout nhiều vật dụng trong cùng một không
gian

Bố cục cuối cùng mà chúng tôi sẽ đề cập là QStackedLayout. Như đã mô tả, bố cục này
cho phép bạn định vị các phần tử ngay trước mặt nhau. Sau đó, bạn có thể chọn tiện
ích mà bạn muốn hiển thị. Bạn có thể sử dụng điều này để vẽ các lớp trong ứng dụng
đồ họa hoặc để bắt chước giao diện theo thẻ. Lưu ý còn cóQStackedWidget là một
widget vùng chứa hoạt động theo cùng một cách. Điều này rất hữu ích nếu bạn muốn
thêm một ngăn xếp trực tiếp vào mộtQMainWindow với .setCentralWidget.

Hình 29. QStackedLayout - chỉ sử dụng widget trên cùng là hiển thị, theo mặc định là
widget đầu tiên được thêm vào bố cục.

82
Hình 30. QStackedLayout, với widget thứ 2 (1) được chọn và đưa lên phía trước

83
Liệt kê 31. basic / layout_7.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt


từ PyQt5.QtWidgets nhập khẩu QApplication, QLabel, QMainWindow,
QStackedLayout, QWidget

từ layout_colorwidget nhập khẩu Màu sắc

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

layout = QStackedLayout ()

layout.addWidget (Màu "màu đỏ" ))


(layout.addWidget (Màu "màu xanh lá" ))
(layout.addWidget) (Màu "màu xanh lam"))
(layout.addWidget (Màu ( "màu vàng" ))

layout.setCurrentIndex (3)

widget = QWidget ()
widget.setLayout (bố cục) bản thân
.setCentralWidget (tiện ích con)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

- Chạy nó! Bạn sẽ chỉ thấy widget cuối cùng mà bạn đã thêm.

84
Hình 31. Một widget ngăn xếp, chỉ hiển thị một widget (widget được thêm cuối cùng).

QStackedWidget là cách thức hoạt động của các dạng xem theo tab trong ứng dụng. Chỉ một chế độ

xem ('tab') được hiển thị cùng một lúc. Bạn có thể kiểm soát tiện ích con nào sẽ hiển thị bất kỳ lúc nào

bằng cách sử dụng.setCurrentIndex () hoặc là .setCurrentWidget () để đặt mục theo chỉ mục (theo thứ

tự các tiện ích đã được thêm vào) hoặc bởi chính tiện ích đó.

Dưới đây là một bản demo ngắn sử dụng QStackedLayout kết hợp với QButton để cung
cấp giao diện dạng tab cho ứng dụng—

Liệt kê 32. basic / layout_8.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt từ


PyQt5.QtWidgets nhập khẩu (
QApplication,
QHBoxLayout,
QLabel,
QMainWindow,
QPushButton,
QStackedLayout,
QVBoxLayout,
QWidget,
)

từ layout_colorwidget nhập khẩu Màu sắc

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

85
pagelayout = QVBoxLayout () button_layout
= QHBoxLayout () bản thân.stacklayout =
QStackedLayout ()

pagelayout.addLayout (button_layout)
pagelayout.addLayout (bản thân.stacklayout)

btn = QPushButton ( "màu đỏ" )


btn.pressed.connect (bản thân.activate_tab_1)
button_layout.addWidget (btn)
bản thân.stacklayout.addWidget (Màu ( "màu đỏ" ))

btn = QPushButton ( "màu xanh lá" )


btn.pressed.connect (bản thân.activate_tab_2)
button_layout.addWidget (btn)
bản thân.stacklayout.addWidget (Màu ( "màu xanh lá" ))

btn = QPushButton ( "màu vàng" )


btn.pressed.connect (bản thân.activate_tab_3)
button_layout.addWidget (btn)
bản thân.stacklayout.addWidget (Màu ( "màu vàng" ))

widget = QWidget ()
widget.setLayout (pagelayout) bản
thân.setCentralWidget (tiện ích con)

phản đối active_tab_1(bản thân):


bản thân.stacklayout.setCurrentIndex (0)

phản đối active_tab_2(bản thân):


bản thân.stacklayout.setCurrentIndex (1)

phản đối active_tab_3(bản thân):


bản thân.stacklayout.setCurrentIndex (2)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

86
- Chạy nó! Bây giờ bạn có thể thay đổi tiện ích hiển thị bằng nút.

Hình 32. Một widget ngăn xếp, với các nút để điều khiển widget hoạt động.

Một cách hữu ích, Qt cung cấp một tiện ích tab tích hợp cung cấp kiểu bố cục này - mặc dù
nó thực sự là một tiện ích chứ không phải một bố cục. Dưới đây, bản trình diễn tab được
tạo lại bằng cách sử dụngQTabWidget-

87
Liệt kê 33. basic / layout_9.py

nhập khẩu sys

từ PyQt5.QtCore nhập khẩu Qt từ


PyQt5.QtWidgets nhập khẩu (
QApplication,
QLabel,
QMainWindow,
QPushButton,
QTabWidget,
QWidget,
)

từ layout_colorwidget nhập khẩu Màu sắc

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

tab = QTabWidget ()
tabs.setTabPosition (QTabWidget.West)
tabs.setMovable (Đúng vậy)

vì n, màu sắc trong liệt kê([ "màu đỏ" , "màu xanh lá" , ,
"màu xanh lam" "màu vàng" ]):
tabs.addTab (Màu (màu), màu)

bản thân.setCentralWidget (tab)

app = QApplication (sys.argv)

window = MainWindow ()
window.show ()

app.exec_ ()

Như bạn có thể thấy, nó đơn giản hơn một chút - và hấp dẫn hơn một chút! Bạn có thể
đặt vị trí của các tab bằng cách sử dụng các hướng chính và chuyển đổi

88
liệu các tab có thể di chuyển được với .setMoveable.

Hình 33. Các QTabWidget chứa các widget của chúng tôi, với các tab được hiển thị ở bên trái
(phía Tây). Ảnh chụp màn hình cho thấy sự xuất hiện của Windows, macOS và Ubuntu.

Bạn sẽ nhận thấy rằng thanh tab macOS trông khá khác so với những thanh khác — theo mặc

định trên các tab macOS có Viên thuốc hoặc là bong bóng Phong cách. Trên macOS, điều này

thường được sử dụng cho các bảng cấu hình theo thẻ. Đối với tài liệu, bạn có thể bậtchế độ tài

liệu để cung cấp các tab slimline tương tự như những gì bạn thấy trên các nền tảng khác. Tùy
chọn này không có hiệu lực trên các nền tảng khác.

Liệt kê 34. basic / layout_9b.py

tab = QTabWidget ()
tabs.setDocumentMode (Đúng vậy)

89
Hình 34. QTabWidget với chế độ tài liệu được đặt thành Đúng vậy trên macOS.

90
9. Hành động, Thanh công cụ & Menu
Tiếp theo, chúng ta sẽ xem xét một số yếu tố giao diện người dùng phổ biến mà bạn có thể đã

thấy trong nhiều ứng dụng khác - thanh công cụ và menu. Chúng ta cũng sẽ khám phá hệ thống

gọn gàng mà Qt cung cấp để giảm thiểu sự trùng lặp giữa các khu vực giao diện người dùng

khác nhau -QAction.

Thanh công cụ

Một trong những yếu tố giao diện người dùng thường thấy nhất là thanh công cụ. Thanh
công cụ là các thanh biểu tượng và / hoặc văn bản được sử dụng để thực hiện các tác vụ
phổ biến trong một ứng dụng mà việc truy cập thông qua menu sẽ rất phức tạp. Chúng là
một trong những tính năng giao diện người dùng phổ biến nhất được thấy trong nhiều ứng
dụng. Mặc dù một số ứng dụng phức tạp, đặc biệt là trong bộ Microsoft Office, đã chuyển
sang giao diện 'ruy-băng' theo ngữ cảnh, thanh công cụ tiêu chuẩn vẫn đủ cho phần lớn các
ứng dụng bạn sẽ tạo.

Hình 35. Các phần tử GUI tiêu chuẩn - Thanh công cụ

Các thanh công cụ Qt hỗ trợ hiển thị các biểu tượng, văn bản và cũng có thể chứa bất kỳ
widget Qt tiêu chuẩn nào. Tuy nhiên, đối với các nút, cách tiếp cận tốt nhất là sử dụng
QAction hệ thống đặt các nút trên thanh công cụ.

Hãy bắt đầu bằng cách thêm một thanh công cụ vào ứng dụng của chúng tôi.

-
Tải lên một bản sao mới của myapp.py và lưu nó dưới một tên mới
cho phần này.

Trong Qt, các thanh công cụ được tạo từ lớp QToolBar. Để bắt đầu, bạn tạo một phiên bản
của lớp và sau đó gọi.addToolbar trên QMainWindow. Truyền một chuỗi vào làm tham số
đầu tiên choQToolBar đặt tên của thanh công cụ, tên này sẽ được sử dụng để xác định
thanh công cụ trong giao diện người dùng.

91
Liệt kê 35. basic / toolbars_and_menus_1.py

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

label = QLabel ( "Xin chào!" )


label.setAlignment (Qt.AlignCenter)

bản thân.setCentralWidget (nhãn)

thanh công cụ = QToolBar ( "Thanh công cụ chính của tôi" )


bản thân.addToolBar (thanh công cụ)

phản đối onMyToolBarButtonClick(bản thân, s):


in( "nhấp chuột" , s)

- Chạy nó! Bạn sẽ thấy một thanh màu xám mỏng ở đầu cửa sổ. Đây là thanh công cụ
của bạn. Nhấp chuột phải và nhấp vào tên để tắt nó đi.

Hình 36. Một cửa sổ với thanh công cụ.

Tôi không thể lấy lại thanh công cụ của mình !?

Thật không may khi bạn xóa một thanh công cụ thì giờ đây không có chỗ để

- nhấp chuột phải để thêm lại thanh công cụ đó. Vì vậy, theo nguyên tắc

chung, bạn muốn giữ một thanh công cụ không thể xóa được hoặc cung cấp

một giao diện thay thế để bật và tắt các thanh công cụ.

Hãy làm cho thanh công cụ thú vị hơn một chút. Chúng tôi chỉ có thể thêm mộtQButton

92
tiện ích con, nhưng có một cách tiếp cận tốt hơn trong Qt giúp bạn có được một số tính năng thú vị

- và đó là thông qua QAction. QAction là một lớp cung cấp một cách để mô tả các giao
diện người dùng trừu tượng. Điều này có nghĩa là trong tiếng Anh, là bạn có thể xác
định nhiều phần tử giao diện trong một đối tượng duy nhất, được thống nhất bởi hiệu
ứng tương tác với phần tử đó. Ví dụ: thông thường có các chức năng được đại diện
trong thanh công cụ nhưng cũng có trình đơn - hãy nghĩ về một cái gì đó như Chỉnh
sửa→Cắt xuất hiện cả trong menu Chỉnh sửa nhưng cũng xuất hiện trên thanh công cụ
dưới dạng một cái kéo và cũng thông qua phím tắt Ctrl-X (Cmd-X trên macOS).

Không có QAction bạn sẽ phải xác định điều này ở nhiều nơi. Nhưng vơi QAction bạn có
thể xác định một QAction, xác định hành động được kích hoạt, rồi thêm hành động này
vào cả menu và thanh công cụ. MỗiQAction có tên, thông báo trạng thái, biểu tượng và
tín hiệu mà bạn có thể kết nối (và nhiều hơn nữa).

Xem mã bên dưới để biết cách thêm QAction.

93
Liệt kê 36. basic / toolbars_and_menus_2.py

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

label = QLabel ( "Xin chào!" )


label.setAlignment (Qt.AlignCenter)

bản thân.setCentralWidget (nhãn)

thanh công cụ = QToolBar ( "Thanh công cụ chính của tôi" )


bản thân.addToolBar (thanh công cụ)

"Nút của bạn" , bản thân)


button_action = QAction (button_action.setStatusTip
"Đây
(button_action.triggered.connect nút của bạn" )
(bảnlàthân.onMyToolBarButtonClick)
toolbar.addAction (button_action)

phản đối onMyToolBarButtonClick(bản thân, s):


in( "nhấp chuột" , s)

Để bắt đầu, chúng tôi tạo hàm chấp nhận tín hiệu từ QAction vì vậy chúng tôi có thể xem
nếu nó đang hoạt động. Tiếp theo, chúng tôi xác địnhQAction chinh no. Khi tạo cá thể,
chúng ta có thể chuyển một nhãn cho hành động và / hoặc một biểu tượng. Bạn cũng phải
vượt qua bất kỳQObject đóng vai trò là cha mẹ của hành động - ở đây chúng ta đang
chuyển bản thân như một tham chiếu đến cửa sổ chính của chúng tôi. Kỳ lạ choQAction
phần tử cha được chuyển vào làm tham số cuối cùng.

Tiếp theo, chúng ta có thể chọn đặt mẹo trạng thái - văn bản này sẽ được hiển thị trên thanh

trạng thái khi chúng ta có. Cuối cùng, chúng tôi kết nối.kích hoạt tín hiệu đến chức năng tùy

chỉnh. Tín hiệu này sẽ kích hoạt bất cứ khi nàoQAction được 'kích hoạt' (hoặc được kích hoạt).

- Chạy nó! Bạn sẽ thấy nút của mình có nhãn mà bạn đã xác định. Nhấp vào nó và
chức năng tùy chỉnh của chúng tôi sẽ phát ra "nhấp chuột" và trạng thái của nút.

94
Hình 37. Thanh công cụ hiển thị QAction cái nút.

Tại sao tín hiệu luôn sai?

-
Tín hiệu được truyền cho biết liệu hành động có đã kiểm tra, và vì nút của

chúng tôi không thể kiểm tra được - chỉ có thể nhấp vào - nên nó luôn sai.

Điều này giống nhưQPushButton chúng ta đã thấy trước đó.

Hãy thêm một thanh trạng thái.

Chúng tôi tạo một đối tượng thanh trạng thái bằng cách gọi QStatusBar và chuyển kết quả vào

. setStatusBar. Vì chúng ta không cần thay đổithanh trạng thái cài đặt chúng ta có thể
chuyển nó vào khi chúng ta tạo nó. Chúng ta có thể tạo và xác định thanh trạng thái trong
một dòng:

95
Liệt kê 37. basic / toolbars_and_menus_3.py

lớp học Cửa sổ chính(QMainWindow):


phản đối __trong đó__(bản thân):

siêu().__trong đó__()

bản thân.setWindowTitle ( "Ứng dụng của tôi" )

label = QLabel ( "Xin chào!" )


label.setAlignment (Qt.AlignCenter)

bản thân.setCentralWidget (nhãn)

thanh công cụ = QToolBar ( "Thanh công cụ chính của tôi" )


bản thân.addToolBar (thanh công cụ)

"Nút của bạn" , bản thân)


button_action = QAction (button_action.setStatusTip
"Đây
(button_action.triggered.connect nút của bạn" )
(bảnlàthân.onMyToolBarButtonClick)
toolbar.addAction (button_action)

bản thân.setStatusBar (QStatusBar (bản thân))

phản đối onMyToolBarButtonClick(bản thân, s):


in( "nhấp chuột" , s)

- Chạy nó! Di chuột qua nút thanh công cụ và bạn sẽ thấy văn bản trạng thái xuất
hiện trên thanh trạng thái ở cuối cửa sổ.

96

You might also like