Tkinter link button press and 'return' key - function

I've looked at various tutorials for how to link a button press and a keyboard press of 'return.' I can do them both, but only one at a time. The keyboard style is rootWindow.bind('<Return>' functionName and that linking an on-screen button is command=functionName. I just can't get them to work when used at the same time.
This is the very basic skeleton of what I'm working with
def printthis(event):
print("worked")
root = Tk()
root.bind('<Return>', printthis)
button1 = Button(root, text='Enter', command=printthis)
button1.pack()
root.mainloop()
I get this error when I run the current code, I'm just not sure what 'event' I should pass into the command=printthis section
TypeError: printthis() missing 1 required positional argument: 'event'
As a side note I am using Python 3.x

When you bind a function an event object will be passed into it whenever the binding action occurs. If you want your function to work for both on event and button press then you have two options.
First is if your function may require the event object. Then allow your function to take an optional argument for event.
def printthis(event = None):
if event is None:
# handle this case
# otherwise handle event object normally.
The second is if you don't care about the event object then the 1st is still fine (you just never use the event parameter), or you can use lambda when binding.
def printthis():
print("worked")
root.bind('<Return>', lambda e: printthis())
lambda takes e which is the event object and then calls your function without passing in e discarding it.

Related

How can I run a command from inside another stack command?

I have a callback handler in a stack that looks for telemetry data. When it gets some, I parse it and then want to save it. However, to save it requires other functions and commands in the same stack.
I could put it on the card, but where? I use the openCard end openCard and that's about it in the card.
The stack has all the functions and commands I need. There's no button to press to run the save code - I need it to run automatically.
How can I put the chunk of code on the card and then have the stack 'call it'?
I know how to call commands from the card, but not from the stack.
Generically, you simply call either a command handler or a function handler in-line:
on mouseUp -- a "main" handler
doSomething -- a command handler
dosomethingElse -- another command handler
put doYetAnotherThing(paramList) into field 1 -- a function handler
end mouseUp
on doSomething
well, do something
end doSomething
on doSomethingElse
you get the picture
...
Try making a simple main handler that does silly trivial things for each of the three "subRoutine" calls above. You will be an expert in a matter of hours.
The placement of the three has to be managed. Generally, they reside in the script where the main handler lives. But they can be anywhere in LC.
If you want to call a handler in a card (or any other control) from another script, you can use one of the following commands:
dispatch "command" to control with param1, param2, …
send "command" to control [in time]
put value(command, control) into tResult
Dispatch happily continues even if the command isn't handled by the control. You can check that of course.
Send has the advantage that you can schedule the sending forwards in time, but is a bit harder if you want to also send some parameters.
Value is good candidate if you call a function and want the result back.
Note that ""openCard" and "preOpenCard" messages can be trapped and worked in the stack script, as long as there are no such handlers in the card script. And even if there are, you can "pass" each message after the card script handler is done with it";
Try creating a command on the stack that is called every X times while the user is on that card. This command must be called to itself and to the other manipulators that you use to obtain the data. This same manipulator will be in charge of saving the data.
# Code on the card
local sTelemetryData
on openCard
// If the card belongs to the pile where all the telemetry is or if this pile is a library.
getTelemetryData
// otherwise you will have to call the getTelemetryData command. You can use send, disparsh, or call.
// call "getTelemetryData" to stack "stack name"
end openCard
# Code on the stack
constant kTime = 100
local sPendingMessageID
on getTelemetryData
if the short name of this card is not "TelemetryData"
then exit getTelemetryData
if sPendingMessageID is a number
then cancel sPendingMessageID
// call the commands and functions that look up the telemetry data.
// The data must be stored in the sTelemetryData variable to save it and at once use this variable as a flag
if sTelemetryData is not empty then
// The data is sent to be saved
end if
put empty into sTelemetryData
send "getTelemetryData" to me in kTime milliseconds
put the result into sPendingMessageID
end getTelemetryData

Add variable to the instance of the class

I'm trying to add variable to the instance of the class.
In console, I get this error:
TypeError: __init__() missing 1 required positional argument: 'view'
And here is the code itself:
import sublime_plugin
class TestMe(sublime_plugin.EventListener):
def __init__(self, view):
self.view = view
self.need_update = False
def setme():
need_update = True
def on_activated(self, view):
setme()
if need_update == True:
print("it works")
I spend all day trying to figure out different ways to resolve it. What I'm doing wrong?
It looks like the core of your issue is that you're subclassing EventListener and not ViewEventListener.
The reason you're seeing this error is that the __init__ method of the EventListener class takes no arguments (with the exception of self, which is always present in class methods). When Sublime creates the instance, it doesn't pass in a view, and since your __init__ requires one, you get an error that you're missing a positional parameter.
This is because the events in EventListener all pass in the view that they apply to (if any), so the class doesn't associate with one specific view and thus one is not needed when the listener is created.
In contrast, ViewEventListener offers only a subset of the events that EventListener does, but its instances apply to a specific view, so its constructor is provided with the view that it applies to. In this case the events themselves don't have a view argument because the listener already knows what view it is associated with.
A modified version of your code that takes all of this into account would look like this:
import sublime_plugin
class TestMe(sublime_plugin.ViewEventListener):
def __init__(self, view):
super().__init__(view)
self.need_update = False
def setme(self):
self.need_update = True
def on_activated(self):
self.setme()
if self.need_update == True:
print("it works")
Here the super class is ViewEventListener, for which Sublime will pass a view when it is created. This also invokes the super class version of the __init__ method instead of setting self.view to the view passed in, which allows it to do whatever other setup the default class needs to do (in this case none, but better safe than sorry).
Additionally the methods are adjusted a little bit, since in this case every view will have a unique instance of this class created for it:
setme takes a self argument so that it knows what instance it is being called for
on_activated does not take a view argument because it has access to self.view if it needs it
Calls to setme need to be prefixed with self. so that python knows what we're trying to do (this also implicitly passes in the self argument)
All accesses for need_update are prefixed with self. so that each method accesses the version of the variable that is unique to its own instance.

Tkinter button and entry

I have a couple of defined functions that I want to create buttons for in my GUI. A couple of these functions require one or two arguments(numbers) and that is what's causing problems for me. I have thought about a combination between a button and an entry where when I click the specific button(for one of my functions), an entry will pop up where I type in a number. Then when I press enter I want this number to be used as the argument for the function I have binded to my button and then the function should be executed.
1 function I want to bind to a button:
def move(power, tacho_units):
MOTOR_CONTROL.cmd(5, power, tacho_units, speedreg=0, smoothstart=1, brake=0)
is_ready(5)
We are working with Lego Mindstorms, so Im pretty sure that for example the function above could be a bit confusing for some people.
from Tkinter import *
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.button = Button(frame, text="Move", command=!_______!)
self.button.pack(side=LEFT)
root = Tk()
app = App(root)
root.mainloop()
root.destroy()
Does someone have any suggestions/solutions for me? I would appreciate if someone could help me. Do I create a function(that will open a new window with an entry) that I call when I click the Move button? The numbers(power and tacho_units in this function) that I type into the entry is what I want to be used for the function Move when I press enter.
Typically, the way to pass arguments to a function associated with a widget is to use lambda or functools.partial (note: these aren't the only ways). Both of these are somewhat advanced topics, but if you just follow an example, it's fairly safe to use them without fully understanding them.
Here's an example using lambda:
b = tk.Button(..., command=lambda power=1, tacho_units="x": move(power, tacho_units)
While not technically correct, just think of a lambda as a "def" but without a name. It takes arguments and can call functions.
Here is the same thing, using functools.partial:
b = tk.Button(..., command=functools.partial(move, power=1, tacho_units="x"))
Note: you'll have to add an import statement for functools.
functools.partial in essence copies the function (in this case, move) and provides default values for the arguments. Thus, when you call it with no arguments (as tkinter does by default), the parameters will have these default values.
HOWEVER...
Often it's easier to write a function to call your function. The purpose of this extra function is to gather the inputs -- presumably from other widgets -- and then call the final function. For example:
def do_move():
power = power_input.get()
tacho_units = tacho_input.get()
move(power, tacho_units)
b = tk.Button(..., command=do_move)
Whether you use this third method depends on where the argument values come from. If you know the values at the time you create the widget, using lambda or functools.partial works because you can embed the arguments right there. If you're going to be getting the parameters from other widgets, the third form is preferable.
Use lambda function to assign function with arguments
some_power = ... # set value
some_tacho_units = ... # set value
self.button = Button(frame, text="Move", command=lambda a=some_power,b=some_tacho_units:move(a, b) )
or
self.button = Button(frame, text="Move", command=lambda:move(5, 10))

tkinter command to call function from another Python script

I am having a few issues, calling Python functions defined in another script using tkinter. I would prefer to have a separate script for my functions that the GUI uses when needed. At the moment I am doing it like this.
ttk.Button(mainframe, text="1", command=one).grid(column=1, row=1, sticky=NW)
def one():
code_entry.insert(END,"1")
The above calls the command one on a button click, which will print the character one in a entry field with the GUI. I thought I could create a separate script to hold my functions and call them like this:
ttk.Button(mainframe, text="1", command=functions.one()).grid(column=1, row=1, sticky=NW)
And then simply add an import statement at the top of my GUI, like below:
import functions
This doesn't work and looking for some advice on how to approach this.
You didn't specify any error messages, but it's most likely that you're doing fuctions.one() - actually calling the one() function of that module before the Button is created. It's simply fixed by removing the () part - when you specify a function without (), you are passing a reference of the function object.
Also keep in mind the scope of the code_entry variable - if you were using it as a module level global before (or function local, if one() was inside the same function as your ttk.Button call), it won't be available when you move it to a new namespace without code_entry.
To solve this you should pass code_entry as a parameter to the callback without calling one() at first. The usual approach for this is creating a lambda - essentially creating a function that works on the same scope of the original one(), having access to variables like code_entry, but also calling a function in a different module.
ttk.Button(mainframe, text="1", command=lambda: functions.one(code_entry))
Note that this is basically the same as:
def some_anonymous_function():
functions.one(code_entry)
ttk.Button(mainframe, text="1", command=some_anonymous_function)
Both examples create a function object and pass that object as reference - the functions.one() call of the lambda is actually inside the body of the lambda function, to be called later by tkinter.
Of course you also have to redefine one() to accept this new parameter:
def one(code_entry):
code_entry.insert(END,"1")

Isn't it redundant to declare the data type of an event object in a listener function's parameters?

When you click on the button something happens. However it seems redundant to me that in the declaration of myListenerFunction, the event object e of class MouseEvent, actually has to have its data type MouseEvent mentioned.
mybutton.addEventListener(MouseEvent.CLICK, myListenerFunction);
function myListenerFunction(e:MouseEvent):void
{
// function body
}
Couldn't I get away with this (the .swf works just the same so far as I know...)?
function myListenerFunction(e):void
Since the data type of e should always match the class of the event MouseEvent.CLICK (which is MouseEvent)?
EDIT:
So let's say we go from a mouse event to a keyboard event. By not declaring the data type of e, we can not be prone to errors in not changing the data type of e. e by default is going to be of type KeyboardEvent
mybutton.addEventListener(KeyboardEvent.KEY_DOWN, myListenerFunction);
function myListenerFunction(e):void
{
// function body
}
You can keep the event type to the base class Event if you like. But you will not have access to any of the MouseEvent / KeyboardEvent-specific members when you do it like that.
Using it without a type will make it Object, which is dynamic, meaning you can try to access any member by name (even if it does not exist) - this is slower (a lot) and fairly error prone. You will not get compile time checking for example.