PYQT TUTORIAL
PyQt là gì? Tạo một chương trình "Hello World". Tín hiệu và Khe (Signals & Slots) trong PyQt Cách sử dụng widget PyQt QLabel Cách sử dụng widget QPushButton của PyQt Cách sử dụng widget QLineEdit trong PyQt Cách sử dụng QVBoxLayout trong PyQt Cách sử dụng QGridLayout trong PyQt Cách sử dụng QFormLayout trong PyQt Cách sử dụng lớp QCheckBox trong PyQt Cách sử dụng lớp PyQt QRadioButton Sử dụng PyQt QComboBox để tạo Widget Combobox Cách sử dụng widget PyQt QSpinBox để tạo một spin box Cách tạo một widget nhập ngày sử dụng lớp PyQt QDateEdit Cách tạo một widget nhập giờ sử dụng lớp PyQt QTimeEdit Cách tạo một widget nhập ngày và giờ sử dụng PyQt QDateTimeEdit Cách sử dụng lớp PyQt QSlider để tạo một widget thanh trượt (slider). Cách dùng PyQt QWidget để làm container chứa các widget khác. Cách dùng lớp PyQt QTabWidget để tạo một widget dạng tab Cách dùng lớp PyQt QGroupBox để tạo một khung nhóm với tiêu đề Cách dùng lớp PyQt QTextEdit để tạo một widget cho phép chỉnh sửa Cách sử dụng lớp PyQt QProgressBar để tạo một widget progress bar Cách sử dụng lớp PyQt QMessageBox để tạo một hộp thoại Cách dùng lớp PyQt QInputDialog để tạo một hộp thoại nhập liệu Cách dùng lớp PyQt QFileDialog để tạo hộp thoại chọn file Cách sử dụng lớp QMainWindow của PyQt để tạo cửa sổ Cách sử dụng lớp PyQt QMenu để tạo menu Cách dùng lớp PyQt QToolBar để tạo các widget toolbar Cách dùng lớp QDockWidget của PyQt để tạo một widget Cách dùng lớp QStatusBar trong PyQt để tạo thanh status bar Cách sử dụng lớp QListWidget trong Python Cách sử dụng lớp QTableWidget để tạo một bảng Cách sử dụng lớp QTreeWidget của PyQt Cách sử dụng Qt Designer để thiết kế UX/UI trong PyQt. Cách sử dụng QThread trong PyQt Cách tạo các lớp QThreadPool đa luồng trong PyQt Cách hoạt động của Model/View trong PyQt Cách sử dụng Qt Style Sheets (QSS) trong PyQt. Chuyển đổi PyQt sang EXE trong PyQt
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
MỚI CẬP NHẬT

Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.

Cách sử dụng lớp PyQt QMenu để tạo menu

Trong bài viết này, bạn sẽ học cách sử dụng lớp PyQt QMenu để tạo ra các menu cho ứng dụng của mình. QMenu là một lớp quan trọng trong PyQt, giúp bạn xây dựng các menu trong thanh menu, menu ngữ cảnh (chuột phải) hoặc các menu pop-up. Việc tạo menu không chỉ giúp ứng dụng dễ sử dụng hơn mà còn cung cấp nhiều tính năng hữu ích như mở tệp, lưu tệp, hoặc thực hiện các thao tác chỉnh sửa. Bài viết này sẽ hướng dẫn bạn từng bước cách tạo và quản lý các menu trong PyQt một cách đơn giản và hiệu quả.

test php

banquyen png
Bài viết này được đăng tại freetuts.net, không được copy dưới mọi hình thức.

Giới thiệu về lớp PyQt QMenu

Lớp QMenu cho phép bạn tạo một menu trong thanh menu, menu ngữ cảnh (context menu), và menu bật lên (popup menu). Hướng dẫn này sẽ tập trung vào cách sử dụng QMenu để tạo menu trong thanh menu.

