pythonpyqt6qmenuqactionqtoolbar

PyQt6: Remove arrow from QToolBar action with popup menu


Currently I am working on a file explorer and ran into this problem; the arrow and little "button" per say I have been trying to:

enter image description here

  1. Remove the arrow entirely
  2. Join the 2nd "button" with the QAction on the Toolbar
  3. The QAction would act as a drop down menu

How would I go about trying this. I have attempted this so far:

  1. setStyleSheet("::menu-arrow { image: none; }")
  2. setStyleSheet("::icon { display: none; }")
  3. setStyleSheet("::menu-indicator { image: none; }")

QToolBar --> QAction --> QMenu

def setUpMainWindow(self):
    self.main_toolbar = QToolBar()
    self.setUpToolBar()

    self.addToolBar(self.main_toolbar)
    self.addToolBarBreak()
    ...................
    ..............
    .........



def setUpToolBar(self):
    self.main_toolbar.setFixedHeight(45)
    self.main_toolbar.setMovable(False)
    self.main_toolbar.setContextMenuPolicy(Qt.ContextMenuPolicy.DefaultContextMenu)
    self.main_toolbar.setIconSize(QSize(25, 25))
    self.main_toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)

    t_back_i = QIcon(QPixmap("icons/back.png"))
    self.t_back_act = QAction(t_back_i, "")
    self.t_back_act.setToolTip("Back")
    self.t_back_act.triggered.connect(self.directory_back_process)

    t_fwrd_i = QIcon(QPixmap("icons/forward.png"))
    self.t_frwd_act = QAction(t_fwrd_i, "")
    self.t_frwd_act.setEnabled(False)
    self.t_frwd_act.triggered.connect(self.directory_forward_process)

    t_path_output_i = QIcon(QPixmap("icons/vert-menu.png"))
    self.t_path_output_act = QAction(t_path_output_i, "")
    #self.t_path_output_act.setFixedSize(30,30)
    self.t_path_output_act.setMenu(self.window_context_menu)

    t_srch_i = QIcon(QPixmap("icons/search.png"))
    self.t_srch_act = QAction(t_srch_i, "")

    self.dirPath_h_box = QHBoxLayout()
    self.dirPath_h_box.setContentsMargins(10, 0, 10, 0)
    self.dirPath_h_box.setSpacing(5)
    self.dirPath_h_box.setAlignment(Qt.AlignmentFlag.AlignLeft)




    pathOutput_widget = QWidget()
    pathOutput_widget.setLayout(self.dirPath_h_box)
    self.pathOutput = QScrollArea()
    self.pathOutput.setFixedSize(415,30)
    self.pathOutput.setObjectName("tbFrame")

    self.pathOutput.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
    self.pathOutput.horizontalScrollBar().setStyleSheet("QScrollBar {height:0px}")
    self.pathOutput.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
    self.pathOutput.setWidgetResizable(True)
    self.pathOutput.setWidget(pathOutput_widget)



    spacer_1 = QWidget()
    spacer_1.setFixedWidth(5)
    spacer_2 = QWidget()
    spacer_2.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
    spacer_3 = QWidget()
    spacer_3.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)

    self.main_toolbar.addWidget(spacer_1)
    self.main_toolbar.addAction(self.t_back_act)
    self.main_toolbar.addAction(self.t_frwd_act)
    self.main_toolbar.addWidget(spacer_2)
    self.main_toolbar.addWidget(self.pathOutput)
    self.main_toolbar.addAction(self.t_path_output_act)
    self.main_toolbar.addAction(self.t_srch_act)
    self.main_toolbar.addWidget(spacer_3)


    self.displayPath(QDir.homePath())

def setUpContextMenu(self):
    self.window_context_menu = QMenu()
    self.window_context_menu.setObjectName("idk")
    self.window_context_menu.addAction(self.copy_directory_act)
    #self.window_context_menu.addAction(self.paste_directory_act)
    self.window_context_menu.addAction(self.new_directory_act)
    self.window_context_menu.addAction(self.delete_directory_act)
    #self.window_context_menu.addAction(self.select_all_act)


 def setUpActions(self):
    self.copy_directory_act = QAction("Copy")
    self.copy_directory_act.triggered.connect(self.copy_directory)
    self.paste_directory_act = QAction("Paste")
    #self.paste_directory_act.triggered.connect(self.paste_directory)
    self.new_directory_act = QAction("New Folder")
    self.new_directory_act.triggered.connect(self.new_directory)
    self.delete_directory_act = QAction("Delete")
    self.delete_directory_act.triggered.connect(self.delete_directory)
    self.select_all_act = QAction("Select All")
    #self.select_all_act.triggered.connect(self.select_all)

** I understand that it says "setUpContextMenu", though not relating to the actual context menu of the QToolbar.


Solution

  • If I understand your requirements correctly, you want a toolbar button (with no extra arrows) that simply opens a menu and does nothing else. This functionality is provided by ToolButtonPopupMode.InstantPopup - but to activate it, you need to access the QToolButton object that is created for the action. Once you have that, you can also set a stylesheet on it to remove the menu-arrow.

    Here's a basic demo that does that:

    screenshot

    from PyQt6 import QtCore, QtGui, QtWidgets
    
    class Window(QtWidgets.QMainWindow):
        def __init__(self):
            super().__init__()
            toolbar = self.addToolBar('Test')
            menu = QtWidgets.QMenu(self)
            menu.addAction('This')
            menu.addAction('That')
            menu.addAction('Thus')
            action = QtGui.QAction(self.style().standardIcon(
                QtWidgets.QStyle.StandardPixmap.SP_DirOpenIcon), 'Open', self)
            action.setMenu(menu)
            toolbar.addAction(action)
            button = toolbar.widgetForAction(action)
            button.setPopupMode(
                QtWidgets.QToolButton.ToolButtonPopupMode.InstantPopup)
            button.setStyleSheet('::menu-indicator {image: none}')
    
    if __name__ == '__main__':
    
        app = QtWidgets.QApplication(['Test'])
        window = Window()
        window.setGeometry(600, 100, 300, 200)
        window.show()
        app.exec()