I'm brand new at python, and didn't understand the other answers for this question. Why when I run my code, does int(weight[0]) not convert variable "weight" into a integer. Try your best to dumb it down because I'm really new and still don't quite understand most of it. Here is the relevant section of my code
weight = (lb.curselection())
print ("clicked")
int(weight[0])
print (weight)
print (type(weight))
and heres my code for this script
lb = Listbox(win, height=240)
lb.pack()
for i in range(60,300):
lb.insert(END,(i))
def select(event):
weight = (lb.curselection())
print ("clicked")
int(weight[0])
print (weight)
print (type(weight))
lb.bind("<Double-Button-1>", select)
Thanks
When I run the code, it comes up with TypeError: int() argument must be a string, a bytes-like object or a number, not 'tuple'
and I want it instead to convert the "weight" variable into a integer, so I can use it for math operations.
Full Traceback:Traceback (most recent call last):
File "C:\Users\Casey\AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 1699, in __call__
return self.func(*args)
File "C:/Users/Casey/AppData/Local/Programs/Python/Python36-32/s.py", line 11, in select
int(weight)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'tuple'
what you're looking for is
weight = int(weight[0])
int is a function that returns an integer, so you have to assign that return to a variable.
if what you're looking for is to reassign the variable weight with the value of its first record, that code should work for you.
If the item is already an integer then the int call might be redundant, you might be able to get it with just
weight = weight[0]
I noticed you were using lb.bind("<Double-Button-1>", select) here. This does get around the issue with curselection() returning the last selected list item but I would say using lb.bind('<<ListboxSelect>>', select) would work better for this. Binding to <<ListboxSelect>> works because this event triggers after the selection has changed and when you go to call curselection() using this event instead you will get the correct output you are looking for.
Here is a bit of code that provides an example use of the <<ListboxSelect>> event:
import tkinter as tk
class Application(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self.lb = tk.Listbox(self.parent, height=4)
self.lb.pack()
self.lb.bind('<<ListboxSelect>>', self.print_weight)
for item in ["one: Index = 0", "two: Index = 1", "three: Index = 2", "four: Index = 3"]:
self.lb.insert("end", item)
def print_weight(self, event = None):
# [0] gets us the 1st indexed value of the tuple so weight == a number.
weight = self.lb.curselection()[0]
print(weight)
if __name__ == "__main__":
root = tk.Tk()
app = Application(root)
root.mainloop()
You will notice the print out in the console will be the current selected item on a single click. This will prevent the need for a double click.
Related
I'm trying to develop a text editor that replaces user-defined shortcuts with words. I've been able to solve the replace function and tweak it to my design, but I'm having trouble taking the syntax of the console (see code below) and feeding the information to the parent window. However, I keep running into this error and I've been working for a couple days on how to fix this. It keeps saying "replace_shortcut() missing 1 required positional argument: 'shortcut'", but I'm not sure what I'm supposed to do. I've looked on other questions on SO, but nothing that's relevant to my problem. (If it helps I'm new to Python, switched over from C/C++)
Code:
from tkinter import *
# For the window
root = Tk()
root.title("Scrypt")
# For the parent text
text = Text(root)
text.pack(expand=1, fill=BOTH)
# For console window and text
win1 = Toplevel()
console_text = Text(win1, width=25, height=25)
console_text.pack(expand=1, fill=BOTH)
# For menubar
menubar = Menu(root)
root.config(menu=menubar)
def get_console_text(*args):
syntax = console_text.get('1.0', 'end-1c')
tokens = syntax.split(" ")
word = tokens[:1]
shortcut = tokens[2:3]
# return word, shortcut
def replace_shortcut(word, shortcut):
idx = '1.0'
while 1:
idx = text.search(shortcut, idx, stopindex=END)
if not idx: break
lastidx = '% s+% dc' % (idx, len(shortcut))
text.delete(idx, lastidx)
text.insert(idx, word)
lastidx = '% s+% dc' % (idx, len(word))
idx = lastidx
def open_console(*args):
replace_shortcut(get_console_text())
win1.mainloop()
# Function calls and key bindings
text.bind("<space>", replace_shortcut) and text.bind("<Return>", replace_shortcut)
win1.bind("<Return>", open_console)
# Menu bar
menubar.add_command(label="Shortcuts", command=open_console)
root.mainloop()
The traceback (I think that's what it's called):
replace_shortcut() missing 1 required positional argument: 'shortcut'
Stack trace:
> File "C:\Users\Keaton Lee\source\repos\PyTutorial\PyTutorial\PyTutorial.py", line 42, in open_console
> replace_shortcut(get_console_text())
> File "C:\Users\Keaton Lee\source\repos\PyTutorial\PyTutorial\PyTutorial.py", line 54, in <module>
> root.mainloop()
I'm not sure if I'm missing a second declaration that needs to be, well, declared, but any help you guys can offer is appreciated!
your function get_console_text() doesn't actually return anything, so when you call replace_shortcut(get_console_text()), you are effectively calling replace_shortcut(None)
Notice in your get_console_text() function the lines are :
def get_console_text(*args):
syntax = console_text.get('1.0', 'end-1c')
tokens = syntax.split(" ")
word = tokens[:1]
shortcut = tokens[2:3]
# return word, shortcut <------ you have commented out the return !!!!
You also need to do :
replace_shortcut(*get_console_text())
Note the *, this tells Python that the return value from get_console_text needs to be unpacked into two arguments before being set to replace_shortcut as two arguments.
The reason is clean as other answer and comment pointed out.
Just one more point:
get_console_text() will return one object None, so the complaint is "missing 1 required positional argument: 'shortcut'", not two arguments.
If I store the canvas item in a variable I expect that is stored as an tkinter.rectangle object which I can use later.
rec = can.create_rectangle(l, fill="blue")
But instead is stored as an integer << class 'int' >>
from tkinter import Tk, Canvas, Button
def press(canv, rect):
print("pressed")
canv.move(rect, 10)
l = [50,100,100,200]
root = Tk()
can = Canvas(root)
can.pack()
rec = can.create_rectangle(l, fill="blue")
print("rec",rec) #1
print("type(rec) ", type(rec)) #<class 'int'>
b = Button(root, text="NOTHING", command=lambda:press(can, rec))
b.pack()
print("type(b) = ",type(b)) #<class 'tkinter.Button'>
print("b = ",b) #TCL id like .41549040
root.mainloop()
When run this code it returns a error:
_tkinter.TclError: wrong # args: should be ".21823184 move tagOrId xAmount yAmount"
Why is it of type integer and how get the id of the canvas item to move it around later?
If I store the canvas item in a variable I expect that is stored as an tkinter.rectangle object
That is a false expectation. The documented behavior is that it returns an integer id.
Why is it of type integer and how get the id of the canvas item to move it around later?
There is no other id than the integer returned by the create_rectangle method. You can use this id to move the item around.
When run this code it returns a error: _tkinter.TclError: wrong # args: should be ".21823184 move tagOrId xAmount yAmount"
That error message is telling you exactly what is wrong: wrong # args. You must supply the id, and an xAmount and yAmount. You are only giving the id and the xAmount.
The solution is easy: you don't give the Y value to function.
The function wants:
canv.move(item, x, y)
If you need to move its only on the x axis, you have to write the following string:
canv.move(rect, 10, 0)
So i'm making a hangman game in tkinter and I'm trying to make the buttons disappear when pressed and reappear when the restart button is pressed. I'm still learning to code and have tried to adjust it to include classes to make the code clearer. This is the code I've used to create the button widgets:
class Buttons:
def __init__(self, letter, column, row):
self.letter = letter
self.column = column
self.row = row
def create(self):
column = self.column
row = self.row
letter = self.letter
self = tk.Button(window, text=self.letter, bg = colour, font=FONT,
command=lambda : check(letter))
self.place(relx=column, rely=row)
And then I place the buttons like this and it all works fine:
A = Buttons('A', column1, row1).create()
What I want to do however is access the 'self.letter', 'self.row', and 'self.column' outside of the class definition, however it says that the object is a Nonetype when I try to use 'A.letter' and it has no attribute letter.
Traceback (most recent call last):
File "C:\Users\cameron\Documents\Python\Hangman\Hangman v2.1.py", line 227, in <module>
print(A.letter)
AttributeError: 'NoneType' object has no attribute 'letter'
Does anyone know how I could access this?
Thank you
You don't need to reassign self. Try this:
def create(self):
#column = self.column # don't need these
#row = self.row
#letter = self.letter
self.tkbutton = tk.Button(window, text=self.letter, bg = colour, font=FONT, command=lambda : check(letter))
# Stashes the tk.Button instance away in `self.tkbutton`.
self.tkbutton.place(relx=self.column, rely=self.row)
self stays the same all the time, so you should never say self = <whatever>. Instead, use self.<some field name> = <whatever value>. Then the <some field name> will be accessible from outside as A.<some field name>.
Then, to use the button, try
A = Buttons('A', column1, row1) # calls A.__init__()
A.create()
# at this point A.tkbutton exists and is accessible.
Although a better approach might be to combine create's work into __init__ so that the button is created and placed in the A=Buttons(...) call.
Edit The reason you got a NoneType error is that create() does not include a return statement. Therefore, its return value is None. As a result, A=Buttons(...).create() returns None, i.e., a NoneType.
I've written an app that takes some data from the user, queries the API of a website, and returns and processes the data given by the API. I'm trying to allow the user greater control of what happens next by creating checkboxes for each item retrieved.
Because the number of items retrieved will vary on each use, I'm putting the checkboxes and the IntVars for if they're checked or not into lists. However, when I try to set the IntVars to 1 (so they all start out checked) I get a TypeError telling me it wants the IntVar instance as the first arg, but that doesn't make any sense to me as I'm trying to call a method for the IntVar in the first place.
This is a much simplified version of my code that generates an identical error:
import Tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.grid()
self.test_names = ["Box 1", "Box 2", "Box 3", "Box 4"]
self.boxes = []
self.box_vars = []
self.box_num = 0
btn_test1 = tk.Button(self, text="Test 1", width = 11, command = self.test1)
btn_test1.grid()
def test1(self):
for name in self.test_names:
self.box_vars.append(tk.IntVar)
self.boxes.append(tk.Checkbutton(self, text = name, variable = self.box_vars[self.box_num]))
self.box_vars[self.box_num].set(1)
self.boxes[self.box_num].grid(sticky = tk.W)
self.box_num += 1
root = tk.Tk()
app = Application(master=root)
app.mainloop()
And the error message when pushing the button:
TypeError: unbound method set() must be called with IntVar instance as first
argument (got int instance instead)
What am I doing wrong?
Classic problem. You add the type IntVar instead of adding an object of type IntVar. Add parentheses like this:
self.box_vars.append(tk.IntVar())
Yes you forgot the brackets. The result will be and not a tkinter intvar instance.
Im sitting in a situation i can't figure out myself.
When im using the Entry widget to get user interaction i am having a hard time finding the right way to validate the data.
The situation:
I have two Entry widgets in which the user must enter two variables which has to be floats.
While i can run a program that only works properly if the entered value is a float, if i then leave it blank or enter a letter shuts down - therefor i want to validate the entry to be a float:
variableentry = Entry(root and so on)
variableentry.grid()
I am using the:
variablename = float(variableentry.get())
And when i:
print(type(variablename)
i get the message:
<class 'float'>
thus i am unable to use the
#...
try:
if(variablename is not float):
messagebox.showerror("Error", "Incorrect parameter")
return
This obviously isnt working since the variablename is of class 'float' and not float, i have tried different ways of entering instead of float in the if statement - without any luck.
Any ideas?
In advance, thanks!
Best regards,
Casper
EDIT:
I have found the:
from Tkinter import *
class ValidatingEntry(Entry):
# base class for validating entry widgets
def __init__(self, master, value="", **kw):
apply(Entry.__init__, (self, master), kw)
self.__value = value
self.__variable = StringVar()
self.__variable.set(value)
self.__variable.trace("w", self.__callback)
self.config(textvariable=self.__variable)
def __callback(self, *dummy):
value = self.__variable.get()
newvalue = self.validate(value)
if newvalue is None:
self.__variable.set(self.__value)
elif newvalue != value:
self.__value = newvalue
self.__variable.set(self.newvalue)
else:
self.__value = value
def validate(self, value):
# override: return value, new value, or None if invalid
return value
from http://effbot.org/zone/tkinter-entry-validate.htm
However the rest of the code is not written in classes (i know this is not optimal but it is demanded by the teacher) will that effect the above example? And how would i make it fit my needs?
What you want to do is to try converting the contents of the entry box to a float, and report an error message if the conversion is not possible. Doing variablename = float(variableentry.get()) is fine, but to catch errors raised by float if the string it is given cannot be converted, you must wrap the line in a try block, and catch the ValueError raised by float. If there is no exception, you can proceed with the code:
try:
variablename = float(variableentry.get())
except ValueError:
# error messagebox, etc
else:
# do stuff with variablename