I'm building tkinter python calculator. And I want to add comma button. But as we know comma appears in every calculator's window only once. I made a condition that makes that you can type only once but when you type other sign you can type more than one comma sign. How to do if condition that you can type only once in any case.
from tkinter import*
from tkinter.ttk import *
root=Tk()
def show_point():
if e.get()==".":
pass
else:
e.insert(END,".")
e=Entry(root,width=30,justify="right",font=(None,20))
e.grid(row=0,column=0,columnspan=3,ipady=10,sticky=W)
but19 = Button(root,text=".", style='my.TButton',command=show_point)
but19.grid(row=5,column=3,ipadx=10,ipady=15)
root.mainloop()
I think this is what your looking for:
from tkinter import*
from tkinter.ttk import *
root = Tk()
def correct(inp):
if inp == '':
return True
if ' ' in inp:
return False
try:
float(inp)
except ValueError: #catching error because strings cannot be converted to string
return False
else:
return True
reg = root.register(correct) #registering validation
e = Entry(root, width=30, justify="right", font=(None, 20),validate='key', validatecommand=(reg, '%P')) #assigning it while declaring
e.grid(row=0, column=0, columnspan=3, ipady=10, sticky=W)
#but19 = Button(root,text=".", style='my.TButton',command=correct)
# but19.grid(row=5,column=3,ipadx=10,ipady=15)
root.mainloop()
This is just validation, your allowing the user to just enter decimals, anything other than that will not be allowed at all.
Take a look here for more info on validation
Cheers
Try that instead of the if statement
input = e.get()
try:
input.index(".")
except:
e.insert(END, ".")
I think what you need to something called "validation" which Entry widgets support. This will allow you to make sure the character isn't entered more than once (or any other rule you want to enforce), either by clicking on the Button or by manually typing it in. For reference see Adding validation to an Entry widget.
Here's how to do it in the context of what you're trying to do:
from tkinter import*
from tkinter.ttk import *
PERIOD = '.'
root = Tk()
def insert_point():
if e.get().count(PERIOD) < 1: # Allow at most one in entry.
e.insert(END, PERIOD)
def check_okay(new_value):
return new_value.count(PERIOD) < 2 # Only zero or one allowed in entry.
ok_command = root.register(check_okay) # Register the callback function.
e = Entry(root, width=30, justify="right", font=(None, 20),
validate='all', validatecommand=(ok_command, '%P'))
e.grid(row=0, column=0, columnspan=3, ipady=10, sticky=W)
but19 = Button(root, text=PERIOD, style='my.TButton', command=insert_point)
but19.grid(row=5, column=3, ipadx=10, ipady=15)
root.mainloop()
Related
I want to set the answer using the set() method without writing it in the text attribute in the Label and also I want to change the message without displaying the messages over each other.
I want the new message to appear and the one before it to disappear. I tried to use the set() and get() methods but it used to return its default value without using the value in the set() method and I don't know why.
from tkinter import *
from tkinter import messagebox
from PIL import ImageTk,Image
root= Tk()
root.title("Project")
root.geometry('500x600')
root.title('Choose Answer')
var = IntVar()
textt = StringVar()
print(textt.set('Clicked..........'))
def Result():
print(textt.set('You Clicked....................'))
if(var.get() == 1):
print(var.get())
print(textt)
textt.set('You Clicked')
resultText = Label(root, text=textt , fg='white',bg='gray', width=40)
resultText.place(x=100,y=200)
else:
textt.set('You did\'t Click')
resultText = Label(root, text=textt, fg='white',bg='grey', width=40)
resultText.place(x=100,y=200)
checkBox = Checkbutton(root, text='Did you Study Math', variable=var, bg='grey')
checkBox.place(x=50,y=50)
button = Button(root, text='Select', fg='white', bg='grey',font='sans-serif',command=Result)
button.place(x=50,y=100)
root.mainloop()
This should work:
from tkinter import *
root = Tk()
root.title("Project")
root.geometry('500x600')
root.title('Choose Answer')
var = IntVar()
textt = StringVar()
resultText = Label(root, textvariable=textt , fg='white',bg='gray', width=40)
resultText.place(x=100,y=200)
def Result():
print(var.get())
if var.get() == 1:
textt.set('You Clicked')
else:
textt.set('You didn\'t Click')
checkBox = Checkbutton(root, text='Did you Study Math', variable=var, bg='grey')
checkBox.place(x=50,y=50)
button = Button(root, text='Select', fg='white', bg='grey',font='sans-serif',command=Result)
button.place(x=50,y=100)
root.mainloop()
When you create resultText, instead of setting the text argument to textt, you need to set the textvariable argument to text. That way, the text of the variable is automatically changed when you change textt.
I removed all the lines where resultText was recreated and re-placed, and just created it once before defining Result(). Also, I removed from tkinter import messagebox, because you already import it when you call from tkinter import *. Just a note: wildcard imports are discouraged, so try to avoid using them in the future.
I'm trying to create a factorial calculator GUI.
The program works fine, but the problem I'm having is that when there are too many numbers coming in from the output, the screen automatically increases in width. I've tried using tk.Text to create a limit to the size of the textbox and so the text continues to the next row when the columns are filled.
But when I had to input text in to the tk.Text it didn't work since the variable I used is being processed in the function that gets called when the button is pressed. I have tried googling this problem but I couldn't find anything, I did find some people explaining how to use variables that get created/processed inside of a function, but that didn't work so I think I have done something wrong in my code.
Note: I am using lambda to call my function (not sure if this is important or not).
TLDR: Text gets too long when too much information is outputted. tk.Text didn't work for me since I couldn't figure out how to use the variable that is created/processed inside of a function that is only called when the button is pressed.
Here is my entire code: https://pastebin.com/1MkdRjVE
Code for my function:
def start_calc():
output_array = ["placehold"]
start_text.set("Loading...")
i = 1
global e1
global e2
output_array.clear()
string = e1.get()
string2 = e2.get()
integr = int(string)
integr2 = int(string2)
if string == "":
error_message.set("Please enter correct numbers.")
elif string2 == "":
error_message.set("Please enter correct numbers.")
else:
while integr2 >= i:
calc = integr ** i
calcstr = (str(calc))
output_array.append(calcstr)
i += 1
start_text.set("Start!")
output_array_str = (', '.join(output_array))
output_msg.set("Output: " + output_array_str)
print(output_array_str) #This is just so I know if it's working or not in the terminal
Code for my output:
output_msg = tk.StringVar()
output_text = tk.Label(root, textvariable=output_msg, font="Raleway")
output_msg.set("Output: ")
output_text.grid(columnspan=3, column=0, row=14)
I think this is what you are looking for:
#Imports
import tkinter as tk
#Variables
root = tk.Tk()
#Tkinter GUI setup basic
canvas = tk.Canvas(root, width= 400, height=400)
canvas.grid(columnspan=3, rowspan=120)
#Title
text = tk.Label(root, text="Calculating factorials", font="Raleway")
text.grid(column=1, row=1)
#Function
def start_calc():
output_array = ["", ""]
start_text.set("Loading...")
i = 1
global e1
global e2
output_array.clear()
string = e1.get()
string2 = e2.get()
integr = int(string)
integr2 = int(string2)
if string == "":
error_message.set("Please enter correct numbers.")
elif string2 == "":
error_message.set("Please enter correct numbers.")
else:
while integr2 >= i:
calc = integr ** i
calcstr = (str(calc))
output_array.append(calcstr)
i += 1
start_text.set("Start!")
output_array_str = (', '.join(output_array))
# Change the output
output_text.config(state="normal")
# delete last output:
output_text.delete("0.0", "end")
# insert new output:
output_text.insert("end", output_array_str)
output_text.config(state="disabled")
print(output_array_str) #This is just so I know if it's working or not in the terminal
#input
tk.Label(root, text="Number :").grid(row=10)
tk.Label(root, text="Factorial :").grid(row=11)
e1 = tk.Entry(root)
e2 = tk.Entry(root)
e1.grid(row=10, column=1)
e2.grid(row=11, column=1)
#Error message if the input is invalid
error_message = tk.StringVar()
error_text = tk.Label(root, textvariable=error_message, font="Raleway")
error_message.set(" ")
error_text.grid(column=1, row=12)
#Startbutton
start_text = tk.StringVar()
start_btn = tk.Button(root, textvariable=start_text, command=start_calc, font="Raleway", bg="#20bebe", fg="white", height=2, width=15)
start_text.set("Start!")
start_btn.grid(column=1, row=13, pady=10)
#output
output_text = tk.Text(root, height=1, width=20, wrap="none", font="Raleway")
output_text.insert("end", "Output")
output_text.config(state="disabled")
output_text.grid(columnspan=3, column=0, row=14, sticky="news")
#Adding a scrollbar
scrollbar = tk.Scrollbar(root, orient="horizontal", command=output_text.xview)
scrollbar.grid(columnspan=3, column=0, row=15, sticky="news")
output_text.config(xscrollcommand=scrollbar.set)
#disclaimer message
disclaimer_text = tk.Label(root, text="Disclaimer: The factorials will be printed from 1 to the number you entered.")
disclaimer_text.grid(columnspan=3, column=0, row=110)
root.mainloop()
I used a <tkinter.Text> widget with wrap="none", height=1 and width=20 to make the output box. I disabled the entry so that the user can't change the results but can still copy it.
I'm trying to clear a Tkinter Entry Box by using a Tkinter Button. The problem is that my entry includes both 'Integers' aswell as a 'String' and my code wont clear the entry.
I have tried changing the attributes of the clearing method. Right now it's .delete(0, END). But i have tried changing it to .delete("0.0", END) and .delete(0.0, END. But this is just me desperatly trying things out.
enter code here
from tkinter import *
root = Tk()
def validatecontent(entry_text1):
return (entry_text1.isdigit() == bool(entry_text1)) or entry_text1 ==
(".")
def clear_entry():
entry_1.delete(0, END)
vcmd = (root.register(validatecontent), '%S')
entry_text1 = StringVar()
entry_1 = Entry(root, width=11, textvariable=entry_text1,
validate='all', validatecommand=vcmd)
entry_1.pack()
button = Button(root, width=10, text="Clear",
command=clear_entry)
button.pack()
root.mainloop()
If the entry contains Integers alone it gets cleared. But if the entry contains '.' nothing happens, no error code at all.
I'm exploring tkinter as of now and trying to do sample exercises I can think of. What I want is when I enter an input like this:
I've
entered
this
I want to display them that way as well but I'm only getting this:
I'veenteredthis
This is a snippet from my code for this part:
input = textBox.get("1.0", 'end-1c')
logBox.insert(tk.END, input)
I've tried doing these:
input = input.replace("\n", "\n"), logBox.insert(tk.END, input+ "\n")
Please do understand that I'm not well equipped with knowledge in Python as I am still trying to learn the language. Thank you in advance!
Edit: Here is the full code just don't mind the other parts since I'm trying to do something
import sys
import os
import time
import operator
import tkinter as tk
from tkinter import *
def test():
input = textBox.get("1.0", 'end-1c')
# input = input.replace("\n", "\n")
logBox.insert(tk.END, input+ "\n")
window = tk.Tk()
window.geometry("{0}x{1}+0+0".format(window.winfo_screenwidth(),
window.winfo_screenheight()))
window.title("Test")
mainFrame = Frame(window, width=8000, height=8000)
mainFrame.pack(side=TOP)
LabelText = Label(mainFrame, text="Type your text below:", anchor='center', pady=10)
LabelText.pack()
textBox = tk.Text (mainFrame, font=('averdana', 10), height=18, width=180)
textBox.pack()
BTNRun = Button(mainFrame, text="Run", height=1, width=10,
command=test)
BTNRun.pack(padx=10, pady=10)
LogText = Label(mainFrame, text="Console Log", anchor='ne', pady=10)
LogText.pack()
logBox = tk.Listbox(mainFrame, font=('averdana', 10), height=10, width=180)
logBox.pack()
BTNExit = Button(mainFrame, text="Exit", height=1, width=10, command=quit)
BTNExit.pack()
window.mainloop()```
Do not name a variable input. input is a built in method of python. That said you need to split the string at the line breaks so use split() and then input the resulting list.
Change this:
def test():
input = textBox.get("1.0", 'end-1c')
# input = input.replace("\n", "\n")
logBox.insert(tk.END, input+ "\n")
To this:
# had to update this function my original answer had some issues
def test():
my_input = textBox.get("1.0", 'end-1c')
x = my_input.split("\n")
for item in x:
logBox.insert(tk.END, item.strip())
from tkinter import *
def hi(event):
print(txt.get('1.0',END))
txt.delete('1.0',END)
root = Tk()
lbl = Label(root, text="client")
lbl.pack()
txt = Text(root, height=10, width=50)
txt.pack()
txt.bind('<Return>', hi)
btn = Button(root, text="OK")
btn.pack()
root.mainloop()
When I delete Text widget contents, a blank line is left. How to prevent that?
The built-in bindings cause a newline to be inserted when you press the return key. When you create a binding, your bound function is called before the default behavior. Thus, when you press return, your function deletes everything, and then the default action inserts a newline.
If you want to prevent the default action from happening, your function needs to return the string break:
def hi(event):
print(txt.get('1.0',END))
txt.delete('1.0',END)
return "break"
What happens is that the text widget still gets the return you entered. Binding the Enter does not inhibits the propagation of the event after your function ends, unless you alter it to cancel event propagation by returning the break string, like this:
def hi(event):
print(txt.get('1.0',END))
txt.delete('1.0',END)
return 'break'
You must ask tkinter not to propagate that event to other handlers as follows:
from tkinter import *
def hi(event):
print(txt.get('1.0',END))
txt.delete('1.0',END)
return "break"
root = Tk()
lbl = Label(root, text="client")
lbl.pack()
txt = Text(root, height=10, width=50)
txt.pack()
txt.bind('<Return>', hi)
btn = Button(root, text="OK")
btn.pack()
root.mainloop()