#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
экземпляр где-то в вашем коде и вы просто хотите заполнить пункты меню в 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. Однако, похоже, я не могу заставить кнопки появляться. Не могли бы вы взглянуть на новый код?