Để tạo một menu và thêm nó vào thanh menu, bạn làm theo các bước sau:

  • Lấy thanh menu của cửa sổ chính bằng cách gọi phương thức menuBar() của đối tượng QMainWindow.
  • Thêm một menu vào thanh menu bằng phương thức addMenu(). Phương thức addMenu() sẽ trả về một đối tượng mới của lớp QMenu.

Ví dụ sau đây cho thấy cách thêm ba menu vào thanh menu của cửa sổ chính, bao gồm: File, Edit, và Help:

Bài viết này được đăng tại [free tuts .net]

menu_bar = self.menuBar()

file_menu = menu_bar.addMenu('&File')
edit_menu = menu_bar.addMenu('&Edit')
help_menu = menu_bar.addMenu('&Help')

Lưu ý rằng dấu & xác định một phím tắt để nhảy đến menu khi nhấn phím Alt. Ví dụ, để nhảy đến menu File, bạn nhấn tổ hợp phím Alt-F.

Khi có menu, bạn có thể thêm các mục vào nó. Thông thường, bạn tạo một QAction và sử dụng phương thức addAction() của đối tượng QMenu để thêm các hành động vào menu.

Để thêm một dải phân cách giữa các mục menu, bạn sử dụng phương thức addSeparator() của đối tượng QMenu.

Ví dụ về QMenu trong PyQt

Chúng ta sẽ tạo một ứng dụng chỉnh sửa văn bản để minh họa cách sử dụng lớp QMenu:

PyQt QMenu Example png

Lưu ý rằng các biểu tượng được sử dụng trong ứng dụng này từ trang web icon8.com. Bạn cũng có thể tải chúng từ đây.

Dưới đây là chương trình đầy đủ:

import sys
from pathlib import Path
from PyQt6.QtWidgets import QApplication, QMainWindow, QTextEdit, QFileDialog, QMessageBox, QWidget, QVBoxLayout
from PyQt6.QtGui import QIcon, QAction

