It looks like the only way to get the selected item of a gtk.TreeView() is to actually click on it :
tree_selection = self.treeview.get_selection()
tree_selection.connect('changed', self.my_callback)
self.treeview.connect('row-activated', self.my_other_callback)
But what if I'm listing files in my treeview, and need a "file properties" menu item?
Or a play button, that needs to access selected file to pass the filename to a player class / method ?
Bonus question : How to call my_other_callback from tree_selection.connect('changed', ...) (that does not seem to return all the row data..?) or in other words, how to pass treeview and path to the callback?
To get the selection of a tree view, call the get_selected_rows method of the gtk.TreeSelection object. You can call it at any place from which you can access the tree view.
It is unclear why you want to pass the tree view to my_other_callback since it, being a method on your class, can access it as self.treeview. But if you want to do it anyway, you can add the tree view (or any other Python object) as an additional argument to connect:
tree_selection.connect('changed', self.my_other_callback, self.treeview)
For an even finer-grained control of how the callback is invoked, use a lambda:
tree_selection.connect('changed', lambda *args: self.my_other_callback(self.treeview))
This allows you to use the same handler for multiple signals without having to declare the handler as accepting *args.
Related
I want to override the uom._compute_price() and compute_quantity() in odoo to add product as an argument.
the problem is that these functions are called in many other functions in many other modules like stock, account, sale, purchase.
So I have to override each calling function which is about 140 occurrences .
Is there a better way to implement this without modifying the 140 calls ?
for ex. in the overridden functions, can I get the original caller object and its attributes ?
If there is a way to get the product from self or any other object, you can
make product_id a keyword only argument and check
it's not None, else you set it your self from an object.
def _compute_price(self, same_arguments,*,product_id=None)
if product_id is None:
product_id = # get the id from something
# your code here
If you can't get the product_id from anywhere I hope you find
and solution for that or you have to edit all calls.
Changing an upstream method arguments is not recommended, and you are discovering the why.
However, your calls to it can add a key in the context, and the overridden method can react to it. Example:
def _compute_price(self, original_args):
if self.env.context.get("product_id"):
# Do your stuff here
return super()._compute_price(original_args)
Then, from other parts of your module, call the method with that context key:
uom.with_context(product_id=product.id)._compute_price(original_args)
Another option would be to add the context key in the overriden method itself, if you want it to be present under every call:
def _compute_price(self, original_args):
# Get the product somehow here
return super(type(self), self.with_context(product_id=product.id))._compute_price(original_args)
However, keep in mind that only addons that are aware of this context and react to it actually need it. The 1st approach should be the most accurate for most cases.
I'm trying to add a functionality to a text box where a user can highlight a word, right click and be able to choose whether to define or get synonyms for the highlighted word. I coded a context menu but it only appears when I click outside of the textbox. Is there anyway I can add functions to the default context menu that includes Copy, Paste, etc.? Here is my code for the context menu.
self.setContextMenuPolicy(Qt.ActionsContextMenu)
defineAction = QtWidgets.QAction("Define", self)
defineAction.triggered.connect(lambda: self.define(event))
self.addAction(defineAction)
synonymAction = QtWidgets.QAction("Find Synonyms", self)
synonymAction.triggered.connect(lambda: self.synonym(event))
self.addAction(synonymAction)
You'll need to subclass the text edit widget and override createStandardContextMenu(point).
In your overridden method, cal the base call implementation to get the standard context menu object (it returns QMenu). Modify this menu with custom actions and then return the menu.
The function will be called when the user requests a context menu.
See http://doc.qt.io/qt-5/qplaintextedit.html#createStandardContextMenu for more details
EDIT: You can subclass like this
class MyTextEdit(QLineEdit):
def createStandardContextMenu(self, menu):
#as above, reimplement this method
Then you use that class instead of QLineEdit when you make your GUI.
Alternatively I've remembered there is a signal called customContextMenuRequested. You use this instead like this
#assume you have the textbox in a variable called self.my_textbox
self.my_textbox.setContextMenuPolicy(Qt.CustomContextMenu)
self.my_textbox.customContextMenuRequested.connect(self.generate_context_menu)
and then add a method to the class that generates the GUI like:
def generate_context_menu(self, location):
menu = self.my_textbox.createStandardContextMenu()
# add extra items to the menu
# show the menu
menu.popup(self.mapToGlobal(location))
I thought it would be possible to create a custom Dexterity factory that calls the default factory and then adds some subcontent (in my case Archetypes-based) to the created 'parent' Dexterity content.
I have no problem creating and registering the custom factory.
However, regardless of what method I use (to create the AT subcontent), the subcontent creation fails when attempted from within the custom factory.
I've tried everything from plone.api to invokeFactory to direct instantiation of the AT content class.
In most cases, traceback shows the underlying Plone/CMF code tries to get portal_types tool using getToolByName and fails; similarly when trying to instantiate the AT class directly, the manage_afterAdd then tries to access reference_catalog, which fails.
Is there any way to make this work?
A different approach can simply be to add event handlers for IObjectAddedEvent, and add there your subcontents using common APIs.
After some trials and errors, it turns out this is possible:
from zope.container.interfaces import INameChooser
from zope.component.hooks import getSite
from plone.dexterity.factory import DexterityFactory
class CustomDexterityFactory(DexterityFactory):
def __call__(self, *args, **kw):
folder = DexterityFactory.__call__(self, *args, **kw)
# we are given no context to work with so need to resort to getSite
# hook or zope.globalrequest.getRequest and then wrap the folder
# in the context of the add view
site = getSite()
wrapped = folder.__of__(site["PUBLISHED"].context)
# invokeFactory fails if the container has no id
folder.id = "tmp_folder_id"
# standard AT content creation
wrapped.invokeFactory("Page", "tmp_obj_id")
page = wrapped["tmp_obj_id"]
new_id = INameChooser(service_obj).chooseName(title, page)
page.setId(new_id)
page.setTitle(title)
# empty the id, otherwise it will keep
folder.id = None
return folder
While the above works, at some point the created Page gets indexed (perhaps by invokeFactory), which means there will be a bogus entry in the catalog. Code to remove the entry could be added to the factory.
Overall, it would be easier to just create an event handler, as suggested by #keul in his answer.
CODE: http://pastebin.com/W4uXmazw
I would like to memorize how to get values from any wx widget with event handling after clicking a wx.Button.
In my program i have two fields, the new filename and the contents.
What are the steps i have to take in order to get the values from each field?
From there, i can use pythons f.open and f.write methods to complete my application.
Thanks!
If you want to get value of a widget, then you need to make that widget accessible throughout the entire class. To do that, you need to make the variable for the widget into an instance variable. So instead of adding the text control directly to the sizer, you'll want to do something like this:
self.newfilename = wx.TextCtrl(panel,-1), 0, wx.TOP, 5)
self.contents = wx.TextCtrl(panel,-1,size=(390,150),style = wx.TE_MULTILINE|wx.TE_PROCESS_TAB)
Then in your button's event handler, you can just do something like this:
valueOne = self.newfilename.GetValue()
contents = self.contents.GetValue()
The other way to do it would be to use your panel. If you use "self.panel", then you could grab all its children via its GetChildren method and then iterate over the list and use Python's "isinstance" builtin to check what kind of widget you're accessing. If you have set the widget's name, you can check that too.
If you have a controller method like so:
#expose("json")
def artists(self, action="view",artist_id=None):
artists=session.query(model.Artist).all()
return dict(artists=artists)
How can you call that method from within your controller class, and get the python dict back - rather than the json-encoded string of the dict (which requires you to decode it from json back into a python dict). Is it really necessary to write one function to get the data out of your model, and another to pack that data for use by the templates (KID, JSON)? Why is it that when you call this method from in the same class, e.g.:
artists = self.artists()
You get a json string, when that's only appropriate if the method is called as part of a HTML request.
What have I missed?
I normally approach this by having a 'worker' method, which queries the database, transforms results, etc., and a separate exposing method, with all the required decorators. E.g.:
# The _artists method can be used from any other method
def _artists(self, action, artist_id):
artists = session.query(model.Artist).all()
return dict(artists=artists)
#expose("json")
##identity.require(identity.non_anonymous())
# error handlers, etc.
def artists(self, action="view", artist_id=None):
return self._artists(action=action, artist_id=artist_id)