删除动态创建的Qmenu项目

时间:2018-07-13 22:57:59

标签: python pyqt pyqt5 qmenu qsettings

我有一个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']]

2 个答案:

答案 0 :(得分:2)

我认为您使用的数据结构不正确,因为当我执行代码时,它生成的QAction数量是原来的两倍,我建议的结构是字典,其中的键是{{1 }}和数据列表的值:

QAction

要构建初始配置,请使用以下脚本:

create_settings.py

{
 'item0': ['itemdata00', 'itemdata01', 'itemdata02'],
 'item1': ['itemdata10', 'itemdata11', 'itemdata12'],
  ...
}

另一方面,我认为您要处理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,如下所示:

QMenu

答案 1 :(得分:0)

我明白了。我不确定是否有更好的方法,但是我使用对象名称来做到这一点。
在MainWindow中,使用如下这样的for循环内列表列表中每个列表的第一项,将objectNames设置为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_())

self.action

然后我在MainWindow类中创建了此函数:

self.action.setObjectName(item[0])

然后我添加了此内容:

def remove_menu_item(self, value):
    self.add_menu.removeAction(self.findChild(QAction, value))

到List类中的remove函数以获取列表列表中的第一项,现在它是QAction的objectName。