PyQt QMenu

Resumo : neste tutorial, você aprenderá como usar a QMenuclasse PyQt para criar um menu para a aplicação.

Introdução à classe PyQt QMenu

A QMenuclasse permite criar um widget de menu em barras de menu, menus de contexto e menus pop-up. Este tutorial se concentra em como usar a QMenuclasse para criar menus em barras de menus.

Para criar um menu e adicioná-lo a uma barra de menu, siga estas etapas:

  • Obtenha a barra de menu da janela principal chamando o menuBar()método do QMainWindowobjeto.
  • Adicione um menu à barra de menus usando o addMenu()método. O addMenu()retorna uma nova instância da QMenuclasse.

A seguir mostramos como adicionar três menus à barra de menus da janela principal, incluindo Arquivo, Editar e Ajuda:

menu_bar = self.menuBar()

file_menu = menu_bar.addMenu('&File')
edit_menu = menu_bar.addMenu('&Edit')
help_menu = menu_bar.addMenu('&Help')Linguagem de código:  Python  ( python )

Observe que o e comercial ( &) define um atalho para ir para o menu ao pressionar a Alttecla. Por exemplo, para ir para o menu Arquivo, pressione o atalho de teclado Alt-F.

Depois de ter um menu, você pode adicionar itens a ele. Normalmente, você cria um QActione usa o addAction()método do QMenuobjeto para adicionar ações ao menu.

Para adicionar um separador entre itens de menu, você usa o addSeparator()método do QMenuobjeto.

Exemplo de PyQt QMenu

Criaremos um aplicativo editor de texto para demonstrar como usar a QMenuclasse:

Exemplo de PyQt QMenu

Observe que os ícones usados ​​neste aplicativo são do site icon8.com . Além disso, você pode baixá- los aqui .

Aqui está o programa completo:

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)
        m = 30

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

        self.set_title()

        self.path = None

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

        container = QWidget(self)
        container.setLayout(QVBoxLayout())
        container.layout().addWidget(self.text_edit)
        self.setCentralWidget(container)
        # container.setContentsMargins(5, 5, 5, 5)

        menu_bar = self.menuBar()

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

        # new menu item
        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)

        # open menu item
        open_action = QAction(QIcon('./assets/open.png'), '&Open...', self)
        open_action.triggered.connect(self.open_document)
        open_action.setStatusTip('Open a document')
        open_action.setShortcut('Ctrl+O')
        file_menu.addAction(open_action)

        # save menu item
        save_action = QAction(QIcon('./assets/save.png'), '&Save', self)
        save_action.setStatusTip('Save the document')
        save_action.setShortcut('Ctrl+S')
        save_action.triggered.connect(self.save_document)
        file_menu.addAction(save_action)

        file_menu.addSeparator()

        # exit menu item
        exit_action = QAction(QIcon('./assets/exit.png'), '&Exit', self)
        exit_action.setStatusTip('Exit')
        exit_action.setShortcut('Alt+F4')
        exit_action.triggered.connect(self.quit)
        file_menu.addAction(exit_action)

        # edit menu
        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)

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

        # status bar
        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"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

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

    def save_document(self):
        # save the currently openned file
        if (self.path):
            return self.path.write_text(self.text_edit.toPlainText())

        # save a new file
        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)

    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())
Linguagem de código:  Python  ( python )

Como funciona.

Primeiro, crie a janela principal usando a QMainWindowclasse:

class MainWindow(QMainWindow):Linguagem de código:  Python  ( python )

Segundo, defina o ícone e a geometria da janela:

self.setWindowIcon(QIcon('./assets/editor.png'))
self.setGeometry(100, 100, 500, 300)Linguagem de código:  Python  ( python )

Terceiro, inicialize os filtros do arquivo de texto e o título da janela e chame o set_title()método para definir o título da janela:

self.filters = 'Text Files (*.txt)'
self.title = 'Editor'
self.set_title()Linguagem de código:  Python  ( python )

O set_title()método aceita um nome de arquivo. Se o nome do arquivo for omitido, o set_title()método define o título da janela como Untitled - Editor. Caso contrário, ele define o título da janela usando o formato filename - Editor:

def set_title(self, filename=None):
    title = f"{filename if filename else 'Untitled'} - {self.title}"
    self.setWindowTitle(title)Linguagem de código:  Python  ( python )

Por exemplo, ao iniciar o programa pela primeira vez ou criar um novo arquivo, o título da janela será:

PyQt QMenu - Título da janela padrão

Se você abrir um arquivo, por exemplo, C:/temp/ test.txt, o título da janela mudará para:

PyQt QMenu - Título da janela com nome de arquivo

Quarto, inicialize uma variável que conterá o caminho do arquivo que está sendo aberto para edição:

self.path = NoneLinguagem de código:  Python  ( python )

Observe que usaremos a Pathclasse do pathlibmódulo para gerenciar o caminho do arquivo, lendo um arquivo de texto e gravando no arquivo de texto.

Quinto, crie um QTextEditwidget e defina-o como widget central da janela principal:

