Python GUI Events - python

I'm sure this question has been asked many times before, so I apologize in advance. I simply cannot find the answer via google or searching stack overflow.
I'm working in python with the wx library. I simply need a wx.EVT_CHAR to be thrown anytime a user presses a key, no matter the focus. How can this be accomplished? Is there a way to bind all widgets? Or a way to always throw an event when application receives a key press?
I tried binding the application itself, the main frame, and the main panel. None of these have accomplished the job of always throwing a wx.EVT_CHAR when a key is pressed.

I was able to solve my problem by writing a recursive method that sets every widget to receive characters and binds every widget to my callback function. It's pretty simple, but took me a bit of googling to realize that not every widget can inherently receive text events (such as a button). Hopefully this will save someone some time in the future. It should be noted that only widgets that are children or subchildren of the parent window passed will be bound to the callback method.
def __RecursiveBinding(self, parent):
try:
parent.Bind(wx.EVT_CHAR, self.CharInputCallback)
parent.SetWindowStyleFlag(wx.WANTS_CHARS)
parent.Refresh()
children = parent.GetChildren()
if(children):
for child in children:
self.__RecursiveBinding(child)

Related

Make widget treat numpad arrows the same way as the other arrow keys

I first noticed this when I was using IDLE for a task, but it shows up in my own tkinter programs as well. There are two sets of arrow keys on many keyboards, the regular arrow keys that are often next to the spacebar row, and the arrow keys on the key pad, which double as number entry keys when numlock is turned on. In tkinter the two sets produce different event names when pressed.
My issue is that when using various built in tkinter widgets, such as Text, and Entry, the default tkinter behaviour appears to be to ignore the key pad events. I would like to have my program treat both sets the same.
I am hoping that there is a relatively simple method of accomplishing this, such as setting a variable in the module after I import it, or binding the KP_* events to functions which then emit corresponding regular arrow key events back to my widgets. However the only thing I have found that even acknowledges the existence of this quirk is this other, unanswered, Stack Overflow question.
So after digging around some more I created this function to forward events to another event name. It probably has a number of potential improvements, but this is the general idea.
The function is called on the widget that you want to remap events for, calling it on the root widget will remap events for at least all other widgets that haven't been bound to anything else.
One can change which events are translated to which other events using the kmap variable. If you do, be sure you don't have any loops in your forwarding, this function does zero sanity checking.
I have only copied the modifier key state from the original event here, since that was enough for it to do what I wanted, but in some circumstances you could need to copy more information.
I found the key event information from the link in the Python docs for tkinter. I got the event_generate() and event property information from the same source.
Be aware that this solution, while it worked for my simple issue, may well require much more care when applied to a more complicated situation.
def fix_keypad(widget):
kmap = {
'<KP_Left>': '<Left>',
'<KP_Right>': '<Right>',
'<KP_Up>': '<Up>',
'<KP_Down>': '<Down>',
'<KP_Home>': '<Home>',
'<KP_End>': '<End>',
'<KP_Next>': '<Next>',
'<KP_Prior>': '<Prior>',
'<KP_Enter>': '<Return>',
}
for i in kmap:
def mfunc(event, key=i):
widget.event_generate(kmap[key], **{'state': event.state})
widget.bind(i, mfunc)

Are there any ways to bind the enter key to a Tkinter.Toplevel() window in Python?

I have a tk window opening another. This secondary window is used as my input for a program. I would like to read the results each time the cartage return key is pressed. I read somewhere that the method I am trying to use (below) only works for root .Tk() windows.
input_window.bind('<Return>',lambda: function_to_save_data (args) )
Is there a way to get around this, or an alternative way to do such a thing?
(I have tried this, and it fails to work, and does not bug out, thus the question above)
Bind works for any window, there are no special cases.
The problem you are experiencing is likely due to the fact that top level windows may not get keyboard focus. When you press a key, it is the window with focus that processes the event.

How to handle button states efficiently in Tkinter

