Строка меню () в PyQt5

#python #user-interface #pyqt5

#python #меню #pyqt #pyqt5

Вопрос:

Я пытаюсь загрузить строку меню в свой графический интерфейс, но у моего объекта класса нет атрибута для self.MenuBar(). Может ли кто-нибудь мне помочь, никакие учебные пособия, похоже, не предлагают никаких обходных путей.

 class EmailBlast(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        bar = QtWidgets.menuBar() 
        file_menu = bar.addMenu('File')
        file_edit = bar.addMenu('Edit')        
  

Сообщение об ошибке:

 File "BasicEmail.py", line 84, in email_config
self.ui = EmailBlast()
File "BasicEmail.py", line 96, in __init__
self.menuBar()
AttributeError: 'EmailBlast' object has no attribute 'menuBar'
  

Чего мне здесь не хватает.

Обновленный проект:

 class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
    super().__init__()
    self.email_blast_widget = EmailBlast()
    self.setCentralWidget(self.email_blast_widget)
    bar = self.menuBar()
    file_file = bar.addMenu('File')         
    file_edit = bar.addMenu('Edit') 

class EmailBlast(QtWidgets.QWidget):
def __init__(self):
    super().__init__()
    self.text_box = QtWidgets.QTextEdit(self)
    self.save_button = QtWidgets.QPushButton('Save')
    self.clear_button = QtWidgets.QPushButton('Clear')        
    self.open_button = QtWidgets.QPushButton('Open')        
    self.init_ui()
  

Ответ №1:

Исключение говорит правду: QWidget у класса нет menuBar атрибута, у QMainWindow есть (а также панели инструментов и строка состояния):

Макет QMainWindow

Если у вас есть QMainWindow экземпляр где-то в вашем коде и вы просто хотите заполнить пункты меню в EmailBlast init, вы можете получить строку меню упомянутого QMainWindow вызова bar = QtWidgets.QMainWindow.menuBar() . Меню состоит из QAction s, поэтому вам, вероятно, нужно их тоже добавить.

Если у вас его нет QMainWindow , подумайте о его добавлении. QMainWindow должен быть «Центральный виджет». В вашем случае это, вероятно EmailBlast , виджет. Поскольку EmailBlast будет частью MainWindow , вам нужно создать и показать MainWindow экземпляр вместо EmailBlast .

Если у вас есть несколько элементов (кнопки, текстовые изменения и т.д.) В EmailBlast виджете, то система компоновки Qt вступает в игру почти неизбежно (быстро взгляните на фотографии в документах, чтобы понять концепцию).

Может быть довольно сложно охватить все это сразу, так что еще раз.

QMainWindow — центральная часть вашего приложения. Имеет строку меню, панели инструментов, строку состояния и центральную область, занятую центральным виджетом.

Центральный виджет — виджет, обеспечивающий основную функциональность вашего приложения (или это может быть виджет, содержащий другие виджеты, такие как QSplitter). В вашем случае это, вероятно EmailBlast , виджет.

Виджет EmailBlast предоставляет часть (повторно используемой) функциональности. Для этого он сам состоит из различных вспомогательных виджетов (редактирование текста, кнопки, флажки и так далее). Для размещения этих небольших виджетов предсказуемым образом создается макет. Виджеты размещаются внутри layout, а layout устанавливается в EmailBlast widget .

Строка меню состоит из нуля или более QMenu, которые, в свою очередь, могут иметь QAction. Сигналы QAction (обычно triggered ) подключаются к слотам для обеспечения желаемого поведения.

Вот полный пример:

 import sys
from PyQt5 import QtWidgets


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # creating EmailBlast widget and setting it as central
        self.email_blast_widget = EmailBlast(parent=self)
        self.setCentralWidget(self.email_blast_widget)
        # filling up a menu bar
        bar = self.menuBar()
        # File menu
        file_menu = bar.addMenu('File')
        # adding actions to file menu
        open_action = QtWidgets.QAction('Open', self)
        close_action = QtWidgets.QAction('Close', self)
        file_menu.addAction(open_action)
        file_menu.addAction(close_action)
        # Edit menu
        edit_menu = bar.addMenu('Edit')
        # adding actions to edit menu
        undo_action = QtWidgets.QAction('Undo', self)
        redo_action = QtWidgets.QAction('Redo', self)
        edit_menu.addAction(undo_action)
        edit_menu.addAction(redo_action)

        # use `connect` method to bind signals to desired behavior
        close_action.triggered.connect(self.close)


class EmailBlast(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        # create and set layout to place widgets
        grid_layout = QtWidgets.QGridLayout(self)

        self.text_box = QtWidgets.QTextEdit(self)
        self.save_button = QtWidgets.QPushButton('Save')
        self.clear_button = QtWidgets.QPushButton('Clear')
        self.open_button = QtWidgets.QPushButton('Open')
        # add widgets to layout. Params are:
        # (widget, fromRow, fromColumn, rowSpan=1, columnSpan=1)
        grid_layout.addWidget(self.text_box, 0, 0, 1, 3)
        grid_layout.addWidget(self.save_button, 1, 0)
        grid_layout.addWidget(self.clear_button, 1, 1)
        grid_layout.addWidget(self.open_button, 1, 2)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    # creating main window
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())
  

Этот код создает приятное маленькое приложение, подобное этому:

окно приложения

Комментарии:

1. Я рекомендую вам размещать виджеты внутри макета и размещать этот макет внутри centralWidget.

2. Идея состоит в том, чтобы помочь автору вопроса, если вы разместите код, который не работает, это смутит автора. Другой вариант — удалить эту часть и отобразить необходимый код.

3. @eyllanesc, справедливое замечание. Я попытался обновить ответ, чтобы свести к минимуму путаницу.

4. @Mikhail код отлично работает и, очевидно, является правильным способом сделать это. Однако мои кнопки меню по-прежнему не отображаются.

5. @MikhailKnyazev, спасибо за объяснение концепции window vs frame. Однако, похоже, я не могу заставить кнопки появляться. Не могли бы вы взглянуть на новый код?