Есть ли какой-нибудь способ показать вкладку справки в pyqt5?

#python #pyqt5

#python #pyqt5

Вопрос:

Я пишу код для своего проекта collage в pyqt5, где мне нужно создать одну вкладку справки. Я планирую сделать справку по содержанию, как и большинство программ, как показано на рисунке ниже (справка onlyoffice). Есть ли какой-нибудь способ легко написать это?

введите описание изображения здесь

Ответ №1:

Проблема с таким интерфейсом, который показывает несколько «вкладок», встроенных в строку заголовка, заключается в том, что это нелегко выполнимо с помощью Qt, и вы должны реализовать всю строку заголовка вручную, что непросто.

Если вы ищете более простое решение, я бы предложил использовать QTabWidget, который не отображает панель вкладок, если есть только одна вкладка. Если вы еще не используете интерфейс с вкладками с закрываемыми вкладками, вы можете настроить виджет вкладки так, чтобы разрешать закрываемые вкладки и переопределять методы по умолчанию, чтобы скрыть кнопку закрытия, если это действительно не требуется.

 class TabWidget(QtWidgets.QTabWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setDocumentMode(True)
        self.setTabsClosable(True)
        self.tabCloseRequested.connect(self.removeTab)
        self.tabBar().hide()

    def addTab(self, *args, **kwargs):
        self.insertTab(-1, *args, **kwargs)

    def insertTab(self, *args, **kwargs):
        super().insertTab(*args)
        closable = kwargs.get('closable', False)
        if not closable:
            index = args[0]
            if index < 0:
                index = self.count() - 1
            for side in QtWidgets.QTabBar.LeftSide, QtWidgets.QTabBar.RightSide:
                widget = self.tabBar().tabButton(index, side)
                if isinstance(widget, QtWidgets.QAbstractButton):
                    self.tabBar().setTabButton(index, side, None)
                    break
        self.tabBar().setVisible(self.count() > 1)

    def removeTab(self, index):
        super().removeTab(index)
        self.tabBar().setVisible(self.count() > 1)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.tabWidget = TabWidget()
        self.setCentralWidget(self.tabWidget)

        self.main = QtWidgets.QWidget()
        self.tabWidget.addTab(self.main, 'My program')
        layout = QtWidgets.QGridLayout(self.main)

        someButton = QtWidgets.QPushButton('Some button')
        layout.addWidget(someButton, 0, 0)

        layout.addWidget(QtWidgets.QLabel('Some label'), 0, 1)

        helpButton = QtWidgets.QPushButton('Show help!')
        layout.addWidget(helpButton, 0, 2)

        textEdit = QtWidgets.QTextEdit()
        layout.addWidget(textEdit, 1, 0, 1, 3)

        self.helpTab = QtWidgets.QTextBrowser()
        self.helpTab.setHtml('Hello, this is <b>help</b>!')

        helpButton.clicked.connect(self.showHelp)

    def showHelp(self):
        for i in range(self.tabWidget.count()):
            if self.tabWidget.widget(i) == self.helpTab:
                break
        else:
            self.tabWidget.addTab(self.helpTab, 'Help!', closable=True)
        self.tabWidget.setCurrentWidget(self.helpTab)
        self.tabWidget.tabBar().show()
  

Теперь, поскольку вам также нужна контекстная справка, вы можете взломать эту whatsThis() функцию. Функция «что это» позволяет отображать некоторую контекстную справку в небольшом наложенном окне, когда окно находится в режиме «что это за режим», и пользователь нажимает на виджет. Мы можем использовать фильтр событий для определения того, когда пользователь нажимает на виджет, и использовать whatsThis() свойство в качестве контекста для отображения соответствующей справки.

В следующем примере я использую простой словарь, который заполняет QTextBrowser, но вы, очевидно, можете использовать доступ к локальным файлам документации или даже к справочной платформе Qt.

Обратите внимание, что для использования этого подхода мне пришлось установить фильтр событий для всех дочерних виджетов, и это потому, что Qt может реагировать на события «что это», если у виджета действительно есть набор whatsThis() свойств. Хитрость заключается в том, чтобы установить whatsThis свойство для всех дочерних виджетов, когда окно переходит в режим what’s this, и установить специализированный фильтр событий для каждого из них, а затем удалить фильтр событий, как только останется режим what’s this.

 NoWhatsThisText = '__NoWhatsThis'
NoWhatsThisValue = 'There is no help for this object'
HelpData = {
    NoWhatsThisText: NoWhatsThisValue, 
    'someButton': 'Do something with the button', 
    'helpButton': 'Click the button to show this help', 
    'textEdit': 'Type <b>some text</b> to <i>read</i> it', 
    'mainWindow': 'A main window is cool!', 
}

class WhatsThisWatcher(QtCore.QObject):
    whatsThis = QtCore.pyqtSignal(str)
    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.WhatsThis:
            whatsThis = source.whatsThis()
            while whatsThis == NoWhatsThisText:
                if not source.parent():
                    break
                source = source.parent()
                whatsThis = source.whatsThis()
            self.whatsThis.emit(whatsThis)
            event.accept()
            return True
        return super().eventFilter(source, event)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        # ...

        whatsThisAction = self.menuBar().addAction('What's this?')
        whatsThisAction.triggered.connect(
            QtWidgets.QWhatsThis.enterWhatsThisMode)

        self.watchedWhatsThis = []
        self.whatsThisWatcher = WhatsThisWatcher()
        self.whatsThisWatcher.whatsThis.connect(self.showHelp)
        self.installEventFilter(self.whatsThisWatcher)

        someButton.setWhatsThis('someButton')
        helpButton.setWhatsThis('helpButton')
        textEdit.setWhatsThis('textEdit')
        self.setWhatsThis('mainWindow')

    def showHelp(self, context=''):
        # ...
        if context:
            self.helpTab.setHtml(HelpData.get(context, NoWhatsThisValue))
        if QtWidgets.QWhatsThis.inWhatsThisMode():
            QtWidgets.QWhatsThis.leaveWhatsThisMode()
  

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

1. Спасибо @musicamante, извините за поздний ответ. Мне кажется, что это слишком сложно для понимания. У вас есть простое решение для этого? Например, у меня есть PDF-файл со всей темой, описанной в справке. Как я могу включить этот файл?

2. @ParthPatel используйте QSplitter в качестве центрального виджета и добавьте средство просмотра pdf или используйте для него QDockWidget.