I've done a few searches but I couldn't find anything about this topic. Perhaps because it is common programmer knowledge (I'm not a programmer, I've learned from necessity), or because I'm going about it the wrong way.
I would like ideas/suggestions on how to manage button states for a GUI. For example, if I have a program which allows the user to import and process data, then certain functions should be inaccessible until the data has been imported successfully, or if they want to graph certain data, they need to select which data to graph before hitting the 'graph' or 'export' button. Even in the simple programs I've built these relationships seems to get complicated quickly. It seems simple to say "User shouldn't be able to hit button 'A' until 'B' and 'C' have been completed, then 'A' should be disabled if button 'D' or the 'Cancel' button. But that's a lot to track for one button. Thus far, I've tried two things:
Changing/Checking button states in the callback functions for the button. So in the above example, I would have code in buttons B's and C's callback to check if A should be enabled. And in buttons D's and Cancel's callbacks I would have code to disable button A. This gets complicated quickly and is difficult to maintain as code changes.
Setting boolean variables in every buttons callback (or just checking the states later using cget()) and checking the variables in a polling function to determine which buttons should be enabled or disabled.
I'm just not sure about this. I would like to make code as short and easy to understand as possible (and easy to edit later), but I don't like the idea of polling all the button states every few hundred milliseconds just for button 'management'. You can extend the same idea to check boxes, menu items, etc... but I'd like to here what others have done and why they do it the way they do.
You are only changing button states based on events, right? There is no reason to 'poll' to see if a button state has changed. What you can do is build a function which does all of the calling for you, then call it with something like disable_buttons([okButton, graphButton, printButton]). When an event takes place that modifies the appropriate user interface options (such as importing data), have another function that turns them on: enable_buttons([graphButton]). You could do this with each object's methods, of course, but making a wrapper allows you to be consistent throughout your application.

PyQT events between multiple objects

I am creating a GUI program in Python/PyQT and would like to know how I can connect an event which happens in a child object to the parent?
For example, if someone clicks a 'Submit' button, how would i trigger something to happen in the parent object (lets say update a QLabel on the parent)
Any help would be greatly appreciated
L
It is done like in C++ Qt by connecting signals to slots, you will find all the information on this page (and here for the old way).
You must connect these methods every time you set new parent (and remove old connections!!)
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qobject.html#connect
(If widget parent change and You still wont that new parent to recive signals)
But if your layout is static just give good names for your widgets. Then connect each signal to callable (any python function) and that function will change QLable.
In this case relation parent children change nothing since you refer to widgets by names not relations.

Change the focus from one Text widget to another

I'm new to Python and I'm trying to create a simple GUI using Tkinter.
So often in many user interfaces, hitting the tab button will change the focus from one Text widget to another. Whenever I'm in a Text widget, tab only indents the text cursor.
Does anyone know if this is configurable?
This is very easy to do with Tkinter.
There are a couple of things that have to happen to make this work. First, you need to make sure that the standard behavior doesn't happen. That is, you don't want tab to both insert a tab and move focus to the next widget. By default events are processed by a specific widget prior to where the standard behavior occurs (typically in class bindings). Tk has a simple built-in mechanism to stop events from further processing.
Second, you need to make sure you send focus to the appropriate widget. There is built-in support for determining what the next widget is.
For example:
def focus_next_window(event):
event.widget.tk_focusNext().focus()
return("break")
text_widget=Text(...)
text_widget.bind("<Tab>", focus_next_window)
Important points about this code:
The method tk_focusNext() returns the next widget in the keyboard traversal hierarchy.
the method focus() sets the focus to that widget
returning "break" is critical in that it prevents the class binding from firing. It is this class binding that inserts the tab character, which you don't want.
If you want this behavior for all text widgets in an application you can use the bind_class() method instead of bind() to make this binding affect all text widgets.
You can also have the binding send focus to a very specific widget but I recommend sticking with the default traversal order, then make sure the traversal order is correct.
It is really simple in PyQt4 simply use this one single line below and you will be able to change focus by pressing tab button:
self.textEdit.setTabChangesFocus(True)
The focus traversal is somewhat customizable, usually letting the X windows manager handle it (with focus follows mouse, or click). According to the manual it should be possible to bind an event to the key press event, for tab presses, and triggering a focusNext event in those cases.

Categories