Dec-17-2019, 01:51 AM
I have a problem related to a Qt app, but I figured it would be ok to post it in this section as is it not Qt specific. Still, I left the code in it's real context for the sake of the explanation. I need to build a QMenu that respect the structure of a file system. For example, the files in the 'files' variable below should output a menu like this:
I must store the submenus in a dict, and as a key I used the folder name. Obviously, the problem is that there are collisions when a two subfolders share the same name (here 'collision'). Their content is merged like so;
I would like to find a simple way to do this, while supporting nested files. I tried replacing the value 'ref' to make it more specific, but often the result are strange and difficult to debug. Hopefully someone will think of something clever to solve this.
The relevant part is in the 'refresh' function below;
Quote:folderless file
collision > bubu
sub 1 > action1
-------> sub2 > action2
-----------------> collision > action3
I must store the submenus in a dict, and as a key I used the folder name. Obviously, the problem is that there are collisions when a two subfolders share the same name (here 'collision'). Their content is merged like so;
Quote:folderless file
collision > bubu, action3
sub 1 > action1
-------> sub2 > action2
-----------------> collision > bubu, action3
I would like to find a simple way to do this, while supporting nested files. I tried replacing the value 'ref' to make it more specific, but often the result are strange and difficult to debug. Hopefully someone will think of something clever to solve this.
The relevant part is in the 'refresh' function below;
#!/usr/bin/python3 import sys from pathlib import Path, PurePath from PyQt5 import QtWidgets, QtCore, QtGui class Menu(QtWidgets.QMenu): def __init__(self, parent): super().__init__() self.parent = parent self.aboutToShow.connect(self.refresh) def refresh(self): ### For the sake of the example CFG_DIR = Path('/app/') files = \ [Path('/app/notes/folderless file.txt'), Path('/app/notes/collision/bubu.txt'), Path('/app/notes/sub1/action1.txt'), Path('/app/notes/sub1/sub2/action2.txt'), Path('/app/notes/sub1/sub2/collision/action3.txt')] ### self.subMenus = {} self.items = {} menus = set() self.clear() for path in files: name = path.stem folders = path.relative_to(CFG_DIR / "notes") folders = list(PurePath(folders).parts)[:-1] if not folders: self.items[path] = QtWidgets.QAction(name, checkable=True) self.addAction(self.items[path]) elif folders[0] != ".trash": for i, f in enumerate(reversed(folders), 0): ref = f ## if ref not in self.subMenus: self.subMenus[ref] = QtWidgets.QMenu(f) if i == 0: self.items[path] = QtWidgets.QAction(name, checkable=True) self.subMenus[ref].addAction(self.items[path]) else: self.subMenus[ref].addMenu(lastMenu) if i == len(folders)-1: menus.add(self.subMenus[ref]) else: lastMenu = self.subMenus[ref] for m in menus: self.addMenu(m) class Main(QtWidgets.QSystemTrayIcon): def __init__(self, parent): super().__init__(parent) self.menu = Menu(self) self.setContextMenu(self.menu) self.show() def main(): app = QtWidgets.QApplication(sys.argv) widget = Main(app) sys.exit(app.exec_()) if __name__ == '__main__': main()