A code needs to be continued...(Python with Tkinter) - python-2.7

This code is a simplified typing game, but I can't continue. The features required are:
Please don't use classes but just use FP;
When 5 random characters appear after you click the button, the 5 characters drop with a speed of 5 pixel/second, and meanwhile, you hit your keyboard to strike them. For every successful hit, your score wins by 10, and the character being hit will disappear. If not successful, they continue to drop untill the bottom edge of the canvas.
Below is part of my code, I've tried several times, but couldn't make it. How can I continue? Many thanks!
from Tkinter import *
from time import *
import string
import random
root = Tk ( )
root.title("Typing")
cvs = Canvas ( root , width=400 , height=350 , background="White" )
def Start():
s=random.sample("string.ascii_letters",5)
cvs.delete("rand")
return cvs.create_text(200,50,text=s,tags='rand',font=('Courier New',36,'normal'))
Button(root,text="Start",command=Start,width=30).pack()
cvs.pack ( )
root.mainloop ( )

You can animate an object by writing a function that draws one frame of animation, and then schedules itself to be called again in the future.
For example, to move a single object down the screen at five pixels a second you can use a function like this:
def animate(cvs, object_id):
# move down five pixels
cvs.move(object_id, 0, 5)
# call this function again in one second
# if the object is still on the screen
(x0,y0) = cvs.coords(object_id)
if y0 < cvs.winfo_height():
cvs.after(1000, animate, cvs, object_id)
You will have to modify that to handle more than one character, or call it once for each character. That decision is left up to you, this just illustrates the general technique.
Next, you can set up a binding to the <KeyPress> event, look at the character that was pressed, and if it matches something on the screen you can delete it. One simple way to keep track of what's on the screen is to map the characters to their canvas ids.
For example:
chars = {}
for char in random.sample(string.ascii_letters, 5):
obj_id = cvs.create_text(...)
chars[char] = obj_id
Now you'll have a dictionary that looks like:
{"a": 1, "X", 2, "y", 3, "f", 4, "B", 5}
You can now move or delete each canvas item by id.

Related

Mouse wheel moves cursor

I am fairly new to coding with python but I have to learn it as part of my PhD. I want to program a task in which on a straight line (top to bottom) there are 4 possible positions (here circles) that are target zones. Later a stimulus will be presented that corresponds to one of these targets. Afterwards the subject will have to move a mouse cursor on the line to select the correct stimulus. I want to do the input via the wheel of the computer mouse. So if I scroll up the cursor on the button moves along the line and can be placed on one of the zones and then a reward is given.
To my question: How do I implement the input of the mouse wheel, bind it to the cursor and restrict the the cursor to stay on the line (disable all other mouse movements) ?
Thank you in advance.
In PsychoPy Coder --> Demos --> input --> mouse, you will see a demo script on how to react to different kinds of mouse input. Also, see the documentation. In code, you would do something like this, where points is a list of coordinates on your line.
# Your points
points = [[0, 0], [1, 0.5], [2, 1], [3, 1.5]]
# Set up mouse
from psychopy import visual, event
win = visual.Window() # A mouse must be in a window
mouse = event.Mouse() # initialize mouse object
# Begin listening
event.clearEvents('mouse') # Do this in the beginning of every trial, to discard "old" mouse events.
index = 1 # start value
while not any(mouse.getPressed()): # for this example, keep running until any mouse button is pressed
#print mouse.getWheelRel()
scroll_change = int(mouse.getWheelRel()[1]) # returns (x,y) but y is what we understand as scroll.
if scroll_change != 0:
index += scroll_change # increment / decrement index
index = min(len(points)-1, max(index, 0)) # Round down/up to 0 or number of points
print points[index] # print it to show that it works. You would probably do something else here, once you have the coordinates.

Bokeh: dashboard not updating axis range based on widget value

I am trying to implement an interactive dashboard in Bokeh with a "play" function that loops through all value pairs for two indicators selected by widgets.
Screen cap of dashboard
While the loop works, the dashboard resets the axis values for each step of the loop. So what I need is to set axis values based on the widget.value selected. To this end, I have built a data frame "ranges" that has the name of the indicator as index and the min/max value for each indicator as columns.
The updates for controls work thusly (x_axis,etc. are the names of the widgets):
controls = [x_axis, y_axis, start_yr, end_yr, years]
for control in controls:
control.on_change('value', lambda attr, old, new: update())
The update function is supposed to update the ranges upon change in the controls like this:
def update():
p.x_range = Range1d(start = ranges.loc[x_axis.value,"Min"],
end = ranges.loc[x_axis.value,"Max"])
p.y_range = Range1d(start = ranges.loc[y_axis.value,"Min"],
end = ranges.loc[y_axis.value,"Max"])
What should happen: Whenever I change the value of the widget, the ranges should update, but other than that, they should remain constant
What does happen: The ranges are set based on the value of the widget initially set and don't change on update.
I've tried to find examples trying to achieve something similar but no luck.
This is a working example:
import numpy as np
from bokeh.plotting import figure
from bokeh.models import Range1d
from bokeh.io import curdoc
x = np.linspace(0, 100, 1000)
y = np.sin(x)
p = figure(x_range=(0, 100))
p.circle(x, y)
def cb():
# this works:
p.x_range.start += 1
p.x_range.end += 1
# this also works:
#p.x_range = Range1d(p.x_range.start+1, p.x_range.end+1)
curdoc().add_periodic_callback(cb, 200)
curdoc().add_root(p)

Unable to set the Entry box to correct position in python

I am trying to learn creating GUI using Tkinter .I created a window which includes text,Messagebox,Entry widget,labels and Radio buttons.
I used grid method for frames and tried to make entry boxes in row0 and row1 .And a message Box with Some text.But these are not properly aligned even though i gave correct rows and columns but output is not in order.
Entry box is created very far though i mentioned column1 .And message box is created as per the column specified.Can anyone help me how to solve this.If i am missing anything please let me now .
from Tkinter import*
import tkMessageBox
class Example:
def __init__(self,root):
root.title("Sample")
#Entry functions ---------------------------------------
Label(root, text="First Name").grid(row=0)
Label(root, text="Last Name").grid(row=1)
self.e1 = Entry(root)
self.e1.bind("<Return>",self.ShowChoice_radio)
self.e2 = Entry(root)
self.e2.bind("<Return>",self.ShowChoice_radio)
self.e1.grid(row=0,column=1)
self.e2.grid(row =1,column = 1)
#------------------------------------------------------------------------
self.frame=Frame(root)
self.frame.grid(row=3,sticky=W)
self.label=Label(self.frame, text="mine", width=12,bg="green",fg="white",justify=LEFT)
self.label.grid(row=3,column=4,sticky=W,pady=4)
root.minsize(width=666, height=220)
self.v=IntVar()
role=[("ENGLISH",1),("SPANISH",2),("GERMAN",3)]
Label(self.frame,text="Choose your role of target:",justify=LEFT,padx=2,pady=2).grid(row=4,sticky=W)
i=0
for txt,val in role:
i=i+1
self.rad_bt=Radiobutton(self.frame,text=txt,padx=20,variable=self.v,
command=self.ShowChoice_radio,value=val)
self.rad_bt.grid(row=4,column=i+1)
self.bottomframe = Frame(root)
self.bottomframe.grid(row=12,sticky=W)
self.hello(12)
T=Text(self.bottomframe,height=2,width=30)
T.pack(padx=100,side=TOP)
T.insert(END,"just a normal text to display!\n")
self.mbutton=Button(self.bottomframe,text='Quit',command=self.callback,state='normal')
self.mbutton.pack(padx=3,pady=3,side='left')
self.help=Button(self.bottomframe,text='Help',command=self.help_msg,width=5,justify=CENTER)
self.help.pack(padx=93,pady=3,side='left')
def ShowChoice_radio(self):
print self.v.get()
def help_msg(self):
tkMessageBox.showinfo("Help to print ",message="Not yet implemented")
root.minsize(width=666, height=666)
self.show_entry_fields()
self.help.config(state=DISABLED)
def callback(self):
if tkMessageBox.askyesno('verify','Really Quit?'):
root.destroy()
def hello(self,name):
w=Label(root,text="Hello Tkinter!",width=15).grid(row=10)
whatever_you_do = "Whatever . it is my test that \n i can anble to display manner in this case find out whether it is correct one or wrong \n)"
msg=Message(root, anchor='s',width=200,text = whatever_you_do)
msg.config(bg='lightgreen', font=('times', 14, 'italic'))
msg.grid(row=10,column=1,sticky=W)
def show_entry_fields(self):
print "First Name: %s\nLast Name: %s" % (self.e1.get(), self.e2.get())
if __name__=="__main__":
root=Tk()
app=Example(root)
root.mainloop()
Even the quit and Help buttons are not proper...!!!
I initially voted to close this because there is not a clear question, but mostly only a series of statements and opinions, at least one of which is incorrect. After looking more, I think I can answer your implied question "Why is tkinter behaving in a way that seems wrong to me?". The answer, I believe, is that you do not understand that grid coordinates are independent (start over) for each container gridded. Also, coordinates not used are ignored. In particular:
Root has a grid of 5 rows and 2 columns. Renumbering the rows 0, 1, 2, 3, 4 instead of the confusing labeling you used, there is no entry in column 1 for rows 2 and 4. The width of column 0 is determined by the width of self.frame in row 2, column 0. The entry boxes are far to the right because column 0 is very wide.
Self.frame has a grid of 2 rows and 4 columns. The first 3 columns of row 0 are empty. Self.bottomframe is packed instead of gridded. The buttons are to the left of where you want because you packed them to the left. In other words, tkinter did just what you said, which is apparently not what you want.
You might list the result better if you got rid of self.frame, put 'mine' in (2,0) or (2,0), 'Choose...' in (3, 0), and a frame with 3 radio buttoms in (3,1). Then root column 0 would not be so overly wide.

Python 2.7 - Tkinter - Button to move to next item in listbox

def nextItem(self):
active = self.skill_list_listbox.get(tk.ACTIVE)
listbox_contents = self.skill_list_listbox.get(0, tk.END)
current_pos = listbox_contents.index(active)
if current_pos + 1 < len(listbox_contents):
new_pos = current_pos + 1
self.skill_list_listbox.activate(new_pos)
self.skill_list_listbox.selection_set(tk.ACTIVE)
From what I can see within documentation this should highlight and activate the next item in the listbox. If I omit the selection_set I get what I'm looking for but there's no indicator of what's active. Adding it highlights an item, but if you continue to click the "next" button it simply adds to the highlight instead of just highlighting one item creating a long section of highlighted items, which I don't want. I've tried several different methods and this has got me the closest. If there was a 'clear selection' method I suppose I could get my desired effect of just having the next item selected and highlighted, but 3 calls just to do that seems a bit much for a common task? Any thoughts, or suggestions?
Below is an example of what I think you are trying to accomplish, using a button to select the next item in a Listbox. The gist of it is in the button's callback function, which calls selection_clear then selection_set.
Updated the example, hopefully a bit clearer as to what it happening
import Tkinter
class Application(Tkinter.Frame):
def __init__(self, master):
Tkinter.Frame.__init__(self, master)
self.master.minsize(width=256, height=256)
self.master.config()
self.pack()
self.main_frame = Tkinter.Frame()
self.some_list = [
'One',
'Two',
'Three',
'Four'
]
self.some_listbox = Tkinter.Listbox(self.main_frame)
self.some_listbox.pack(fill='both', expand=True)
self.main_frame.pack(fill='both', expand=True)
# insert our items into the list box
for i, item in enumerate(self.some_list):
self.some_listbox.insert(i, item)
# add a button to select the next item
self.some_button = Tkinter.Button(
self.main_frame, text="Next", command=self.next_selection)
self.some_button.pack(side='top')
# not really necessary, just make things look nice and centered
self.main_frame.place(in_=self.master, anchor='c', relx=.5, rely=.5)
def next_selection(self):
selection_indices = self.some_listbox.curselection()
# default next selection is the beginning
next_selection = 0
# make sure at least one item is selected
if len(selection_indices) > 0:
# Get the last selection, remember they are strings for some reason
# so convert to int
last_selection = int(selection_indices[-1])
# clear current selections
self.some_listbox.selection_clear(selection_indices)
# Make sure we're not at the last item
if last_selection < self.some_listbox.size() - 1:
next_selection = last_selection + 1
self.some_listbox.activate(next_selection)
self.some_listbox.selection_set(next_selection)
root = Tkinter.Tk()
app = Application(root)
app.mainloop()

How to use grid_forget to eliminate a specific ordering of buttons after they have been instantiated

I am building the GUI for a boardgame for my software engineering class. I am using the TKinter toolkit on Python 2.7 (windows). I am stuck right now because I cant seem to find a way to ignore/forget a certain ordering of buttons. Essentially, I am trying to create a grid of buttons that would represent my game board. And right now, I have a game board that has a total of 49 buttons on a 7x7 grid.
So far this is what I have been able to do:
Instantiate all my button objects where columns = x and rows = y. This easily build a grid of x*y
I then place each button into a list (lets call this list1)
I want to use my list of button objects to ignore/forget/delete (for lack of a better description) certain buttons. I am thinking I can create a 2nd list (list2) of the indexes of the button objects that I want to use grid_forget on and then compare my two lists and only keep the ones that are not in list2. Unfortunately, this doesnt work out the way I want it to. Here is the code:
gameboard = ttk.Labelframe(root, padding = (8,8,8,8), text = "Gameboard",
relief = "sunken")
#forgetButtons will not be displayed on the game board b/c they do not have a
#label (they are not a: room, hallway, starting space)
forgetButtons = [0,1,3,5,6,7,13,14,16,18,21,30,32,41,42,43,45,46,47,48]
#this list tracks all the buttons on the gameboard
myButtons=[]
count = 0
for x in range(7): #build a 7x7 grid of buttons (49 buttons total)
for y in range(7):
btn = Button(gameboard, width=7, height=4)
myButtons.append(btn)
btn.grid(column=x, row=y, padx = 3, pady = 3)
#do some comparison here between the two lists
#to weed out the buttons found in forgetButtons
#**or maybe it should not be done here?**
btn.config(text="Room%d\none\ntwo\nfour\nfive" % x)
You don't need grid_forget these widgets if you just don't create them.
import itertools
import Tkinter as tk
root = tk.Tk()
forgetButtons = [0,1,3,5,6,7,13,14,16,18,21,30,32,41,42,43,45,46,47,48]
myButtons = []
for x, y in itertools.product(range(7), repeat=2):
if not x*7 + y in forgetButtons:
btn = tk.Button(root, width=7, height=4, text="Room%d\none\ntwo\nfour\nfive" % x)
btn.grid(column=x, row=y, padx=3, pady=3)
myButtons.append(btn)
root.mainloop()
I don't know the order to calculate the position for forgetButtons (usually the first index represents the row and the second one the column), but you can easily switch it.