class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.setWindowIcon(QIcon('./assets/editor.png'))
        self.setGeometry(100, 100, 500, 300)

        self.title = 'Editor'
        self.filters = 'Text Files (*.txt)'
        self.path = None

        # Thiết lập tiêu đề cửa sổ
        self.set_title()

        # Tạo một widget QTextEdit để soạn thảo văn bản
        self.text_edit = QTextEdit(self)
        container = QWidget(self)
        container.setLayout(QVBoxLayout())
        container.layout().addWidget(self.text_edit)
        self.setCentralWidget(container)

        # Tạo thanh menu
        menu_bar = self.menuBar()
        file_menu = menu_bar.addMenu('&File')
        edit_menu = menu_bar.addMenu('&Edit')
        help_menu = menu_bar.addMenu('&Help')

        # Mục menu "New"
        new_action = QAction(QIcon('./assets/new.png'), '&New', self)
        new_action.setStatusTip('Tạo tài liệu mới')
        new_action.setShortcut('Ctrl+N')
        new_action.triggered.connect(self.new_document)
        file_menu.addAction(new_action)

        # Mục menu "Open"
        open_action = QAction(QIcon('./assets/open.png'), '&Open...', self)
        open_action.triggered.connect(self.open_document)
        open_action.setStatusTip('Mở tài liệu')
        open_action.setShortcut('Ctrl+O')
        file_menu.addAction(open_action)

        # Mục menu "Save"
        save_action = QAction(QIcon('./assets/save.png'), '&Save', self)
        save_action.setStatusTip('Lưu tài liệu')
        save_action.setShortcut('Ctrl+S')
        save_action.triggered.connect(self.save_document)
        file_menu.addAction(save_action)

        file_menu.addSeparator()

        # Mục menu "Exit"
        exit_action = QAction(QIcon('./assets/exit.png'), '&Exit', self)
        exit_action.setStatusTip('Thoát')
        exit_action.setShortcut('Alt+F4')
        exit_action.triggered.connect(self.quit)
        file_menu.addAction(exit_action)

        # Các hành động cho menu "Edit"
        undo_action = QAction(QIcon('./assets/undo.png'), '&Undo', self)
        undo_action.setStatusTip('Hoàn tác')
        undo_action.setShortcut('Ctrl+Z')
        undo_action.triggered.connect(self.text_edit.undo)
        edit_menu.addAction(undo_action)

        redo_action = QAction(QIcon('./assets/redo.png'), '&Redo', self)
        redo_action.setStatusTip('Làm lại')
        redo_action.setShortcut('Ctrl+Y')
        redo_action.triggered.connect(self.text_edit.redo)
        edit_menu.addAction(redo_action)

        # Mục menu "About" trong Help
        about_action = QAction(QIcon('./assets/about.png'), 'About', self)
        help_menu.addAction(about_action)
        about_action.setStatusTip('Thông tin')
        about_action.setShortcut('F1')

        # Thanh trạng thái
        self.status_bar = self.statusBar()
        self.show()

    def set_title(self, filename=None):
        title = f"{filename if filename else 'Untitled'} - {self.title}"
        self.setWindowTitle(title)

    def confirm_save(self):
        if not self.text_edit.document().isModified():
            return True

        message = f"Bạn có muốn lưu thay đổi trong {self.path if self.path else 'Untitled'}?"
        MsgBoxBtn = QMessageBox.StandardButton
        MsgBoxBtn = MsgBoxBtn.Save | MsgBoxBtn.Discard | MsgBoxBtn.Cancel

        button = QMessageBox.question(self, self.title, message, buttons=MsgBoxBtn)

        if button == MsgBoxBtn.Cancel:
            return False

        if button == MsgBoxBtn.Save:
            self.save_document()

        return True

    def new_document(self):
        if self.confirm_save():
            self.text_edit.clear()
            self.set_title()

    def save_document(self):
        if self.path:
            return self.path.write_text(self.text_edit.toPlainText())

        filename, _ = QFileDialog.getSaveFileName(self, 'Lưu tài liệu', filter=self.filters)
        if not filename:
            return

        self.path = Path(filename)
        self.path.write_text(self.text_edit.toPlainText())
        self.set_title(filename)

    def open_document(self):
        filename, _ = QFileDialog.getOpenFileName(self, filter=self.filters)
        if filename:
            self.path = Path(filename)
            self.text_edit.setText(self.path.read_text())
            self.set_title(filename)

    def quit(self):
        if self.confirm_save():
            self.destroy()

if __name__ == '__main__':
    try:
        import ctypes
        myappid = 'mycompany.myproduct.subproduct.version'
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
    finally:
        app = QApplication(sys.argv)
        window = MainWindow()
        sys.exit(app.exec())

Cách hoạt động

Tạo cửa sổ chính bằng cách sử dụng lớp QMainWindow:

class MainWindow(QMainWindow):

Thiết lập biểu tượng và kích thước của cửa sổ:

self.setWindowIcon(QIcon('./assets/editor.png'))
self.setGeometry(100, 100, 500, 300)

Khởi tạo bộ lọc tệp văn bản, tiêu đề cửa sổ và gọi phương thức set_title() để thiết lập tiêu đề cho cửa sổ:

self.filters = 'Text Files (*.txt)'
self.title = 'Editor'
self.set_title()

Phương thức set_title() nhận một tên tệp. Nếu tên tệp bị bỏ qua, phương thức set_title() sẽ thiết lập tiêu đề của cửa sổ là Untitled - Editor. Nếu có tên tệp, nó sẽ thiết lập tiêu đề của cửa sổ theo định dạng filename - Editor.

Khởi tạo biến lưu đường dẫn tệp đang được mở để chỉnh sửa:

PyQt QMenu Default Window Title png

PyQt QMenu Window Title with Filename png

self.path = None

Lưu ý rằng chúng ta sẽ sử dụng lớp Path từ mô-đun pathlib để quản lý đường dẫn tệp, đọc từ tệp văn bản và ghi vào tệp văn bản.

