How to automatically add some actions to context menus
-
I am thinking through how to approach what I want to achieve. I think my desire might be "impossible", but while I am investigating I wonder if a Qt expert can point me in the right direction as to what is or is not achievable.
Qt 5.7 GUI. I have a large body of already-written code, across many files, so changes are to be kept to a minimum.
-
Many pages have a
QTableView
. I have written code to export any table to CSV, PDF etc. I wish to offer this on the right-click context menu for every such table view. I am looking for a generic solution. -
All my occurrences of
QTableView
are wrapped in my ownJTableView(QTableView)
sub-class. So we can do whatever we like in that sub-class. -
Pages which have a
JTableView
may or may not already have their own specific context menu. -
Regardless of whether the specific page has its own menu & items or not, I should like my "table export" items to appear at the bottom of the menu.
If a page does have its own table view context menu, it will have code like this:
self.tableView = JTableView(self) self.tableView.setContextMenuPolicy(Qt.CustomContextMenu) self.tableView.customContextMenuRequested.connect(self.openContextMenu) def openContextMenu(self, position): menu = JMenu(self) # JMenu is sub-class of QMenu action = menu.addAction("...") action.triggered.connect(...) menu.exec_(self.tableView.viewport().mapToGlobal(position))
So:
-
If the page's table does not have its own context menu, all I have to do is copy the above code principle directly into my
JTableView
s. -
However, if a page does have the above, I assume I am in trouble? I won't be able to intercept that menu creation to append my own entries to the bottom, will I?
So, for a generic case which should include the second possibility as well as the first, what approach can I take? I realise if I re-write all callers' code I can achieve something, but is there anything I can do which will work "generically", with as little separate-file code changes as feasible??
-
-
Well here is the outline of what I have implemented, bearing in mind my desire to make as little code changes as possible and to provide the basic export facility quite "transparently" & automatically to all existing
JTableView
s which do not have their own context menus to add in.Step 1 is just to make
JTableView
's constructor gosetContextMenuPolicy(Qt.CustomContextMenu)
and set its own slot oncustomContextMenuRequested
to its ownopenContextMenu()
method which displays its export custom menu. At this point all existingJTableView
s have the export menu without them even knowing about it/changing any of their code. That deals with 50% of client cases, with 0 lines of code changes.Step 2 is to handle those callers which already have their own
customContextMenuRequested
slot registered (after theJTableView
has been created and registered its own) with their own menu. The problem is that will lead to 2 separate menus being shown, one after the other, and the caller-specific one won't be called till after theJTableView
's one has executed, so it will be too late to do anything about that at that point.So I provide a
JTableView.replaceCustomContextMenuRequested()
which accepts the caller's own slot as a parameter: itdisconnect()
s its own slot first and then registers the caller's slot in its place. The caller's slot code builds its own menu as before, but now instead of displaying it directly it passes it toJTableView
'sopenContextMenu()
which merges that with its own export menu and then displays it for the caller. This deals with the remaining 50% of client cases, at just 2 lines of code changes per client.Ugly? Possibly. But achieves desired with minimal changes, and it's not that bad is it?
-
Hi,
In that case, shouldn't you have a base widget that contains your custom tableview and context menu handler ?
You could also have a method that generates a list of actions to add to the menu and on the widgets that have more action, re-implement that method to return the defaults values plus the one they need.
-
Well here is the outline of what I have implemented, bearing in mind my desire to make as little code changes as possible and to provide the basic export facility quite "transparently" & automatically to all existing
JTableView
s which do not have their own context menus to add in.Step 1 is just to make
JTableView
's constructor gosetContextMenuPolicy(Qt.CustomContextMenu)
and set its own slot oncustomContextMenuRequested
to its ownopenContextMenu()
method which displays its export custom menu. At this point all existingJTableView
s have the export menu without them even knowing about it/changing any of their code. That deals with 50% of client cases, with 0 lines of code changes.Step 2 is to handle those callers which already have their own
customContextMenuRequested
slot registered (after theJTableView
has been created and registered its own) with their own menu. The problem is that will lead to 2 separate menus being shown, one after the other, and the caller-specific one won't be called till after theJTableView
's one has executed, so it will be too late to do anything about that at that point.So I provide a
JTableView.replaceCustomContextMenuRequested()
which accepts the caller's own slot as a parameter: itdisconnect()
s its own slot first and then registers the caller's slot in its place. The caller's slot code builds its own menu as before, but now instead of displaying it directly it passes it toJTableView
'sopenContextMenu()
which merges that with its own export menu and then displays it for the caller. This deals with the remaining 50% of client cases, at just 2 lines of code changes per client.Ugly? Possibly. But achieves desired with minimal changes, and it's not that bad is it?