I am using wxPython to create a taskbar menu. The menu contains some menu items (obviously).
Now I would like to update/change some of these items when a particular item is clicked, while still displaying the menu.
How can I prevent the taskbar menu from disappearing after clicking an item?
The only method I've found that could be useful is wxMenu.UpdateUI(), but that doesn't prevent the menu from disappearing.
Although I never got around to trying it myself, I remember attempting a similar effect with a popup menu & textctrl. You might want to consider trying wx.lib.agw.flatmenu.FlatMenuBar, it provides an event handler OnMenuDismissed(self, event), as well as a few others, which by name appear to be what you need. You would need to create your own OnMenuDismissed() and override the event.
Related
I have a sort of to-do list app and I would like to make it so that a user can click and drag down a list of checkboxes, toggling their state to be that of the first box clicked. Basically the same as this HTML question here: "Check" Multiple Checkboxes With Click & Drag?.
How would I go about doing this in Qt? I tried subclassing the mouseMoveEvent of a checkbox to get the current mouse state, but that did not work out for a number of reasons (not the least of which is that per the documenation mouseMoveEvents always return Qt.NoButton). I also ran into focus issues, whereby when the first box is clicked it grabs focus until the mouse is let go of, thus blocking signals to the other boxes.
What I want is a mean to remove an item from the combobox without having to add a separate remove button somewhere else. So I want a remove button to appear at the right side on a combobox dropdown item when I hover over my mouse pointer on it. And, it is also OK if all the items have remove button at the right side and do not need hovering.
The images bellow will illustrate what I am saying [...please ignore my mspaint skils]
[combobox with remove button for hovering item]
https://i.imgur.com/kIMtF3G.jpg
[combobox with remove button for each item]
https://i.imgur.com/iyG23vG.jpg
[NOTE: Sorry, I cannot post images directly because it needs at least 10 reputation to post images.]
[I am new to python and wxpython. So please ignore my ignorance if any. And for the same reason any simple code sample will be greatly helpful.]
Regards.
The wx.ComboBox does not have this feature. The wxPython GUI toolkit uses the target platform's native widgets. If those widgets don't support doing it, then neither does wxPython.
However, wxPython does have custom widgets or you could create your own widget to do this sort of thing.
I also think you could use a context-menu for this task. You would need to right-click to make it work. Another method would be to bind to a mouse event and try to figure out where in the widget you are, but I think that method would be error prone.
I'm writing a document based application in wxPython, by which I mean that the user can have open multiple documents at once in multiple windows or tabs. There are multiple kinds of documents, and the documents can all be in different "states", meaning that there should be different menu options available in the main menu.
I know how to disable and enable menu items using the wx.EVT_UPDATE_UI event, but I can't figure out how to pull off a main menu that changes structure and content drastically based on which document that currently has focus. One of my main issues is that the main menu is created in the top level window, and it has to invoke methods in grand children and great grand children that haven't even been created yet.
Contrived example; when a document of type "JPEG" is open, the main menu should look like:
File Edit Compression Help
And when the user switches focus (CTRL+Tab) to a document of type "PDF", the main menu should change to:
File Edit PDF Publish Help
And the "Edit" menu should contain some different options from when the "JPEG" document was in focus.
Current I'm just creating the menu in a function called create_main_menu in the top level window, and the document panels have no control over it. What would be necessary to pull off the kind of main menu scheme I describe above, specifically in wxPython?
I've figured out a pretty clean way to do this. First of all I create my "base" main menu bar, which contains the File and Help menu items. Then I defined a class EditorPanel than is a subclass of wx.Panel and defined the methods bind_main_menu_bar and release_main_menu_bar. The first of those methods receives the main menu bar when the panel is focused, and adds some items to it. Here is one of my implementations:
def bind_main_menu_bar(self, main_menu_bar):
main_frame = wx.GetApp().GetTopWindow()
self.main_menu_bar = main_menu_bar
# Create the edit menu.
self.edit_menu = edit_menu = shared.create_menu([
(const.ID_UNDO, self.LABEL_UNDO_EMPTY),
(const.ID_REDO, self.LABEL_REDO_EMPTY)
])
# Create the tools menu.
self.tools_menu = tools_menu = shared.create_menu([
(const.ID_SELECT_ADDRESS_COLUMNS, 'Select address columns...'),
(),
(const.ID_VALIDATE_ADDRESSES, 'Validate selected addresses'),
(const.ID_VALIDATE_ALL_ADDRESSES, 'Validate all addresses')
])
# Bind some menu event handlers to the main frame.
main_frame.Bind(wx.EVT_MENU, self.on_menu)
main_frame.Bind(wx.EVT_UPDATE_UI, self.on_menu_update)
# Insert the new menus into the main menu bar.
main_menu_bar.Insert(1, edit_menu, 'Edit')
main_menu_bar.Insert(2, tools_menu, 'Tools')
Now, when that editor panel is opened, the main menu receives an Edit menu and a Tools menu that is bound to event handlers in the EditorPanel, which is incredibly handy. When the editor loses focus, the release_main_menu_bar method is called, which should restore the main menu bar to it's original state. This is counterpart of the code above:
def release_main_menu_bar(self):
main_frame = wx.GetApp().GetTopWindow()
# Unbind the menu event handlers from the main frame.
main_frame.Unbind(wx.EVT_MENU, handler=self.on_menu)
main_frame.Unbind(wx.EVT_UPDATE_UI, handler=self.on_menu_update)
# Remove the edit and tools menu from the main menu bar.
self.main_menu_bar.Remove(1)
self.main_menu_bar.Remove(1)
# Reset the fields used for the menu.
self.edit_menu = None
self.tools_menu = None
self.main_menu_bar = None
So every editor that wants to edit the main menu just has to subclass those two methods and they have full control. The main frame will monitor when the user switches between editors and call the methods accordingly. The biggest problem was to figure out when the editor panel receives and loses focus, which is the topic of another question of mine: How do I monitor when wx.Panel receives and loses focus?
Probably the only way to do it with the standard wx.Menu is to destroy and recreate the entire menubar. You might be able to Hide it though. Either way, I think it would be easiest to just put together a set of methods that creates each menubar on demand. Then you can destroy one and create the other.
You might also take a look at FlatMenu since it is pure Python and easier to hack.
I am using a SearchCtrl with a dropdown menu and I'm having some trouble with the events. When I click the little arrow next to the search button, the EVT_SEARCHCTRL_SEARCH_BTN is triggered, which is not what I want. I only want the EVT_MENU_RANGE to be triggered after I clicked an item, and not also the EVT_SEARCHCTRL_SEARCH_BTN before i click it.
self.search_ctrl = wx.SearchCtrl(self.panel_1, -1,
style=wx.TE_PROCESS_ENTER)
self.search_menu = wx.Menu()
self.search_items = {"text1":"value1", "text2":"value2"}
for txt in self.search_items:
self.search_menu.Append(-1, txt)
self.search_ctrl.SetMenu(self.search_menu)
self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.search, self.search_ctrl)
self.Bind(wx.EVT_MENU_RANGE, self.onSearchMenu)
Although I should probably add id's to the menu bind, this isn't causing the problem. The code works as expected when I comment out the search button bind.
UPDATE
Apparently this isn't a problem, but a 'feature' of the searchctrl. I tried the wxpython demo and the menu also showed up if I just clicked the search button, and not the arrow. It is apparently one button, instead of the two i thought it was.
Is there a way to accomplish my original request? Do i have to manually modify a textctrl, or is there an other solution?
All the examples I've seen suggest you need to specify a range of IDs when you call your menu bind.
Maybe by default it binds to something unexpected... ?
Edit - In light of your update, it seems likely that you're going to need to make a custom control to me..
Wondering if there's a menu event I can bind to that's related to the currently selected menu item? By menu item I mean the items that show up in a popup menu like New, Open, Save, etc.
Use case: I would like to update a statusbar area of our application with a description of the currently selected menu item.
Any ideas appreciated.
Thank you,
Malcolm
You need to bind to the <<MenuSelect>> event.
There's an <Enter> event that is triggered when the mouse pointer enters a widget's space. Depending on how you're building your menu, you may be able to use it.
See http://www.pythonware.com/library/tkinter/introduction/events-and-bindings.htm for more