Python 删除动态创建的Qmenu项

Python 删除动态创建的Qmenu项,python,pyqt,pyqt5,qmenu,qsettings,Python,Pyqt,Pyqt5,Qmenu,Qsettings,我有一个Qmenu,我通过加载带有Qsettings的列表来创建它,我试图通过在QListQWidget中加载列表并删除所选项目来从菜单中删除项目。目前我可以删除列表小部件中的菜单项,它也可以从qsettings中删除它们,但我不知道如何在不重新启动的情况下从菜单中删除这些项。我尝试过各种方法,如removeAction等,但都没有找到答案。 这是我的密码: import functools import sys from PyQt5 import QtCore from PyQt5.QtWid

我有一个Qmenu,我通过加载带有Qsettings的列表来创建它,我试图通过在QListQWidget中加载列表并删除所选项目来从菜单中删除项目。目前我可以删除列表小部件中的菜单项,它也可以从qsettings中删除它们,但我不知道如何在不重新启动的情况下从菜单中删除这些项。我尝试过各种方法,如removeAction等,但都没有找到答案。
这是我的密码:

import functools
import sys
from PyQt5 import QtCore
from PyQt5.QtWidgets import QWidget, QPushButton, QHBoxLayout, \
    QApplication, QAction, QMenu, QListWidgetItem, \
    QListWidget, QGridLayout

class MainWindow(QWidget):
    settings = QtCore.QSettings('test_org', 'my_app')
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.layout = QHBoxLayout()
        self.menu_btn = QPushButton()
        self.menu = QMenu()
        self.add_menu = self.menu.addMenu("Menu")
        self.menu_btn.setMenu(self.menu)
        self.open_list_btn = QPushButton('open list')

        self.load_items = self.settings.value('menu_items', [])
        for item in self.load_items:
            self.action = QAction(item[0], self)
            self.action.setData(item)
            self.add_menu.addAction(self.action)
            self.action.triggered.connect(functools.partial(self.menu_clicked, self.action))

        self.layout.addWidget(self.menu_btn)
        self.layout.addWidget(self.open_list_btn)
        self.setLayout(self.layout)
        self.open_list_btn.clicked.connect(self.open_window)

    def open_window(self):
        self.create_menu_item = List()
        self.create_menu_item.show()

    def menu_clicked(self, item):
        itmData = item.data()
        print(itmData)

class List(QWidget):
    settings = QtCore.QSettings('test_org', 'my_app')
    def __init__(self, parent=None):
        super(List, self).__init__(parent)
        self.menu_items = self.settings.value('menu_items', [])
        self.layout = QGridLayout()
        self.list = QListWidget()
        self.remove_btn = QPushButton('Remove')
        self.layout.addWidget(self.list, 1, 1, 1, 1)
        self.layout.addWidget(self.remove_btn, 2, 1, 1, 1)
        self.setLayout(self.layout)
        self.remove_btn.clicked.connect(self.remove_items)

        for item in self.menu_items:
            self.item = QListWidgetItem()
            self.item.setText(str(item[0]))
            self.list.addItem(self.item)

    def remove_items(self):
        self.menu_items = self.settings.value('menu_items', [])
        del self.menu_items[self.list.currentRow()]
        self.settings.setValue('menu_items', self.menu_items)
        listItems = self.list.selectedItems()
        if not listItems: return
        for item in listItems:
            self.list.takeItem(self.list.row(item))

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec_()
有人有什么想法吗

编辑:

这是QSettings中列表的结构。我用这个加载菜单,用这个加载QlistWidget。当我为QListWidget删除这些项目时,我试图让菜单也删除它们

mylist = ['item_name',['itemdata1', 'itemdata2', 'itemdata3'], 
          'item_name2',['itemdata1', 'itemdata2', 'itemdata3'], 
          'item_name3',['itemdata1', 'itemdata2', 'itemdata3']]

我认为您使用的数据结构是不正确的,因为当我执行代码时,它会生成两倍于
QAction
s的数据,我建议的结构是一个字典,其中键是
QAction
的名称和数据列表的值:

{
 'item0': ['itemdata00', 'itemdata01', 'itemdata02'],
 'item1': ['itemdata10', 'itemdata11', 'itemdata12'],
  ...
}
要构建初始配置,请使用以下脚本:

创建_设置.py

from PyQt5 import QtCore