Tạo widget QTextEdit và đặt nó làm widget chính của cửa sổ chính:

self.text_edit = QTextEdit(self)
self.setCentralWidget(self.text_edit)

Tạo đối tượng QMenuBar bằng cách gọi phương thức menuBar() của đối tượng QMainWindow:

menu_bar = self.menuBar()

Tạo các hành động mới, mở, lưu và thoát và thêm chúng vào file_menu bằng cách sử dụng phương thức addAction():

# Mục menu mới
new_action = QAction(QIcon('./assets/new.png'), '&New', self)
new_action.setStatusTip('Create a new document')
new_action.setShortcut('Ctrl+N')
new_action.triggered.connect(self.new_document)
file_menu.addAction(new_action)

Điều này sẽ tạo ra menu với các mục mới, mở, lưu và thoát.

Tạo các hành động undo và redo và thêm chúng vào menu chỉnh sửa:

# Menu chỉnh sửa
undo_action = QAction(QIcon('./assets/undo.png'), '&Undo', self)
undo_action.setStatusTip('Undo')
undo_action.setShortcut('Ctrl+Z')
undo_action.triggered.connect(self.text_edit.undo)
edit_menu.addAction(undo_action)

redo_action = QAction(QIcon('./assets/redo.png'), '&Redo', self)
redo_action.setStatusTip('Redo')
redo_action.setShortcut('Ctrl+Y')
redo_action.triggered.connect(self.text_edit.redo)
edit_menu.addAction(redo_action)

Tạo hành động "About" và thêm nó vào menu Help:

PyQt QMenu File Menu png

about_action = QAction(QIcon('./assets/about.png'), 'About', self)
help_menu.addAction(about_action)
about_action.setStatusTip('About')
about_action.setShortcut('F1')

PyQt QMenu Edit Menu 20 1  png

Thêm thanh trạng thái vào cửa sổ chính bằng cách sử dụng phương thức statusBar() của đối tượng QMainWindow:

PyQt QMenu About Menu png

self.status_bar = self.statusBar()

Định nghĩa phương thức confirm_save() để yêu cầu người dùng lưu tài liệu hoặc không. Nếu người dùng nhấp vào nút "Yes", gọi phương thức save_document() để lưu văn bản từ widget QTextEdit vào tệp:

PyQt QMenu Confirm Save Dialog 20 1  png

def confirm_save(self):
    if not self.text_edit.document().isModified():
        return True

    message = f"Do you want to save changes to {self.path if self.path else 'Untitled'}?"
    MsgBoxBtn = QMessageBox.StandardButton
    MsgBoxBtn = MsgBoxBtn.Save | MsgBoxBtn.Discard | MsgBoxBtn.Cancel

    button = QMessageBox.question(
        self, self.title, message, buttons=MsgBoxBtn
    )

    if button == MsgBoxBtn.Cancel:
        return False

    if button == MsgBoxBtn.Save:
        self.save_document()

    return True

Định nghĩa phương thức new_document() để chạy khi người dùng chọn mục New trong menu:

def new_document(self):
    if self.confirm_save():
        self.text_edit.setText('')
        self.set_title()

Định nghĩa phương thức save_document() để lưu văn bản của widget QTextEdit vào một tệp văn bản:

def save_document(self):
    if (self.path):
        return self.path.write_text(self.text_edit.toPlainText())

    filename, _ = QFileDialog.getSaveFileName(
        self, 'Save File', filter=self.filters
    )

    if not filename:
        return

    self.path = Path(filename)
    self.path.write_text(self.text_edit.toPlainText())
    self.set_title(filename)

Định nghĩa phương thức open_document() để hiển thị hộp thoại Mở tệp và tải nội dung từ tệp văn bản vào widget QTextEdit:

def open_document(self):
    filename, _ = QFileDialog.getOpenFileName(self, filter=self.filters)
    if filename:
        self.path = Path(filename)
        self.text_edit.setText(self.path.read_text())
        self.set_title(filename)