self.text_edit = QTextEdit(self)
self.setCentralWidget(self.text_edit)Linguagem de código:  Python  ( python )

Sexto, crie um QMenuBarobjeto chamando o menuBar()método do QMainWindowobjeto:

menu_bar = self.menuBar()Linguagem de código:  Python  ( python )

Sétimo, crie ações novas, abrir, salvar e sair e adicione-as ao file_menumétodo addAction().

# new menu item
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)

# open menu item
open_action = QAction(QIcon('./assets/open.png'), '&Open...', self)
open_action.triggered.connect(self.open_document)
open_action.setStatusTip('Open a document')
open_action.setShortcut('Ctrl+O')
file_menu.addAction(open_action)

# save menu item
save_action = QAction(QIcon('./assets/save.png'), '&Save', self)
save_action.setStatusTip('Save the document')
save_action.setShortcut('Ctrl+S')
save_action.triggered.connect(self.save_document)
file_menu.addAction(save_action)

file_menu.addSeparator()

# exit menu item
exit_action = QAction(QIcon('./assets/exit.png'), '&Exit', self)
exit_action.setStatusTip('Exit')
exit_action.setShortcut('Alt+F4')
exit_action.triggered.connect(self.quit)
file_menu.addAction(exit_action)Linguagem de código:  Python  ( python )

Isso resultará no seguinte menu:

Oitavo, crie ações de desfazer e refazer e adicione-as ao menu de edição:

# edit menu
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)Linguagem de código:  Python  ( python )

Isso resultará no seguinte menu Editar:

Nono, crie a ação about e adicione-a ao menu Ajuda:

about_action = QAction(QIcon('./assets/about.png'), 'About', self)
help_menu.addAction(about_action)
about_action.setStatusTip('About')
about_action.setShortcut('F1')Linguagem de código:  Python  ( python )

Isso resultará no seguinte menu:

Décimo, adicione a barra de status à janela principal usando o statusBar()método do QMainWindowobjeto:

self.status_bar = self.statusBar()Linguagem de código:  Python  ( python )

Observe que você aprenderá mais sobre o widget da barra de status no QStatusBartutorial .

Décimo primeiro, defina o confirm_save()método que avisa ao usuário se deseja salvar o documento ou não. Se o usuário clicar no botão Sim, chame o save_document()método para salvar o texto do QTextEditwidget em um arquivo.

O confirm_save()método retorna Falsese o usuário clicar no botão Cancelar ou Truese o usuário clicar no botão Yesou :No

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 TrueLinguagem de código:  Python  ( python )

Décimo segundo, defina o new_document()método que será executado quando o usuário selecionar o item de menu Novo:

def new_document(self):
    if self.confirm_save():
        self.text_edit.setText('')
        self.set_title()Linguagem de código:  Python  ( python )

O new_document()método chama o confirm_save()método para salvar o documento e deixar o texto em QTextEditbranco. Além disso, redefine o título da janela principal.

Décimo terceiro, defina o save_document()método para salvar o texto do QTextEditwidget em um arquivo de texto:

def save_document(self):
    # save the currently openned file
    if (self.path):
        return self.path.write_text(self.text_edit.toPlainText())

    # save a new file
    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)Linguagem de código:  Python  ( python )

Se o usuário abrir um arquivo, então self.pathis not None, ele obtém o texto do QTextEditwidget chamando o toPlainText()método e salva o texto no arquivo especificado pelo objeto Path usando o write_text()método.

Se o usuário não abriu um arquivo, o método mostra uma caixa de diálogo Salvar arquivo usando QFileDialoge grava o texto no arquivo que está aberto no momento.

Décimo quarto, defina o open_document()método que mostra a caixa de diálogo Abrir arquivo e carrega o conteúdo de um arquivo de texto no QTextEditwidget:

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)Linguagem de código:  Python  ( python )

Como o nome do arquivo muda, ele chama o set_title()método para definir o título do arquivo QMainWindow.

Décimo quinto, defina o quit()método que será executado quando o usuário selecionar o item de menu Sair:

def quit(self):
    if self.confirm_save():
        self.destroy()Linguagem de código:  Python  ( python )

Finalmente, se você executar o programa no Windows, a barra de tarefas não exibirá o ícone da janela principal corretamente. Para corrigir isso, você usa o seguinte código:

import ctypes
myappid = 'mycompany.myproduct.subproduct.version'
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)Linguagem de código:  JavaScript  ( javascript )

Se você executar o programa no macOS ou Linux, este código gerará um erro de importação. Portanto, nós o envolvemos em um trybloco:

try:
    import ctypes
    myappid = 'mycompany.myproduct.subproduct.version'
    ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
finally:
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec())Linguagem de código:  JavaScript  ( javascript )

Resumo

  • Qt usa a QMenuclasse para representar um widget de menu.
  • Use o menuBar()método QMainWindowpara criar uma barra de menu e addMenu()o método para adicionar uma nova barra de menu.
  • Use o addAction()método do QMenuobjeto para adicionar um item a um menu.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *