I'm quite new to Python and have been unsuccessful in finding a way around this problem. I have a GUI using TKinter that displays an image using Label. I would like the user to be able to click on two places in the image and use those two pixel locations elsewhere.
Below is the basic code I'm using so far, but I'm unable to return the pixel locations. I believe bind is not what I want to use, is there another option?
px = []
py = []
def onmouse(event):
px.append(event.x)
py.append(event.y)
return px,py
self.ImgPanel.bind('<button-1>',onmouse)
If I try to use:
px,py = self.ImgPanel.bind('<button-1>',onmouse)
I get an error "Too many values to unpack"
bind is what you want, if you want to capture the x,y coordinate of the click. However, functions called from bindings don't "return". Technically they do, but they return a value to the internals of Tkinter.
What you need to do is set an instance or global variable within the bound function. In the code you included in your question, if you add global px,py, you can then use those values in other code.
Related
I am using a Jupyter notebook for my project with a Xbox controller to control a robot in real time.
import ipywidgets.widgets as widgets is used
it works directly assigning them to sliders or motors using traitlets, but I do not how to do calculations with them beforehand.
If I assign these values to variables, it gets the current value at the time of running the cell.
Here is working code that assigns directly to motor:
left_link = traitlets.dlink((controller.axes[1], 'value'), (robot.left_motor, 'value'), transform=lambda x: -x)
However, I need to calculate the angle I want to go, therefore calculating arctan2 of two axes of joystick values (the transform: lambda does not suffice I think?).
I do not understand how I should take on this problem, as I have never worked with always updating variables, like the Xbox controller variables. Please tell me if you need any more information.
The thing I was looking for was Observe()
like here:
import ipywidgets.widgets as widgets
int_range = widgets.IntSlider()
display(int_range)
def on_value_change(change):
print(change)
print(change['new'])
int_range.observe(on_value_change, names='value')
This allows reassigning the variable value everytime the controller changes it's value.
Trying to make a simple drawing program based on x an y coordinates an i'm using a function to draw and modify the coordinates in one call without actually giving valuea to the function itself using global variables for what needs modification by the function but it still seees as if i've given it actual direct input.
In a previous version i got away by using a class to memorize the ghanging coordinates and functions of the respective class to do the drawing, but in this case the input method is slightly different since i'm using the scale widget isntead of the buttons and as i mentioned before i did try using global variables in both programs actually and it doesn't work in either of them.
from tkinter import *
win=Tk()
win.title("Etch a Schetch")
win.configure(background="grey")
win.configure(bd=5)
global xa
xa=0
global ya
ya=0
def MOVE():
tabla.create_line(xa,ya,sx.get(),sy.get())
xa=sx.get()
ya=sy.get()
tabla=Canvas(win,width=300,height=300)
sx=Scale(win,from_=0,to=300,length=300,orient="horizontal",command=MOVE)
sy=Scale(win,from_=0,to=300,length=300,command=MOVE)
ex=Button(win,text="Exit",command=exit)
tabla.grid(row=1,column=1)
sx.grid(row=2,column=1)
sy.grid(row=1,column=2)
ex.grid(row=2,column=2)
win.mainloop()
If it would work it would be kinda like an etch a sketch.
I actually just realized what the problem was, to quote mkiever who commented first but i didn't understand untill i did some individuall testing on the interaction between "Scale" and the command that is calling. To put it short and easier to understand the function that is beeing called by "Scale" as its command automaticly takes the value of the scale as an input to the function, as a rezult i only need one declared variable in the paranthesis when i define the function but no paranthesis or input variable is required to give an input to it from the scale.
EXAMPLE:
from tkinter import *
import time
win=Tk()
def P(a):
print(a)
sx=Scale(win,from_=0,to=300,length=300,orient="horizontal",command=P)
sx.pack()
win.mainloop()
Some alteration to the code is still required but it'll be much easier without that pesky error showing up.
Thank you everyone for your advice.
I try to get window origin in a mate panel applet.
To be more precise I want to know the position of my applet (x and y) on the screen because I have a button which show/hide a Gtk.window but I need to move that window next to my button (above, below, right, left depending on where the mate panel is)
The only way that I found is to call get_origin but there is a problem. It should return a tuple x,y but instead like the c function it require two integers and since python use pass by value of course it doesn't work.
This code is valid but useless:
window = self.get_window()
x = 0
y = 0
window.get_origin(x, y)
All other "way to use" get_origin (that you can found in any doc) does not work because it require 3 args (I don't know why)
So I'm looking for a way to get the position of my applet (even if it's not accurate) or to move my window next to my button.
I found an alternative get_root_coords
window = self.get_window()
x,y = window.get_root_coords(0, 0)
It works even with multiple screens and I'm able to move my Gtk.Window next to my button with it.
The program I created allows for any letter on the keyboard the user types to be written on the turtle graphics canvas. In my program, I have also created a Python menu to which a Point object (for each letter function) is written to every time a user executes a function/draws a letter. However, because of the nature of my program, the user can also attach two of the same functions to the menu. If two of the same things get attached to the menu, for example two functions, I need a way to differentiate between them somehow. To do this, I have created a counter in another function and called that counter function in the function where the menu is written to, like so:
Counter function:
def increase():
if not hasattr(increase, "counter"):
increase.counter = 0
increase.counter += 1
Code block when menu is written to:
global loki
kli.config(state = NORMAL)
loki = ("{}".format(po.getfunction()))
increase() #<-- Counter function
undo1.add_command(label = str(increase.counter) + Point.__str__(po), command = lambda: selectundo(undo1.index(po)))
Point.__str__ is this method in the Point class:
def __str__(self):
return "({})".format(self.function)
However, I keep getting this error whenever I select something from the menu:
undo1.add_command(label = str(increase.counter) + Point.__str__(po), command = lambda: selectundo(undo1.index(po)))
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/tkinter/__init__.py", line 2782, in index
i = self.tk.call(self._w, 'index', index)
tkinter.TclError: bad menu entry index "(<function draw_O at 0x105834d90>)"
I am thinking it has something to do with the following function, which undoes the function that is selected from the menu, but I am not sure:
def selectundo(x):
# This function undoes the function selected from the menu
for ty in range(x, len(function)):
undoHandler()
update()
listen()
Although, before I concatenated str(increase.counter) to Point.__str__(po), it worked perfectly.
So, what am I doing wrong here? Any help at all is much appreciated! :)
EDIT: Just to clear up what I am trying to do and why, I am trying to differentiate between two (or more) of the same functions if they are written to the menu and I am doing this because of the selectundo function (shown above) since, for example, if the user draws two (or more) of the same letter, I need to be able to differentiate between them, because right now, when I can't, the selectundo function undoes ALL instances of that letter, NOT just the first instance of what is pressed on the menu, which is what I actually want the program to do. If what I am trying to do to accomplish the task is not possible or if there is a better way to accomplish the task, please tell be about any/the other way that I can use to accomplish the task. I hope this helps alleviate any confusion! :)
I don't know what the right words are to ask my question, so please excuse the extra detail below. I am as much asking for the right words/concepts as for an answer to the specific question.
I'm trying to put a simple console in front of a script of mine using curses in Python. I want the console to look relatively familiar and have key shortcuts for 3 commands (Load, Exit, Continue). To highlight which key is the hotkey for an action, I wanted that letter to be in a different colour. (e.g. Exit with hotkey being the x). I figure this must be made up of 3 "addstr" commands- write the first letter in normal ("E"), then the x with a colour attribute, then "it" in normal colour again.
I thought that because I do this 3 times, and maybe more in future screens, I should make a function to do it for me to see if that works. What I can't figure out though, is how to edit the screen without hardcoding the function to the variable name. I want to be able to call the function in a number of different windows. I thought at first I could just pass the screen's variable into my function but that doesn't seem right.
Here is my pseudo code I started working on:
def keyString(menuString,fastChar,highlight,startX,startY,cScreen):
#menuString is the word that has a letter to bring to attention
#fastChar is the character that will be in a different colour
#highlight is binary value to determine which colour pair to use
#definition expects 'h' and 'n' to be colour pairs
#startX and startY are the beginning cursor positions
#cScreen would be global screen variable
fCidx = menuString.find(fastChar) #index of the character to highlight
fXadj = startX + fCidx #set the x position for character to highlight
sHx = fXadj + 1 #set the x position for the remainder of the string
fH = menuString[0:fCidx] #Slice the first half of the string
sH = menuString[(fCidx+1):] #slice the remainder of the string
if highlight:
txtColor = h
else:
txtColor = n
cScreen.addstr(startY,startX,fH,txtColor)
cScreen.addstr(startY,fXadj,fastChar)
cScreen.addstr(startY,sHx,sH,txtColor)
return cScreen
Please ignore the awful variable names..I was getting tired of typing and started shorthanding. I realise that I didn't need to worry about explicitly stating x,y coords because the cursor position is remembered. So a lot of that can be cut out. I'm not asking for someone to fix my function. I just don't have a concept of how to have a function that will write out a word using different colours for different characters. I could probably stick a "global screen" in the function and only use it for editing "screen", but then (for example) I wouldn't be able to use the function for "screen2".
If it helps anyone searching in the future, I found that I can use Windows (curses.newwin) and those can be fed into, and returned from functions.
So for example, if the above code was in a file called "curse_tools.py":
import curses
import curse_tools
def Main(screen):
curses.init_pair(1,curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.init_pair(2,curses.COLOR_BLACK, curses.COLOR_GREEN)
n = curses.color_pair(1)
h = curses.color_pair(2)
curse_tools.n = n
curse_tools.h = h
try:
screen.border(0)
box1 = curses.newwin(20, 20, 5, 5)
box1.box()
box1=curse_tools.keyString("Exit","x",False,1,1,box1)
screen.refresh()
box1.refresh()
screen.getch()
finally:
curses.endwin()
curses.wrapper(Main)
This code would work. I'm going to re-write my original code because I learned a lot along the way but maybe a future beginner will somehow come across this question so I thought I'd post the 'solution'. Although I still don't know the right words.
Most of the code in this post came from Why won't my curses box draw? (in case it looks familiar)