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
Related
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.
I've written a GUI for a script that does some geometrical calculations. Certain ranges of values break the computation (e.g. find the intersection of two shapes that don't intersect.) I raise exceptions in those cases. I'd like to prevent the user from adjusting the spinbox value beyond the point where exceptions are raised.
I've tried overwriting the validator method for the QDoubleSpinBox. This works great when I manually enter values with the keyboard. But, it doesn't prevent me from clicking the up and down arrows.
How I can limit the ability of the user to run-up the values outside of the acceptable range?
Note: The actual some_complicated_function involves the values from 5 different spinboxes.
from PyQt4 import QtCore, QtGui
import sys
def some_complicated_function(val_a):
if val_a + 3 < 10:
return True
else:
raise Exception("Giant number!")
class SpinBoxSpecial(QtGui.QDoubleSpinBox):
def validate(self, value, pos):
# print float(value)
try:
some_complicated_function(float(value))
print "yup"
return QtGui.QValidator.Acceptable, QtGui.QValidator.Acceptable
except:
print "nope"
return QtGui.QValidator.Invalid, QtGui.QValidator.Invalid
a = QtGui.QApplication(sys.argv)
w = QtGui.QMainWindow()
w.resize(320, 100)
w.setWindowTitle("PyQT Python Widget!")
spinbox = SpinBoxSpecial(w)
spinbox.move(20, 20)
spinbox.CorrectionMode = QtGui.QAbstractSpinBox.CorrectToPreviousValue
w.show()
sys.exit(a.exec_())
Edit:
The basic ask is: I want to call a function when the value of a spinbox changes (via mouse or keyboard). If that function throws an exception, I want the value of the spinbox to revert to what it was.
Here is a simple way to dynamically set the range on a spinbox:
class SpinBoxSpecial(QtGui.QDoubleSpinBox):
def __init__(self, parent=None):
super(SpinBoxSpecial, self).__init__(parent)
self._last = self.value()
self.valueChanged.connect(self.handleValueChanged)
def handleValueChanged(self, value):
try:
some_complicated_function(float(value))
print "yup", value
self._last = value
except:
print "nope", value
if value > self._last:
self.setMaximum(self._last)
else:
self.setMinimum(self._last)
EDIT:
Just realized the above won't work correctly if a value is typed in directly, because it could fix the min/max too early. So maybe this would be better:
def handleValueChanged(self, value):
try:
some_complicated_function(float(value))
print "yup", value
self._last = value
except:
print "nope", value
self.setValue(self._last)
I am trying to create a PyQt Dropdown menu(combo box), whose value I need to pass to another function.
Here is a snippet of my code
def combo_box(self):
combo = QtGui.QComboBox(self)
...#Filled in code here
for i in range(0,len(arr)):
combo.addItem(arr[i])
#I want to get the value of the selected Drop-down content to be stored in value
value = combo.activated[str].connect(self.ComboValue)
print value
def ComboValue(self,Text):
print Text
return Text
When I print the variable Text in the ComboValue method it prints it right, but when I print value from the combo_box method it prints None.
I wanted to know why this happens, and is there an alternative to return the value to the other method?
combo.activated[str].connect(self.ComboValue) is signal and signal never return you anything back, so that's why you getting None. Take a look http://pyqt.sourceforge.net/Docs/PyQt4/new_style_signals_slots.html
You may use this value = str(combo.currentText()), but don't know you want this.
And change combo.activated[str].connect to combo.currentIndexChanged [str].connect to get your values properly
create the combobox, then wait till user activates an item:
def combo_box(self):
combo = QtGui.QComboBox(self)
...#Filled in code here
for i in range(0,len(arr)):
combo.addItem(arr[i])
combo.activated.connect(self.ComboValue)
# save it and wait for user to do something:
self.combo = combo
def ComboValue(self, Text):
# user has selected an item, save it:
self.value = Text
assert combo.currentText() == Text
... do something with it ...
Not tested so details may be wrong.
I am trying to have a series of checkboxes which can be selected or not selected - then when the user presses the button, the letters allocated to the checkboxes should be added to an inputted string and then printed.
I am having 2 major problems;
The when the user presses a checkbox, all of the checkboxes are selected.
I would like to have the default being that all of them as checked, but I cannot find how to do this. If this cannot be answered, it is less important than the 1st problem, and hence doesn't matter as much.
This is my code so far;
import Tkinter
class MENU():
def __init__(self,NewData):
self.SCREEN = Tkinter.Tk()
self.NewData = NewData
self.Selection = {"A":1,"B":1,"C":1,"D":1}
self.A = Tkinter.Checkbutton(self.SCREEN,text="A",variable=self.Selection["A"]).pack()
self.B = Tkinter.Checkbutton(self.SCREEN,text="B",variable=self.Selection["B"]).pack()
self.C = Tkinter.Checkbutton(self.SCREEN,text="C",variable=self.Selection["C"]).pack()
self.D = Tkinter.Checkbutton(self.SCREEN,text="D",variable=self.Selection["D"]).pack()
self.BtnFinish = Tkinter.Button(self.SCREEN,text="Finish selection",command=self.FinishSelection)
self.BtnFinish.pack()
self.SCREEN.mainloop()
def FinishSelection(self):
SelectionString = ""
for n in self.Selection:
if self.Selection[n]:
SelectionString+=n
self.NewData+="\nQuestions\n"+SelectionString+"\n"
print self.NewData
MENU("")
If it matters at all, this is for Python 2.7.3. Additionally, my thanks, and also apologies to those of you who likely have to point out something incredibly obvious/basic, which, as a beginner for Tkinter, I have not realised.
You must use one of the Tkinter objects StrintVar, IntVar, BooleanVar or DoubleVar normally (StringVar) as the value of the variable argument. You can't use a normal python variable. You'll have to create an individual variable for each.
For example:
self.Selection = {"A": Tkinter.BoolVar(), "B": Tkinter.BoolVar(), ...}
self.Selection["A"].set(True)
...
Then, to get the value you'll need to use the get method:
value = self.Selection["A"].get()
If I create an entry box like so:
myentry = Entry ()
myentry.place (x = 54,y = 104)
the value that the user enters is a string value. What do I have to add so that the entry is a float? I have tried to write "float" in the parentheses beside Entry but it didn't work and showed me an error saying that tk() does not support float. Any help would be appreciated!
I wrote a simple script to demonstrate how to do what you want:
from Tkinter import Tk, Button, Entry, END
root = Tk()
def click():
"""Handle button click"""
# Get the input
val = myentry.get()
try:
# Try to make it a float
val = float(val)
print val
except ValueError:
# Print this if the input cannot be made a float
print "Bad input"
# Clear the entrybox
myentry.delete(0, END)
# Made this to demonstrate
Button(text="Print input", command=click).grid()
myentry = Entry()
myentry.grid()
root.mainloop()
When you click the button, the program tries to make the text in the entrybox a float. If it can't, it prints "Bad input". Otherwise, it prints the float in the terminal.