Định nghĩa phương thức quit() để chạy khi người dùng chọn mục Exit trong menu:

def quit(self):
    if self.confirm_save():
        self.destroy()

Cuối cùng, nếu bạn chạy chương trình trên Windows, thanh tác vụ sẽ không hiển thị biểu tượng cửa sổ chính chính xác. Để khắc phục điều này, bạn sử dụng mã sau:

import ctypes
myappid = 'mycompany.myproduct.subproduct.version'
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)

Nếu bạn thực thi chương trình trên macOS hoặc Linux, mã này sẽ gây lỗi nhập khẩu. Do đó, chúng tôi bọc nó trong khối try:

try:
    import ctypes
    myappid = 'mycompany.myproduct.subproduct.version'
    ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
finally:
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())

Kết bài

Trong PyQt, lớp QMenu là công cụ chính để tạo và quản lý các menu trong ứng dụng. Khi bạn làm việc với ứng dụng có giao diện người dùng, việc sử dụng QMenu giúp bạn dễ dàng tổ chức các tùy chọn và hành động cho người dùng.

Để thêm menu vào thanh menu chính của cửa sổ ứng dụng, bạn sử dụng phương thức menuBar() của lớp QMainWindow để tạo một thanh menu. Sau đó, phương thức addMenu() cho phép bạn thêm các menu vào thanh menu đó. Mỗi menu có thể chứa nhiều mục khác nhau, được thêm vào bằng cách sử dụng phương thức addAction() của đối tượng QMenu.

Việc sử dụng QMenu không chỉ giúp cải thiện cấu trúc giao diện ứng dụng mà còn tạo ra một trải nghiệm người dùng thân thiện và dễ dàng điều hướng. Thực hiện đúng cách, bạn có thể tạo ra các ứng dụng với giao diện menu phong phú và chức năng tùy chỉnh để đáp ứng nhu cầu của người dùng.

Cùng chuyên mục:

Sử dụng câu lệnh raise from trong Python

Sử dụng câu lệnh raise from trong Python

Ngoại lệ tùy chỉnh trong Python

Ngoại lệ tùy chỉnh trong Python

Ngoại lệ Raise trong Python

Ngoại lệ Raise trong Python

Tìm hiểu về các ngoại lệ trong Python

Tìm hiểu về các ngoại lệ trong Python

Tìm hiểu về decorator dataclass trong Python

Tìm hiểu về decorator dataclass trong Python

Ví dụ sử dụng metaclass trong Python

Ví dụ sử dụng metaclass trong Python

Lớp Metaclass trong Python

Lớp Metaclass trong Python

Tìm hiểu về Class Type trong Python

Tìm hiểu về Class Type trong Python

Phương thức __new__ trong Python

Phương thức __new__ trong Python

Phân biệt Data Descriptor và Non-data Descriptor trong Python

Phân biệt Data Descriptor và Non-data Descriptor trong Python

Mô tả Descriptors trong Python

Mô tả Descriptors trong Python

Tìm hiểu về các lớp mixin trong Python

Tìm hiểu về các lớp mixin trong Python

Đa kế thừa trong Python

Đa kế thừa trong Python

Nguyên tắc đảo ngược sự phụ thuộc trong Python

Nguyên tắc đảo ngược sự phụ thuộc trong Python

Interface Segregation Principle - ISP trong Python.

Interface Segregation Principle - ISP trong Python.

Nguyên tắc thay thế Liskov - LSP trong Python

Nguyên tắc thay thế Liskov - LSP trong Python

Nguyên tắc Đóng-Mở trong Python

Nguyên tắc Đóng-Mở trong Python

Single Responsibility Principle trong Python

Single Responsibility Principle trong Python

Cách sử dụng hàm Auto() của Python

Cách sử dụng hàm Auto() của Python

Tùy chỉnh và mở rộng lớp Enum trong Python

Tùy chỉnh và mở rộng lớp Enum trong Python

Top