I'm currently having an issue with a QLE that I created. I would like the qle to take a value, turn it into a float and then increase or decrease a label value depending on if the value is positive or negative. The only problem is is that every time I type something into the qle it will start adding that value to the label before I'm done typing. For example: I type in "4" into the qle that works but once I type in "4." anything it will read it as 4 two times so the label will be changed to 8. Maybe there's a way so that when I press a button it will increase or decrease but only after I press the button?
I added code for a button I created and maybe it would be easier to link that with the qle. Many thanks!
#this creates the increase button for cam1 focus
self.btnCam1IncreaseFocus = QtGui.QPushButton("+",self)
self.btnCam1IncreaseFocus.clicked.connect(self.cam1IncreaseFocus)
self.btnCam1IncreaseFocus.resize(25,25)
self.btnCam1IncreaseFocus.move(75,100)
#This creates a textbox or QLE for a custom tweak value for cam1 focus
self.qleTextBoxCam1Focus = QtGui.QLineEdit(self)
self.qleTextBoxCam1Focus.resize(25,25)
self.qleTextBoxCam1Focus.move(40,100)
self.qleTextBoxCam1Focus.textChanged[str].connect(self.qleCam1Focus)
def cam1IncreaseFocus(self):
text = self.lblCam1Focus.text()
n = float(text)
n = n + 1
self.lblCam1Focus.setText(str(n))
def qleCam1Focus(self):
text = self.qleTextBoxCam1Focus.text()
if text == "":
text = "0.0"
if str(text).isalpha() == False:
n = float(text)
textLabel = self.lblCam1Focus.text()
if textLabel == "":
textLabel = "0.0"
y = float(textLabel)
result = n + y
if result <= 0.0:
result = 0.0
self.lblCam1Focus.setText(str(result))
Instead of textChanged, use the editingFinished signal, which will only fire when return/enter is pressed, or when the line-edit loses focus:
self.qleTextBoxCam1Focus.editingFinished.connect(self.qleCam1Focus)
Related
I am attempting to validate the text box field so that the user can only insert integers, although i have used a while loop to attempt and cannot figure it out I keep getting errors. Please help.
from tkinter import *
import tkinter as tk
from tkinter.tix import *
# setup the UI
root = Tk()
# Give the UI a title
root.title("Distance converter Miles to Kilometers")
# set window geometry
root.geometry("480x130")
# setup the buttons
valRadio = tk.IntVar()
myText=tk.StringVar()
e1 =tk.IntVar()
def calculate(*arg):
while True:
try:
if valRadio.get() == 1:
# get the miles ( Calculation )
res = round(float(e1.get()) / 1.6093,2)
# set the result text
myText.set( "Your input converts to " + str(res) + " Miles")
break
if valRadio.get() == 2:
# get the kilometeres
res = round(float(e1.get()) * 1.6093,2)
# set the result text
myText.set( "Your input converts to " + str(res) + " Kilometers")
break
if ValueError:
myText.set ("Please check selections, only Integers are allowed")
break
else:
# print error message
res = round(float(e1.get()) / 1.6093,2)
myText.set ("Please check selections, a field cannot be empty")
break
except ValueError:
myText.set ("Please check selections, a field cannot be empty")
break
# Set the label for Instructions and how to use the calculator
instructions = Label(root, text="""Hover me:""")
instructions.grid(row=0, column=1)
# set the label to determine the distance field
conversion = tk.Label( text=" Value to be converted :" )
conversion.grid(row=1,column = 0,)
# set the entry box to enable the user to input their distance
tk.Entry(textvariable = e1).grid(row=1, column=1)
#set the label to determine the result of the program and output the users results below it
tk.Label(text = "Result:").grid(row=5,column = 0)
result = tk.Label(text="(result)", textvariable=myText)
result.grid(row=5,column=1)
# the radio button control for Miles
r1 = tk.Radiobutton(text="Miles",
variable=valRadio, value=1).grid(row=3, column=0)
# the radio button control for Kilometers
r2 = tk.Radiobutton(text="Kilometers",
variable=valRadio, value=2).grid(row=3, column=2)
# enable a calculate button and decide what it will do as well as wher on the grid it belongs
calculate_button = tk.Button(text="Calculate \n (Enter)", command=calculate)
calculate_button.grid(row=6, column=2)
# deploy the UI
root.mainloop()
I have attempted to use the While loop inside the code although I can only get it to where if the user inputs text and doesn't select a radio button the error will display but I would like to have it where the text box in general will not allow anything but integers and if it receives string print the error as it does if the radio buttons aren't selected.
define validation type and validatecommand. validate = key makes with every key input it runs validatecommand. It only types if that function returns true which is 'validate' function in this case.
vcmd = (root.register(validate), '%P')
tk.Entry(textvariable = e1,validate="key", validatecommand=vcmd).grid(row=1, column=1)
this is the validation function
def validate(input):
if not input:
return True
elif re.fullmatch(r'[0-9]*',input):
return True
myText.set("Please check selections, only Integers are allowed")
return False
it return true only when its full of numbers([0-9]* is an regular expression which defines all numbers) or empty. If it contains any letter it return False any it denied this way.
Also do not forget to imports
import re
I read a lot for it and I have the sentiment that there is no solution for me.
Context: user has to enter 6-digit calculation number in the entries. The 9x entries are created by a loop. I wrote the condition to detect if the user did a mistake : number which contains less or more than 6 digit or / and contains a letter. They are working, I tested them. Only 6-digit number are accepted (if 0, it's ok since it means that the user just need to get less than 9x documents).
Goal: if the user did one mistake, a message "Error in the number" at the place of the "0" has to appear right next to the concerned and "faulty" entry.
Everything will be activated through a button.
What I tried: with a list, but it doesn't work.
How can I change the Label dynamically created by the loop ?
user_entries=[]
error_list_length=[0,0,0,0,0,0,0,0,0]
error_list_letters=[0,0,0,0,0,0,0,0,0]
error_calculation_list=[0,0,0,0,0,0,0,0,0]
nbofcalc=9
a=0
b=1
ddd=791250
#------ Function to check if the entered calculation number are composed of 6 characters (mandatory)
def check_calc_number():
global gg_error
gg=0
gg_error=0
while gg<nbofcalc:
if len(user_entries[gg].get()) != 6:
if len(user_entries[gg].get()) ==0:
gg_error+=0
error_list_length[gg]=0
else:
gg_error+=1
error_list_length[gg]=1
else:
gg_error+=0
error_list_length[gg]=0
gg+=1
#------ Function to check if the entered calculation number contains a or many letters (prohibited)
def check_calc_letter():
global hh_error
hh=0
hh_error=0
alphabet_x='a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
for x in range(nbofcalc):
for n in user_entries[hh].get():
if n in alphabet_x:
hh_error+=1
error_list_letters[hh]=1
hh+=1
#------ Function to check with entries has an error and update the list "error_calculation_list" to try to displays the message "Error in the number" next to the concerned entries
def error_length_letters_display():
ww=0
while ww<nbofcalc:
if error_list_length[ww]==1 :
error_calculation_list[ww]="Error"
var_calculation.set(error_calculation_list[ww])
if error_list_letters[ww]==1:
error_calculation_list[ww]="Error"
var_calculation.set(error_calculation_list[ww])
ww+=1
#----- Loop to crate the entries and Label
for x in range(nbofcalc):
cadre1=Frame(fenetre)
cadre1.pack(side=TOP,anchor=NW)
cadre=Frame(cadre1)
cadre.pack()
c=str(b)
calc=Label(cadre,text="Calculation "+c+" ")
calc.pack(side=LEFT)
var_entry=StringVar()
my_entry=Entry(cadre,textvariable=var_entry, bd=5)
my_entry.insert(0,ddd)
my_entry.pack(side=LEFT)
var_calculation=StringVar()
var_calculation.set(error_calculation_list[a])
calc_error_frame=Label(cadre, textvariable=var_calculation) # The Label to change if error
calc_error_frame.pack(side=RIGHT)
user_entries.append(my_entry)
a+=1
b+=1
ddd+=1
Thank you !
You can store values and objects you need to change, so then you can change them dinamically. See this example
from tkinter import *
r = Tk()
my_entries = []
for i in range(5):
e = Label(r, text=i)
my_entries.append(e)
e.pack(side='top')
r.after(4000, lambda: my_entries[2].configure(text='Example'))
r.mainloop()
EDIT 1:As TheLizzard and Cool Cloud pointed out, it's better to avoid using time.sleep() while using tkinter. Replaced with non-blocking after()
you could setup the trace function for tk.StringVar(), when user enter any value into Entry, it will be checked. for example as shown on below user only can type decimal, and you and setup length as well.
def create_widgets(self):
self.vars = tk.StringVar()
self.vars.trace('w', partial(self.validate2, 1, 1))
# Min Voltage Validating Part
self.vars1 = tk.StringVar()
self.vars1.trace('w', partial(self.validate2, 2, 2))
# Max Voltage Validating Part
self.vars2 = tk.StringVar()
self.vars2.trace('w', partial(self.validate2, 3, 4))
# Current Validating Part
self.vars3 = tk.StringVar()
self.vars3.trace('w', partial(self.validate2, 4, 3))
# Channel Validating Part
# function( key, size)
self.enter_info = tk.Label(self, text="Please enter your information: ", bg="lightgrey")
self.enter_info.grid(tke_Table_EnterInfo)
self.voltage = tk.Label(self)
self.voltage["text"] = "MinVoltage"
self.voltage.grid(tke_Label_MinVoltage)
self.voltageInput = tk.Entry(self, width=10, textvariable=self.vars).grid(tke_StringBox_MinVoltage)
self.vars.set(0)
# Min Voltage Validating Part
self.current = tk.Label(self)
self.current["text"] = "MaxVoltage"
self.current.grid(tke_Label_MaxVoltage)
self.currentInput = tk.Entry(self, width=10, textvariable=self.vars1).grid(tke_StringBox_MaxVoltage)
self.vars1.set(5)
# Max Voltage Validating Part
self.power = tk.Label(self)
self.power["text"] = "Current"
self.power.grid(tke_Label_MaxCurrent)
self.powerInput = tk.Entry(self, width=10, textvariable=self.vars2).grid(tke_StringBox_MaxCurrent)
self.vars2.set(62.5)
# Max Current Validating Part
self.channel = tk.Label(self)
self.channel["text"] = "channel"
self.channel.grid(tke_Label_Channel)
self.channelInput = tk.Entry(self, width=10, textvariable=self.vars3).grid(tke_StringBox_Channel)
self.vars3.set(8)
# Max Channel Validating Part
def validate2(self, key, size, *args):
# TODO:add more information
if key == 1:
value = self.vars.get()
elif key == 2:
value = self.vars1.get()
elif key == 3:
value = self.vars2.get()
else:
value = self.vars3.get()
if not value.isdecimal():
print(len(value))
# if len(value) < 2:
corrected = ''.join(filter(str.isdecimal, value))
if key == 1:
self.vars.set(corrected)
elif key == 2:
self.vars1.set(corrected)
elif key == 3:
self.vars2.set(corrected)
else:
self.vars3.set(corrected)
if key == 1:
corrected = self.vars.get()
corrected = corrected[0:size]
self.vars.set(corrected)
elif key == 2:
corrected = self.vars1.get()
corrected = corrected[0:size]
self.vars1.set(corrected)
elif key == 3:
corrected = self.vars2.get()
corrected = corrected[0:size]
self.vars2.set(corrected)
else:
corrected = self.vars3.get()
corrected = corrected[0:size]
self.vars3.set(corrected)
The following code works for requesting input from a user through the Tkinter GUI and turning that input into a usable variable in the main script. However, any value that I put as the last in a list in the if statement (here "4") will hang and crash the program upon enter. This was also the case for "n" in a yes/no scenario. It also happens if I replace the if statement with a while not in [values] - the final value will crash the program. Is this just a quirk of Tkinter or is there something that I am missing?
import tkinter as tk
from tkinter import *
# get choice back from user
global result
badinput = True
while badinput == True:
boxwidth = 1
result = getinput(boxwidth).strip().lower()
if result in ['1', '2', '3', '4']:
badinput = False
# iterate through play options
if result == '1':
# Do Something
elif result =='2':
# Do Something
elif result =='3':
# Do Something
else:
# Do Something
def getinput(boxwidth):
# declaring string variable for storing user input
answer_var = tk.StringVar()
# defining a function that will
# get the answer and set it
def user_response(event):
answer_var.set(answer_entry.get())
return
answer_entry = tk.Entry(root, width = boxwidth, borderwidth = 5)
# making it so that enter calls function
answer_entry.bind('<Return>', user_response)
# placing the entry
answer_entry.pack()
answer_entry.focus()
answer_entry.wait_variable(answer_var)
answer_entry.destroy()
return answer_var.get()
In case anyone is following this question, I did end up solving my problem with a simple if statement within the callback. I can feed a dynamic "choicelist" of acceptable responses into the callback upon user return. If the answer is validated, the gate_var triggers the wait function and sends the program and user response back into the program.
'''
def getinput(boxwidth, choicelist):
# declaring string variable for storing user input
answer_var = tk.StringVar()
gate_var = tk.StringVar()
dumplist = []
# defining a function that will
# get the answer and set it
def user_response(event):
answer_var.set(answer_entry.get())
if choicelist == None:
clearscreen(dumplist)
gate_var.set(answer_entry.get())
return
if answer_var.get() in choicelist:
# passes a validated entry on to gate variable
clearscreen(dumplist)
gate_var.set(answer_entry.get())
else:
# return to entry function and waits if invalid entry
clearscreen(dumplist)
ErrorLabel = tk.Label(root, text = "That is not a valid response.")
ErrorLabel.pack()
ErrorLabel.config(font = ('verdana', 18), bg ='#BE9CCA')
dumplist.append(ErrorLabel)
return
global topentry
if topentry == True:
answer_entry = tk.Entry(top, width = boxwidth, borderwidth = 5)
else:
answer_entry = tk.Entry(root, width = boxwidth, borderwidth = 5)
# making it so that enter calls function
answer_entry.bind('<Return>', user_response)
# placing the entry
answer_entry.pack()
answer_entry.focus()
answer_entry.wait_variable(gate_var)
answer_entry.destroy()
return answer_var.get()
'''
it's my first post here. I'm trying to create a 5x5 table with random numbers. The goal is that the user is supposed to click from the smallest to biggest number on the table, and once he clicked correct one it should be disabled. I don't want to attach each button to variable. I've created windows with random number, but now I'd like to create function which would check if the clicked number is the smallest, and if the answer is yes I have to change it's state to DISABLED. I been sitting on this for over 4 hours and I have no idea how to access clicked button information like 'text', and how can I disable it after user clicks on it.
Here's what I got so far, working on dat function.
from tkinter import *
import random
def click(z=None):
global o
Button(state=DISABLED)
o=Tk()
y=0
listrow=[4,3,2,1,0]
numbers=[]
spr=IntVar()
while len(numbers) < 25:
r = random.randint(0,999)
if r not in numbers:
numbers.append(r)
for i in range(1,26):
Button(o, text=str(numbers[i-1]), width=10).grid(row=listrow[i%5], column=y)
if i == 5:
y+=1
elif i == 10:
y+=1
elif i==15:
y+=1
elif i==20:
y+=1
else:
continue
o.bind_all('<Button-1>', click)
o.mainloop()
Consider integrating a class object with defined modules for building controls and the button click event. Specifically, on each button click check the minimum of the numbers list and disable corresponding button item by passing the index integer as parameter. See adjustment below.
Credit to #BrenBarn for the clever lambda solution lambda i=i in button command call:
from tkinter import *
import random
class NUMapp():
def __init__(self):
self.root = Tk()
self.buildControls()
self.root.mainloop()
def buildControls(self):
self.root.wm_title("Random Number Picker")
x = 0; y = 0
self.numbers = []; self.numbtn = []
while len(self.numbers) < 25:
r = random.randint(0,999)
if r not in self.numbers:
self.numbers.append(r)
for i in range(1,26):
self.numbtn.append(Button(self.root, text=str(self.numbers[i-1]), width=10,
command=lambda i=i:self.btnclick(i-1)))
self.numbtn[i-1].grid(row=x, column=y)
x+=1
if i % 5 == 0:
x = 0
y += 1
def btnclick(self, mynum):
currnum = int(self.numbtn[mynum].cget('text')) # CAPTURE BUTTON TEXT
if currnum == min(self.numbers):
self.numbtn[mynum].config(state="disabled") # DISABLE BUTTON
self.numbers.remove(currnum) # REMOVE FOR NEW MINIMUM
NUMapp()
The following code is a python sprinting game. It was posted as an answer to my previous post, by #mango You have to tap 'a' and 'd' as fast as you can to run 100 meters. However, there are a few bugs...
1) If you hold down 'a' and 'd' at the same time, the game is completed as fast as possible and defeats the point of the game.
2) Like in my previous post, I would like to incorporate a scoring system into this code, however, due to my level of skill and experience with python, unfortunately, I am unable to do so, and would appreciate and suggestions.
Many Thanks
Previous code:
import msvcrt
import time
high_score = 50
name = "no-one"
while True:
distance = int(0)
print("\n--------------------------------------------------------------")
print('\n\nWelcome to the 100m sprint, tap a and d rapidly to move!')
print('* = 10m')
print("\n**Current record: " + str(high_score) + "s, by: " + name)
print('\nPress enter to start')
input()
print('Ready...')
time.sleep(1)
print('GO!')
start_time = time.time()
while distance < 100:
k1 = msvcrt.getch().decode('ASCII')
if k1 == 'a':
k2 = msvcrt.getch().decode('ASCII')
if k2 == 'd':
distance += 1
if distance == 50:
print("* You're halfway there!")
elif distance % 10 == 0:
print('*')
fin_time = time.time() - start_time
fin_time = round(fin_time,2)
print('Well done you did it in...'+str(fin_time))
if fin_time < high_score:
print("Well done you've got a new high score ")
name = input("Please enter your name : ")
This is the code that I recieved as feedback, I have made a few changes, but I am struggling witht the bugs that I listed before.
1) If you hold down 'a' and 'd' at the same time, the game is completed as fast as possible and defeats the point of the game.
2) Like in my previous post, I would like to incorporate a scoring system into this code, however, due to my level of skill and experience with python, unfortunately, I am unable to do so, and would appreciate and suggestions.
Many Thanks
# these are the modules we'll need
import sys
import tkinter as tk
class SprintGame(object):
# this represents the distance we'll allow our player to run
# NOTE: the distance is in meters
distance = 100
# this represents the stride length of the players legs
# NOTE: basically how far the player can travel in one footstep
stride = 1.5
# this represents the last key the user has pressed
lastKey = ""
# this represents wether or not the race has been completed
completed = False
# this function initiates as soon as the "sprint" variable is defined
def __init__(self):
# create the tk window
self.root = tk.Tk()
# set the tk window size
self.root.geometry('600x400')
# set the tk window title
self.root.title("Sprinting Game")
# bind the keypress event to the self.keypress handler
self.root.bind('<KeyPress>', self.keypress)
# center the window
self.centerWindow(self.root)
# insert the components
self.insertComponents()
# initial distance notice
self.output("{0}m left to go!".format(self.distance))
# start out wonderful game
self.start()
# this function centers the window
def centerWindow(self, window):
window.update_idletasks()
# get the screen width
width = window.winfo_screenwidth()
# get the screen height
height = window.winfo_screenheight()
# get the screen size
size = tuple(int(_) for _ in window.geometry().split('+') [0].split('x'))
# get the screen's dimensions
x = (width / 2) - (size[0] / 2)
y = (height / 2) - (size[1] / 2)
# set the geometry
window.geometry("%dx%d+%d+%d" % (size + (x, y)))
# this function replaces the old text in the textbox with new text
def output(self, text = ""):
self.text.delete('1.0', tk.END)
self.text.insert("end", text)
# this function handles key presses inside the tkinter window
def keypress(self, event):
# get the key and pass it over to self.logic
self.logic(event.char)
# this function handles game logic
def logic(self, key):
# convert key to a lower case string
key = str(key).lower()
# let us know how far we've got left
if key == "l":
self.output("{0}m left to go!".format(self.distance))
# restart the race
if key == "r":
# clear the output box
self.text.delete('1.0', tk.END)
# reset the distance
self.distance = 100
# reset the stride
self.stride = 1.5
# reset the last key
self.lastKey = ""
# set race completed to false
self.completed = False
# output restart notice
self.output("The Race Has Been Restarted.")
# don't bother with logic if race is completed
if self.completed == True:
return False
# check if distance is less than or equal to zero (meaning the race is over)
if self.distance <= 0:
# set the "self.completed" variable to True
self.completed = True
# let us know we've completed the race
self.output("Well done, you've completed the race!")
# return true to stop the rest of the logic
return True
# convert the key to lower case
key = key.lower()
# this is the quit function
if key == "q":
# lights out...
sys.exit(0)
# check if the key is a
if key == "a":
# set the last key to a so that we can decrement the "distance"
# variable if it is pressed next
self.lastKey = "a"
# only bother with "d" keypresses if the last key was "a"
if self.lastKey == "a":
# capture the "d" keypress
if key == "d":
# decrement the "distance" variable
self.distance -= self.stride
# let us know how far into the game we are
self.output("{0}m left to go!".format(self.distance))
# this function inserts the components into the window
def insertComponents(self):
# this component contains all of our output
self.text = tk.Text(self.root, background='#d6d167', foreground='#222222', font=('Comic Sans MS', 12))
# lets insert out text component
self.text.pack()
# this function opens the window and starts the game
def start(self):
self.root.mainloop()
# create a new instance of the game
Game = SprintGame()