动态更新 PYQT 菜单项
Dynamically Updating a PYQT Menu Item
我使用以下构造构造了一个 Qmenu 项,其中包含最近打开的文件列表。我想实时更新菜单栏,这样我就不必等到下一次应用 运行 才更新菜单栏。
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtGui import QPixmap
class Application(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(Application, self).__init__(*args, **kwargs)
self.settings = {}
self.settings['recent files'] = ['filename1', 'filename2', 'filename3']
QtWidgets.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.menu_bar()
def menu_bar(self):
file_menu = QtWidgets.QMenu('&File', self)
self.recent = file_menu.addMenu('&Open Recent')
for filename in self.settings['recent files']:
self.recent.addAction(f'{filename}', lambda source=filename: self.dialog_open_file(file_name=source))
self.menuBar().addMenu(file_menu)
def dialog_open_file(self):
self.settings['recent files'] = ['filename 4', 'filename1', 'filename2', 'filename3']
self.update_recent_files()
# do lots more stuff
def update_recent_files(self):
# Update list of recent files in Open Recent menubar <----
qApp = QtWidgets.QApplication(sys.argv)
application_window = Application()
application_window.setWindowTitle(f"My App")
application_window.show()
sys.exit(qApp.exec_())
我的实际代码运行良好(实时更新菜单除外)。它将最近文件列表写入磁盘上的持久 json(示例代码不包括该位)。当用户打开一个新文件时,文件名被成功插入到最近文件列表中。下一次应用 运行,“最近的文件”菜单显示更新后的列表。
但是,我希望最近文件的菜单列表是动态的。我如何最好地调用实时重建“最近的文件”菜单?
EDIT - 我试图澄清这个问题以关注菜单项的动态更新而不是持续维护
文件列表。
如果您想永久保存信息,那么您必须将该信息保存在硬盘驱动器上(在文件中),python 和 Qt 中有很多选择,例如 QSettings。逻辑是在创建window时加载信息,并在需要时保存(例如当window关闭时)。
import sys
from functools import cached_property
from PyQt5 import QtCore, QtWidgets, QtGui
class Application(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Application, self).__init__(parent)
QtWidgets.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.create_menu_file()
self.load_settings()
button = QtWidgets.QPushButton("Load new files")
button.clicked.connect(self.another_task)
self.setCentralWidget(button)
def create_menu_file(self):
file_menu = QtWidgets.QMenu("&File", self)
self.recentfiles_menu = file_menu.addMenu("&Open Recent")
self.recentfiles_menu.triggered.connect(self.handle_triggered_recentfile)
self.menuBar().addMenu(file_menu)
@cached_property
def settings(self):
return QtCore.QSettings()
def load_settings(self):
filenames = self.settings.value("recent_files", [])
for filename in filenames:
self.add_recent_filename(filename)
def save_settings(self):
recentfiles = []
for action in self.recentfiles_menu.actions()[::-1]:
recentfiles.append(action.text())
self.settings.setValue("recent_files", recentfiles)
@QtCore.pyqtSlot(QtWidgets.QAction)
def handle_triggered_recentfile(self, action):
self.process_filename(action.text())
def add_recent_filename(self, filename):
action = QtWidgets.QAction(filename, self)
actions = self.recentfiles_menu.actions()
before_action = actions[0] if actions else None
self.recentfiles_menu.insertAction(before_action, action)
def process_filename(self, filename):
print(filename)
def closeEvent(self, event):
super(Application, self).closeEvent(event)
self.save_settings()
def another_task(self):
# DEMO
# load new filenames
counter = len(self.recentfiles_menu.actions())
filenames = [f"foo {counter}"]
for filename in filenames:
self.add_recent_filename(filename)
qApp = QtWidgets.QApplication(sys.argv)
application_window = Application()
application_window.setWindowTitle(f"My App")
application_window.show()
sys.exit(qApp.exec_())
当菜单的内容是动态的时,我通常更喜欢使用 QMenu 的 aboutToShow
信号,它在即将打开之前被触发,并连接到一个清除它并更新它的函数它的内容。
我也用QAction.setData
存储文件名,这样可以显示自定义的文本(比如路径太长,我们可以省略,或者只显示文件名而不是完整路径)。
class Application(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(Application, self).__init__(*args, **kwargs)
file_menu = self.menuBar().addMenu('&File')
self.recent_menu = file_menu.addMenu('&Open recent')
self.recent_menu.aboutToShow.connect(self.update_recent_menu)
self.recent_menu.triggered.connect(self.open_file_from_recent)
self.settings = {}
def update_recent_menu(self):
self.recent_menu.clear()
for row, filename in enumerate(self.get_recent_files(), 1):
recent_action = self.recent_menu.addAction('&{}. {}'.format(
row, filename))
recent_action.setData(filename)
def get_recent_files(self):
recent = self.settings.get('recent files')
if not recent:
# just for testing purposes
recent = self.settings['recent files'] = ['filename 4', 'filename1', 'filename2', 'filename3']
return recent
def open_file_from_recent(self, action):
self.open_file(action.data())
def open_file(self, filename):
recent = self.get_recent_files()
if filename in recent:
recent.remove(filename)
recent.insert(0, filename)
print(filename)
我使用以下构造构造了一个 Qmenu 项,其中包含最近打开的文件列表。我想实时更新菜单栏,这样我就不必等到下一次应用 运行 才更新菜单栏。
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtGui import QPixmap
class Application(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(Application, self).__init__(*args, **kwargs)
self.settings = {}
self.settings['recent files'] = ['filename1', 'filename2', 'filename3']
QtWidgets.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.menu_bar()
def menu_bar(self):
file_menu = QtWidgets.QMenu('&File', self)
self.recent = file_menu.addMenu('&Open Recent')
for filename in self.settings['recent files']:
self.recent.addAction(f'{filename}', lambda source=filename: self.dialog_open_file(file_name=source))
self.menuBar().addMenu(file_menu)
def dialog_open_file(self):
self.settings['recent files'] = ['filename 4', 'filename1', 'filename2', 'filename3']
self.update_recent_files()
# do lots more stuff
def update_recent_files(self):
# Update list of recent files in Open Recent menubar <----
qApp = QtWidgets.QApplication(sys.argv)
application_window = Application()
application_window.setWindowTitle(f"My App")
application_window.show()
sys.exit(qApp.exec_())
我的实际代码运行良好(实时更新菜单除外)。它将最近文件列表写入磁盘上的持久 json(示例代码不包括该位)。当用户打开一个新文件时,文件名被成功插入到最近文件列表中。下一次应用 运行,“最近的文件”菜单显示更新后的列表。
但是,我希望最近文件的菜单列表是动态的。我如何最好地调用实时重建“最近的文件”菜单?
EDIT - 我试图澄清这个问题以关注菜单项的动态更新而不是持续维护 文件列表。
如果您想永久保存信息,那么您必须将该信息保存在硬盘驱动器上(在文件中),python 和 Qt 中有很多选择,例如 QSettings。逻辑是在创建window时加载信息,并在需要时保存(例如当window关闭时)。
import sys
from functools import cached_property
from PyQt5 import QtCore, QtWidgets, QtGui
class Application(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Application, self).__init__(parent)
QtWidgets.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.create_menu_file()
self.load_settings()
button = QtWidgets.QPushButton("Load new files")
button.clicked.connect(self.another_task)
self.setCentralWidget(button)
def create_menu_file(self):
file_menu = QtWidgets.QMenu("&File", self)
self.recentfiles_menu = file_menu.addMenu("&Open Recent")
self.recentfiles_menu.triggered.connect(self.handle_triggered_recentfile)
self.menuBar().addMenu(file_menu)
@cached_property
def settings(self):
return QtCore.QSettings()
def load_settings(self):
filenames = self.settings.value("recent_files", [])
for filename in filenames:
self.add_recent_filename(filename)
def save_settings(self):
recentfiles = []
for action in self.recentfiles_menu.actions()[::-1]:
recentfiles.append(action.text())
self.settings.setValue("recent_files", recentfiles)
@QtCore.pyqtSlot(QtWidgets.QAction)
def handle_triggered_recentfile(self, action):
self.process_filename(action.text())
def add_recent_filename(self, filename):
action = QtWidgets.QAction(filename, self)
actions = self.recentfiles_menu.actions()
before_action = actions[0] if actions else None
self.recentfiles_menu.insertAction(before_action, action)
def process_filename(self, filename):
print(filename)
def closeEvent(self, event):
super(Application, self).closeEvent(event)
self.save_settings()
def another_task(self):
# DEMO
# load new filenames
counter = len(self.recentfiles_menu.actions())
filenames = [f"foo {counter}"]
for filename in filenames:
self.add_recent_filename(filename)
qApp = QtWidgets.QApplication(sys.argv)
application_window = Application()
application_window.setWindowTitle(f"My App")
application_window.show()
sys.exit(qApp.exec_())
当菜单的内容是动态的时,我通常更喜欢使用 QMenu 的 aboutToShow
信号,它在即将打开之前被触发,并连接到一个清除它并更新它的函数它的内容。
我也用QAction.setData
存储文件名,这样可以显示自定义的文本(比如路径太长,我们可以省略,或者只显示文件名而不是完整路径)。
class Application(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(Application, self).__init__(*args, **kwargs)
file_menu = self.menuBar().addMenu('&File')
self.recent_menu = file_menu.addMenu('&Open recent')
self.recent_menu.aboutToShow.connect(self.update_recent_menu)
self.recent_menu.triggered.connect(self.open_file_from_recent)
self.settings = {}
def update_recent_menu(self):
self.recent_menu.clear()
for row, filename in enumerate(self.get_recent_files(), 1):
recent_action = self.recent_menu.addAction('&{}. {}'.format(
row, filename))
recent_action.setData(filename)
def get_recent_files(self):
recent = self.settings.get('recent files')
if not recent:
# just for testing purposes
recent = self.settings['recent files'] = ['filename 4', 'filename1', 'filename2', 'filename3']
return recent
def open_file_from_recent(self, action):
self.open_file(action.data())
def open_file(self, filename):
recent = self.get_recent_files()
if filename in recent:
recent.remove(filename)
recent.insert(0, filename)
print(filename)