Tạo Ứng Dụng Desktop Đơn Giản Với Python

Nếu như bạn đã quá quen thuộc với nhưng công nghệ làm ứng dụng Desktop kinh điển như Winform, WPF (C#) hay Swing, JavaFx (Java) và nghĩ rằng Python chỉ để làm AI hay Data science thì bạn đã sai. Trong bài viết này chúng ta sẽ cùng đi xây dựng một ứng dụng Desktop trên ngôn ngữ Python và giao diện xịn xò không kém những công nghệ của C# hay Java nhé.

Chúng ta sẽ sử dụng PyQt5 – một thư viện cho phép bạn sử dụng Qt GUI, một framework rất nổi tiếng của C++. Chúng ta sẽ cùng đi tìm hiểu qua các bước:

1. Tìm hiểu, cách cài đặt PyQt5 và công cụ Qt Designer

2. Thực hành ngay với ví dụ “Ứng dụng tính tiền cho phòng khám”

2.1. Xây dựng giao diện bằng Qt Designer

2.2. Xây dựng Back-end.

Ok mở màn thôi nào

1. Cài đặt PyQt5 và công cụ Qt Designer

Như mình đã đề cập ở trên, PyQt là một thư viện được cho phép bạn sử dụng Qt GUI, một framework rất nổi tiếng của C + +. PyQt có nhiều phiên bản nhưng gần đây nhất và được tương hỗ nhiều nhất là PyQt5. Tiến hành setup nó thôi nào :

python -m pip install PyQt5 
# pip install PyQt5

Đơn giản vậy thôi. Nhưng … để phong cách thiết kế nên một giao diện mà code bằng tay thủ công thì rất khó khăn vất vả nên tất cả chúng ta có một công cụ tương hỗ kéo thả rất tuyệt vời là Qt Designer. Các bạn hoàn toàn có thể tải về và setup tại đây : DownloadQtDesigner

Okey vậy là chúng đã đã đủ vũ khí, cùng chinh chiến ngay với một ví dụ thực tế: “Phần mềm tính tiền cho phòng khám” nhé

2. Thực hành “Xây dựng Ứng dụng tính tiền cho phòng khám”

2.1 Xây dựng giao diện bằng Qt Designer

Đầu tiên tất cả chúng ta sẽ mở Qt Designer lên và ngắm nghía một chút ít nhé

Ở giao diện này họ yêu cầu chúng ta chọn template – mọi người chọn Main Window nhé. Sau đó nhấn Create

Chắc hẵn những bạn đã từng làm quen với Winform sẽ khá quen thuộc với giao diện này. Vẫn là 3 phần chính với bên trái là những Widget, ở giữa là giao diện xem trước và bên phải là tùy chỉnh những thuộc tính Property. Bây giờ hãy tưởng tượng ra trong đầu mình một giao diện và kéo thả theo ý mình nhé .

Đây là giao diện mình làm qua. Giải thích một tí nhé. Những Widget mà mình sử dụng :

  • Label: Dùng để hiển thị nội dụng text đơn thuần. Double click để chỉnh sửa nội dung.
  • Group Box: Dùng để nhóm các Widget có cùng mục đích lại với nhau.
  • Line edit: Dùng để nhập dữ liệu dạng 1 dòng (tương tự thẻ trong HTML).
  • Combo Box: Dùng để người dùng chọn các nội dung có sẵn. Các bạn double click vào để thêm các item lựa chọn.
  • Check Box: Cho phép người dụng chọn hoặc bỏ chọn 1 nội dung. Double click để chỉnh sửa label
  • Spin box: Tương tự như Line Edit nhưng chỉ được phép nhập số.
  • Push Button: Đơn giản là một cái nút nhấn. Double click để chỉnh sửa nội dung

Trên đây là những widget cơ bản của Qt, còn rất nhiều những widget hay ho khác, các bạn có thể tự tìm hiểu nhé. Đặc biệt là các widget trong nhóm Layouts sẽ giúp các widget trên ứng dụng bạn co giãn tùy theo kích cỡ window.

*Lưu ý:

  • Các bạn có thể click vào Window bao ngoài và chỉnh sửa WindowTitle để thay đổi title cửa sổ
  • Đối với các Widget chúng ta cần truy xuất ở phần Back-end để xử lí thì các bạn nên thay đổi thuộc tính objectName để dễ dàng xử lí và gọi tên.

Cuối cùng là Ctrl + R để xem lại giao diện nhé :

Bước ở đầu cuối để tạo giao diện là chuyển giao diện này sang code PyQt5. Các bạn lưu file. ui này vào ProjectFolder của mình nhé
Sau đó những bạn chạy lệnh sau :

python -m pyuic5 -x  -o 
#vi du: python -m pyuic5 -x giaodien.ui -o main.py
#hoac pyuic5 -x giaodien.ui -o main.py

pyuic5 sẽ được cài đặt cùng lúc với PyQt5, là công cụ giúp chuyển file giao diện *.ui sang *.py – một chương trình hoàn chỉnh giúp render ra giao diện như ta đã thiết kế

Bây giờ các bạn hãy chạy thử chương trình mà pyuic5 vừa tạo ra. Nếu gặp lỗi như thế này thì các bạn có thể fix theo cách sau 

  1. Copy thư mục platforms của đường dẫn “C : \ Python33 \ Lib \ site-packages \ PyQt5 \ plugins \ platforms ” ( Mỗi phiên bản Python sẽ có đường dẫn khác nhau )
  2. Paste thư mục đó vào thư mục chứa code của tất cả chúng ta
  3. Cuối cùng thêm 2 dòng này vào trên cùng của chương trình :
    import os
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = ".\\platform\\"

    Bây giờ những bạn có thế chạy lại và chương trình sẽ chạy ngon 😀

Vì mặc định PyQt5 sử dụng giao diện cũ nên bạn hoàn toàn có thể thêm lệnh setStyle ( ) để đổi khác giao diện. Đây là full code phần giao diện

from PyQt5 import QtCore, QtGui, QtWidgets
import os
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = ".\\platform\\"
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(403, 483)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(40, 10, 371, 41))
        font = QtGui.QFont()
        font.setPointSize(13)
        font.setBold(True)
        font.setWeight(75)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(40, 80, 311, 121))
        self.groupBox.setObjectName("groupBox")
        self.label_5 = QtWidgets.QLabel(self.groupBox)
        self.label_5.setGeometry(QtCore.QRect(20, 70, 47, 13))
        self.label_5.setObjectName("label_5")
        self.sex = QtWidgets.QComboBox(self.groupBox)
        self.sex.setGeometry(QtCore.QRect(80, 70, 69, 22))
        self.sex.setObjectName("sex")
        self.sex.addItem("")
        self.sex.addItem("")
        self.label_4 = QtWidgets.QLabel(self.groupBox)
        self.label_4.setGeometry(QtCore.QRect(20, 40, 47, 13))
        self.label_4.setObjectName("label_4")
        self.fullname = QtWidgets.QLineEdit(self.groupBox)
        self.fullname.setGeometry(QtCore.QRect(80, 40, 211, 20))
        self.fullname.setObjectName("fullname")
        self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox_2.setGeometry(QtCore.QRect(40, 220, 311, 161))
        self.groupBox_2.setObjectName("groupBox_2")
        self.trongRangNum = QtWidgets.QSpinBox(self.groupBox_2)
        self.trongRangNum.setGeometry(QtCore.QRect(170, 120, 42, 22))
        self.trongRangNum.setObjectName("trongRangNum")
        self.niengRangCb = QtWidgets.QCheckBox(self.groupBox_2)
        self.niengRangCb.setGeometry(QtCore.QRect(190, 30, 70, 17))
        self.niengRangCb.setObjectName("niengRangCb")
        self.label_3 = QtWidgets.QLabel(self.groupBox_2)
        self.label_3.setGeometry(QtCore.QRect(80, 120, 61, 16))
        self.label_3.setObjectName("label_3")
        self.tayTrangCb = QtWidgets.QCheckBox(self.groupBox_2)
        self.tayTrangCb.setGeometry(QtCore.QRect(60, 30, 70, 17))
        self.tayTrangCb.setObjectName("tayTrangCb")
        self.nhoRangNum = QtWidgets.QSpinBox(self.groupBox_2)
        self.nhoRangNum.setGeometry(QtCore.QRect(170, 90, 42, 22))
        self.nhoRangNum.setObjectName("nhoRangNum")
        self.label_2 = QtWidgets.QLabel(self.groupBox_2)
        self.label_2.setGeometry(QtCore.QRect(80, 90, 47, 13))
        self.label_2.setObjectName("label_2")
        self.calcBtn = QtWidgets.QPushButton(self.centralwidget)
        self.calcBtn.setGeometry(QtCore.QRect(80, 400, 61, 21))
        self.calcBtn.setObjectName("calcBtn")
        self.total = QtWidgets.QLineEdit(self.centralwidget)
        self.total.setGeometry(QtCore.QRect(150, 400, 141, 20))
        self.total.setObjectName("total")
        self.label_6 = QtWidgets.QLabel(self.centralwidget)
        self.label_6.setGeometry(QtCore.QRect(300, 400, 47, 13))
        self.label_6.setObjectName("label_6")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 403, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Ứng dụng tính tiền phòng khám"))
        self.label.setText(_translate("MainWindow", "ỨNG DỤNG TÍNH TIỀN PHÒNG KHÁM"))
        self.groupBox.setTitle(_translate("MainWindow", "Thông tin khách hàng"))
        self.label_5.setText(_translate("MainWindow", "Giới tính"))
        self.sex.setItemText(0, _translate("MainWindow", "Nam"))
        self.sex.setItemText(1, _translate("MainWindow", "Nữ"))
        self.label_4.setText(_translate("MainWindow", "Họ và tên"))
        self.groupBox_2.setTitle(_translate("MainWindow", "Dịch vụ"))
        self.niengRangCb.setText(_translate("MainWindow", "Niềng răng"))
        self.label_3.setText(_translate("MainWindow", "Trồng răng"))
        self.tayTrangCb.setText(_translate("MainWindow", "Tẩy trắng"))
        self.label_2.setText(_translate("MainWindow", "Nhổ răng"))
        self.calcBtn.setText(_translate("MainWindow", "Tính tổng"))
        self.label_6.setText(_translate("MainWindow", "vnđ"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle("Fusion")
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

2.2. Xây dựng Back-End.

Tiếp theo chúng ra sẽ thiết kế xây dựng phần xử lí, ở đây tất cả chúng ta sẽ kiến thiết xây dựng hàm tính tổng là một function thuộc lớp Ui_MainWindow. Cấu trúc để thiết lập một sự kiện như sau

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        '''
        Some setup of PyQt5
        '''
        #Event
        self.calcBtn.clicked.connect(self.calcTotal)
    
    def calcTotal(self):
        print("Press button")

Tất cả những Widget tất cả chúng ta sử dụng đều thành thuộc tính của class Ui_MainWindow với tên là objectName tất cả chúng ta đã đặt ở Qt Designer ( Hoặc bạn củng hoàn toàn có thể sửa phần code để đổi tên )
Vì vậy để gán một function cho sự kiện click ta thêm dòng này cuối method setupUi :

self.calcBtn.clicked.connect(self.calcTotal)

Với calcBtn là tên đối tượng người tiêu dùng nút nhấn và calcTotal là tên hàm xử lí nằm cùng class
Vì những Widget đều là thuộc tính của class Ui_MainWindow nên ta hoàn toàn có thể thuận tiện lấy tài liệu ra bằng cách :

    def calcTotal(self):
        print("Press button")
        print("Fullname:", self.fullname.text())
        print("Sex:", self.sex.currentText())
        print("Co tay rang?", self.tayTrangCb.checkState())
        print("Co nieng rang?", self.niengRangCb.checkState())
        print("Trong rang:", self.trongRangNum.text())
        print("Nho rang:", self.nhoRangNum.text())

Và đây là tác dụng

Công việc ở đầu cuối là tính ngân sách và show lên giao diện, việc xử lí khá đơn thuần nên mọi người tìm hiểu thêm thử nhé

    def calcTotal(self):
        prices = {
            "tayTrang": 100000,
            "niengRang": 200000,
            "nhoRang": 50000,
            "trongRang": 500000,
        }
        sum = (0 if self.tayTrangCb.checkState() == 0 else prices["tayTrang"]) \
            + (0 if self.niengRangCb.checkState() == 0 else prices["niengRang"]) \
            + int(self.nhoRangNum.text()) * prices["nhoRang"] \
            + int(self.trongRangNum.text()) * prices["trongRang"]
        print(sum)
        self.total.setText(str(sum))

Công việc của tất cả chúng ta đơn thuần là lấy số lượng hoặc kiểm tra checkBox, sau đó là nhân với đơn giá
Mình sẽ hiển thị nội dung lên textEdit bằng phương pháp setText ( ) như trên .
Để tăng phần sinh động mình sẽ hiện lên một thông tin ngân sách bằng Widget QMessageBox nhé

        msg = QtWidgets.QMessageBox()
        msg.setIcon(QtWidgets.QMessageBox.Information)
        msg.setText("Chào {} {}!".format("Ông" if self.sex.currentText() == "Nam" else "Bà", self.fullname.text()))
        msg.setInformativeText(" Tổng chi phí là {}vnđ".format(str(sum)))
        msg.setWindowTitle("Chi phí")
        msg.exec_()

Cuối cùng là tận hưởng ứng dụng Desktop đầu tiên viết bằng Python nào:

Tạm kết

Vì đây là một chương trình python nên bắt buộc bạn phải thiết lập python và vào chạy chương trình. Trong bài viết sau mình sẽ hướng dẫn những bạn chuyển một đoạn code.py sang. exe để thực thi ở mọi nơi nhé. Cảm ơn mọi người đã xem bài. See you next time <3 Link full code : source code

5/5 - (1 vote)

Bài viết liên quan

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments