PyQt5:QPushButton 上的 setParent 不会将其添加到父级

Posted

技术标签:

【中文标题】PyQt5:QPushButton 上的 setParent 不会将其添加到父级【英文标题】:PyQt5: setParent on QPushButton does not add it to parent 【发布时间】:2020-04-24 08:08:38 【问题描述】:

参考this关于向 QTabWidget 添加新标签按钮的答案, 我不确定 QPushButton 添加到 QTabBar 的位置。 我假设 pushButton 上的 setParent 方法将其添加到标签栏。 但是当我尝试实现它时,即使我在移动操作中添加了硬值,pushButton 似乎也不会出现在标签栏的任何位置。

这是一个最小的可重现示例,

from PyQt5 import QtGui, QtCore, QtWidgets
class TabBarPlus(QtWidgets.QTabBar):
    """Tab bar that has a plus button floating to the right of the tabs."""

    plusClicked = QtCore.pyqtSignal()

    def __init__(self):
        super().__init__()

        # Plus Button
        self.plusButton = QtWidgets.QPushButton("+")
        self.plusButton.setParent(self)
        self.plusButton.setFixedSize(20, 20)  # Small Fixed size
        self.plusButton.clicked.connect(self.plusClicked.emit)
        self.movePlusButton() # Move to the correct location
    # end Constructor

    def sizeHint(self):
        """Return the size of the TabBar with increased width for the plus button."""
        sizeHint = QtWidgets.QTabBar.sizeHint(self) 
        width = sizeHint.width()
        height = sizeHint.height()
        return QtCore.QSize(width+25, height)
    # end tabSizeHint

    def resizeEvent(self, event):
        """Resize the widget and make sure the plus button is in the correct location."""
        super().resizeEvent(event)

        self.movePlusButton()
    # end resizeEvent

    def tabLayoutChange(self):
        """This virtual handler is called whenever the tab layout changes.
        If anything changes make sure the plus button is in the correct location.
        """
        super().tabLayoutChange()

        self.movePlusButton()
    # end tabLayoutChange

    def movePlusButton(self):
        """Move the plus button to the correct location."""
        # Find the width of all of the tabs
        size = sum([self.tabRect(i).width() for i in range(self.count())])
        # size = 0
        # for i in range(self.count()):
        #     size += self.tabRect(i).width()

        # Set the plus button location in a visible area
        h = self.geometry().top()
        w = self.width()
        if size > w: # Show just to the left of the scroll buttons
            self.plusButton.move(w-54, h)
        else:
            self.plusButton.move(size, h)
    # end movePlusButton
# end class MyClass

class CustomTabWidget(QtWidgets.QTabWidget):
    """Tab Widget that that can have new tabs easily added to it."""

    def __init__(self, parent=None):
        super().__init__(parent)

        # Tab Bar
        self.tab = TabBarPlus()
        self.setTabBar(self.tab)

        # Properties
        self.setMovable(True)
        self.setTabsClosable(True)

        # Signals
        self.tab.plusClicked.connect(self.addTab)
        # self.tab.tabMoved.connect(self.moveTab)
        # self.tabCloseRequested.connect(self.removeTab)
    # end Constructor
# end class CustomTabWidget
class AppDemo(QtWidgets.QMainWindow):
    def __init__(self):
        super(AppDemo, self).__init__()
        self.centralwidget = QtWidgets.QWidget(self)
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setContentsMargins(0, -1, 0, -1)

        self.playlist_manager = CustomTabWidget(self.centralwidget)

        self.horizontalLayout.addWidget(self.playlist_manager)

        blankWidget = QtWidgets.QWidget(self.playlist_manager)
        self.playlist_manager.addTab(blankWidget, "New")
        self.setCentralWidget(self.centralwidget)

        self.show()
# end class AppDemo


def main():
    import sys
    app = QtWidgets.QApplication(sys.argv)

    w = AppDemo()
    w.setWindowTitle('AppDemo')
    w.show()

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

预期的行为是“+”按钮出现在所有选项卡的右侧, 但没有出现这样的按钮。

【问题讨论】:

我知道 addTab 方法存在,但我想添加一个自定义按钮来调用 add tab 方法,以便每当按下按钮时都会添加一个新选项卡。在我链接的答案中列出的其他解决方案中,使用了一个空白选项卡,但这会导致很多事情出现问题,并且由于上述解决方案已经奏效,我对为什么它现在不起作用感兴趣。 我不确定您是否了解我的问题。我将根据我在原始问题中提到的答案添加一个最小可重现的示例 对不起,我想我帮不了你;我在c++ 编码,python 的语法已经太久了。被调用的函数或方法是我可以提供帮助的事情。我将使用一个函数连接按下选项卡按钮的信号,该函数使用信号和插槽机制创建或显示按钮。因误会,已删除之前的cmets。 这也是我的想法,但这会与我的自定义标签关闭行为以及我使用标签计数的一些事情相混淆。我曾希望继承 QTabBar 并添加一个自定义 QPushButton,该按钮将保留在所有打开的选项卡的右侧,并在按下时发出一个信号,然后我可以捕获并添加选项卡。 【参考方案1】:

好的,经过一番头脑风暴后,我发现了问题所在。与 PyQt4 不同。 QTabBar 的宽度不会跨越 QTabWidget 的整个宽度,因此当 PlusButton 移动到所有选项卡的右侧时,会超过父窗口小部件的宽度并消失。

解决方案是在 QTabWidget 本身中添加 QPushButton 并从 QTabBar 发出 layoutchange。

这是一个工作示例,我已经修改了值以适合我的用例

class tabBarPlus(QTabBar):
    layoutChanged = pyqtSignal()
    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.layoutChanged.emit()

    def tabLayoutChange(self):
        super().tabLayoutChange()
        self.layoutChanged.emit()


class customTabWidget(QTabWidget):
    plusClicked = pyqtSignal()
    def __init__(self, parent=None):
        super(customTabWidget, self).__init__(parent)

        self.tab = tabBarPlus()
        self.setTabBar(self.tab)

        self.plusButton = QPushButton('+', self)
        self.plusButton.setFixedSize(35, 25)
        self.plusButton.clicked.connect(self.plusClicked.emit)
        self.setMovable(True)
        self.setTabsClosable(True)

        self.tab.layoutChanged.connect(self.movePlusButton)

    def movePlusButton(self):
        size = sum([self.tab.tabRect(i).width() for i in range(self.tab.count())])
        h = max(self.tab.geometry().bottom() - 24, 0)
        w = self.tab.width()
        print(size, w, h)
        if size > w:
            self.plusButton.move(w-self.plusButton.width(), h)
        else:
            self.plusButton.move(size-2, h)

【讨论】:

以上是关于PyQt5:QPushButton 上的 setParent 不会将其添加到父级的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PyQt5 中制作自定义 QPushButton?

python pyqt5 按钮 QPushButton

PyQt5:查找点击了哪个 QPushButton

《PyQT5软件开发 - 控件篇》第1章 按钮-1(QPushButton)

PyQt5:可以通过 QPushButton 触发 QAction 功能吗

Pyqt5 Python3 QPushButton 默认 StrongFocus 颜色或选项卡选择颜色