if __name__ == '__main__':
    settings = QtCore.QSettings('test_org', 'my_app')
    d = {}
    for i in range(5):
        key = "item{}".format(i)
        value = ["itemdata{}{}".format(i, j) for j in range(3)]
        d[key] = value
    settings.setValue('menu_items', d)
    print(d)
    settings.sync()
另一方面,我认为您想要处理销毁
QAction
s的小部件应该接管相应的
QMenu
,如下所示:

import sys
from PyQt5 import QtCore, QtWidgets

class MainWindow(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        layout = QtWidgets.QHBoxLayout(self)

        menu_btn = QtWidgets.QPushButton()
        open_list_btn = QtWidgets.QPushButton('open list')
        layout.addWidget(menu_btn)
        layout.addWidget(open_list_btn)

        menu = QtWidgets.QMenu()
        menu_btn.setMenu(menu)

        self.menu_manager = MenuManager("menu_items", "Menu")
        menu.addMenu(self.menu_manager.menu)
        self.menu_manager.menu.triggered.connect(self.menu_clicked)
        open_list_btn.clicked.connect(self.menu_manager.show)

    def menu_clicked(self, action):
        itmData = action.data()
        print(itmData)


class MenuManager(QtWidgets.QWidget):
    def __init__(self, key, menuname, parent=None):
        super(MenuManager, self).__init__(parent)
        self.settings = QtCore.QSettings('test_org', 'my_app')
        self.key = key

        self.layout = QtWidgets.QVBoxLayout(self)
        self.listWidget = QtWidgets.QListWidget()
        self.remove_btn = QtWidgets.QPushButton('Remove')
        self.layout.addWidget(self.listWidget)
        self.layout.addWidget(self.remove_btn)
        self.remove_btn.clicked.connect(self.remove_items)

        self.menu = QtWidgets.QMenu(menuname)

        load_items = self.settings.value(self.key, [])
        for name, itemdata in load_items.items():
            action = QtWidgets.QAction(name, self.menu)
            action.setData(itemdata)
            self.menu.addAction(action)

            item = QtWidgets.QListWidgetItem(name)
            item.setData(QtCore.Qt.UserRole, action)
            self.listWidget.addItem(item)

    def remove_items(self):
        for item in self.listWidget.selectedItems():
            it = self.listWidget.takeItem(self.listWidget.row(item))
            action = it.data(QtCore.Qt.UserRole)
            self.menu.removeAction(action)
        self.sync_data()

    def sync_data(self):
        save_items = {}
        for i in range(self.listWidget.count()):
            it = self.listWidget.item(i)
            action = it.data(QtCore.Qt.UserRole)
            save_items[it.text()] = action.data()

        self.settings.setValue(self.key, save_items)
        self.settings.sync()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

我弄明白了。我不确定是否有更好的方法,但我使用了对象名。
在主窗口中,我使用for循环内列表列表中每个列表的第一项将objectNames设置为
self.action
,如下所示:

self.action.setObjectName(item[0])
然后我在MainWindow类中创建了这个函数:

def remove_menu_item(self, value):
    self.add_menu.removeAction(self.findChild(QAction, value))
然后我补充说:

w.remove_menu_item(item.text())

添加到List类中的remove函数,以获取列表列表中相同的第一项,该项现在是QActions的objectName。

您可以显示配置文件。我当前只是手动将列表添加到注册表中,并使用qsettings。它们看起来像mylist=['item_name',['itemdata1','itemdata2','itemdata3']]几乎只是第一个项目的项目名称,然后是一个包含随机数据的列表。我已经用objectnames解决了这个问题,但对于我尝试这种方法来说,效果仍然不太好。据我所知,您有一个QListWidget,其中包含QAction的名称,您希望如果删除某些QListWidgetItem,它将删除相应的QAction,而无需重新启动应用程序,我说得对吗?是的,没错。当我从列表中删除时,我希望菜单也能更新以反映删除情况。我刚刚发布了我的答案,但我会花几分钟来检查你的答案。@Richard如评论中所述,你的方法可能会失败。是的,我明白,我不确定是否有人会在你9秒钟后回复并发布我的答案。感谢您的帮助,我现在正在查看您的答案。@Richard等待2小时是一个很短的时间,认为没有人会回应,另一方面,发布答案总是好的,但最好指出局限性,以便希望使用您的解决方案的人知道什么可能失败。如果我的答案对您有帮助,请不要忘记将其标记为正确:)谢谢您的帮助,答案比我的好得多。使用您的方法可能会失败,例如,当您有一个qmen,其中的QAction与属于另一个qmen的另一个QAction具有相同的文本时。