The following is the functional issue I'm dealing with. I'm not sure how long 'frank" will be since in the real program he's being created from a line of text. What's happening is 2 things. 1) in this small demonstration, it isn't waiting for the button press and it just prints empty values for what should reflect an entry. 2) When I use this function to print to a csv, I'm getting the entry box instance as a string. I assume that fixing one will fix the other. Thanks.
from Tkinter import *
import ttk
def getThat(top,bottom):
bottom = bottom.get()
print ('%s: "%s"' % (top, bottom))
root = Tk()
root.title("This space intentionally left blank")
root.minsize(900,200)
mainframe = ttk.Frame(root)
mainframe.grid(column = 1, row = 1)
frank = ["beany", "beans", "beens", "not beets"]
x=0
for f in frank:
ttk.Label(mainframe, text=frank[x]).grid(column=x+1, row=2)
addMore = StringVar()
moreBeans = ttk.Entry(mainframe, textvariable=addMore)
moreBeans.grid(column =x+1, row =3)
ttk.Button(mainframe, text = "Do It", command = getThat(frank[x], addMore)).grid(column=1, row=5, pady=5)
x+=1
root.mainloop()
I think
ttk.Button(mainframe, text = "Do It", command = lambda *a: getThat(frank[x], addMore)).grid(column=1, row=5, pady=5)
should fix it
the problem is its being called on creation ... by putting it in a lambda it wont ca;ll until the click
alternatively and probably better form would be to create a function
def OnClick(*args):
return getThat(frank[x], addMore)
ttk.Button(mainframe, text = "Do It", command =OnClick).grid(column=1, row=5, pady=5)
since you are in a loop you might need to do something like
def OnMyClick(x,addMore,*args):
return getThat(frank[x], addMore)
import functools
for x,f in enumerate(frank):
...
my_listener = functools.partial(OnMyClick,x,addMore)
ttk.Button(mainframe, text = "Do It", command = my_listener)
...
In case you were wondering what the fix was, I'll post it here
from Tkinter import *
import ttk
import nltk
import csv
frank = ["beany", "beans", "beens", "not beets"]
letters = ["a","s","d","f"]
newInputs=[]
allTheBeans=[]
def getThat(newInputs):
for inputs in newInputs:
allTheBeans.append((inputs[0], inputs[1].get()))
print allTheBeans
def makeBoxes (root, frank):
for x in range(0, len(frank)):
Label(mainframe, text=frank[x]).grid(column=x+1, row=2)
moreBeans = ttk.Entry(mainframe)
moreBeans.grid(column =x+1, row =3)
moreBeans.insert(0,letters[x])
newInputs.append((frank[x],moreBeans))
return newInputs
def clearItOut(clearList):
del clearList [:]
root = Tk()
root.title("This space intentionally left blank")
root.minsize(900,200)
mainframe = ttk.Frame(root)
mainframe.grid(column = 1, row = 1)
madeBoxes=makeBoxes(mainframe, frank)
ttk.Button(mainframe, text = "Do It", command = lambda *a: getThat(newInputs)).grid(column=1, row=5)
ttk.Button(mainframe, text = "Undo It", command = lambda *a: clearItOut(allTheBeans)).grid(column=1, row=6)
root.mainloop()
I added some other stuff to make sure I was understanding those principals as well.
Related
I'm trying to create a function in tkinter where I can print out what the user writes in a Entry box. I'm able to print out ask_an_entry_get, but when I try to print what_is_answer_entry_get
, I get nothing my empty spaces.
Please find out the problem here. Also I'm using the Entry widget, along with the get() function, to get input from the user.
def answer_quizmaker_score():
print(ask_an_entry_get)
print(what_is_answer_entry_get)
I made a lot of global variables so I could use them all around my code.
global what_is_answer_entry
what_is_answer_entry = Entry(root4)
what_is_answer_entry.pack()
I then used the get() function to retrieve what the user typed.
global what_is_answer_entry_get
what_is_answer_entry_get = what_is_answer_entry.get()
This is the exact process I did for both ask_an_entry_get and what_is_answer_entry_get. However for some reason only ask_an_entry_get is printed, while what_is_answer_entry_get is printing nothing in the console.
from tkinter import *
root = Tk()
root.geometry("500x500")
txt1 = StringVar()
txt2 = StringVar()
def txt_printer():
print(txt1.get())
print(txt2.get())
x = Entry(root, textvariable=txt1, width=20)
x.place(x=0, y=0)
y = Entry(root, textvariable=txt2, width=20)
y.place(x=0, y=50)
btn_print = Button(root, text="print", command=txt_printer)
btn_print.place(x=0, y=100)
# Or if you want to show the txt on window then:
def txt_on_window():
lb1 = Label(root, text=txt1.get())
lb1.place(x=0, y=200)
lb2 = Label(root, text=txt2.get())
lb2.place(x=0, y=235)
btn_print_on_window = Button(root, text="print on screen", command=txt_on_window)
btn_print_on_window.place(x=0, y=150)
root.mainloop()
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())
I'm coding a text editor as part of my learning Python. I can search the text in Text Widget from an Entry Widget with this piece of code bellow, but need how to make a search from the position of cursor and select if I want to do it from that position to up or down, I don't know how to do that.
I could add a Radiobutton for (up option) and other for (down option) just like Notepad in Windows, but I need the code to do that. Does anyone know?
And my code doesn't differentiate between upper case and lower case, I don´t know why.
from tkinter import *
from tkinter import messagebox as MessageBox
search_list = list()
s = ""
def reset_list():
if s != entry_widget_name.get():
search_list.clear()
text_widget_name.tag_remove(SEL, 1.0,"end-1c")
def search_words():
reset_list()
global search_list
global s
text_widget_name.focus_set()
s = entry_widget_name.get()
if s:
if search_list == []:
idx = "1.0"
else:
idx = search_list[-1]
idx = text_widget_name.search(s, idx, nocase=1, stopindex=END)
lastidx = '%s+%dc' % (idx, len(s))
try:
text_widget_name.tag_remove(SEL, 1.0,lastidx)
except:
pass
try:
text_widget_name.tag_add(SEL, idx, lastidx)
counter_list = []
counter_list = str(idx).split('.')
text_widget_name.mark_set("insert", "%d.%d" % (float(int(counter_list[0])), float(int(counter_list[1]))))
text_widget_name.see(float(int(counter_list[0])))
search_list.append(lastidx)
except:
MessageBox.showinfo("Search complete","No further matches")
search_list.clear()
text_widget_name.tag_remove(SEL, 1.0,"end-1c")
root = Tk()
root.geometry("540x460")
lbl_frame_entry = LabelFrame(root, text="Enter the text to search", padx=5, pady=5)
lbl_frame_entry.pack(padx=10, pady=5, fill="both")
entry_widget_name = Entry(lbl_frame_entry, width=50, justify = "left")
entry_widget_name.pack(fill="both")
lbl_frame_text = LabelFrame(root, text="Enter the text here", padx=5, pady=5, height=260)
lbl_frame_text.pack(padx=10, pady=5, fill="both", expand=True)
text_widget_name = Text(lbl_frame_text)
text_widget_name.pack(fill="both", expand=True)
scrollbar = Scrollbar(text_widget_name, orient="vertical", command=text_widget_name.yview, cursor="arrow")
scrollbar.pack(fill="y", side="right")
text_widget_name.config(yscrollcommand=scrollbar.set)
button_name = Button(root, text="Search", command=search_words, padx=5, pady=5)
button_name.pack()
root.mainloop()
First of all, your search is not case sensitive because you used the option nocase=1.
Secondly, if you want to do a up or down search, there are the backwards and forwards options (I found the documentation here). When you do a backward search, you also need to change the way you move the insert cursor too and the stopindex. Here is an example in which the text in the entry is searched in the text starting from the current insert position and moving upward / downward depending on the selected radiobutton:
from tkinter import *
from tkinter import messagebox as MessageBox
def search():
pattern = e.get()
if search_dir.get() == 'forwards':
res = txt.search(pattern, 'insert', forwards=True, stopindex='end')
else:
res = txt.search(pattern, 'insert', backwards=True, stopindex='1.0')
txt.tag_remove('sel', '1.0', 'end')
try:
txt.tag_add('sel', res, '%s+%ic' % (res, len(pattern)))
if search_dir.get() == 'forwards':
txt.mark_set('insert', '%s+%ic' % (res, len(pattern)))
else:
txt.mark_set('insert', '%s-1c' % (res))
except:
MessageBox.showinfo("Search complete","No further matches")
root = Tk()
txt = Text(root)
txt.pack(fill='both',expand=True)
e = Entry(root)
e.pack(fill='x')
search_dir = StringVar(root, 'forwards')
Radiobutton(root, text='▲', value='backwards', variable=search_dir).pack()
Radiobutton(root, text='▼', value='forwards', variable=search_dir).pack()
Button(root, text='Search', command=search).pack()
root.mainloop()
from Tkinter import *
root = Tk()
root.geometry("230x100")
L1 = Label(root, text="Login page", bg = "blue", fg = "white")
L1.pack(fill = X, ipadx = 5, ipady = 5)
V = StringVar(root, value='Enter username here')
E1 = Entry(root, textvariable=V)
E1.pack(side = LEFT, padx = 5, pady = 5)
def Login():
username = V.get()
print "Username is '" + username + "'"
B1 = Button(root, text ="Login" , command = Login)
B1.pack(side = RIGHT, fill = X, pady=5)
mainloop()
I have been trying to get the value of 'username' in the function Login() to use it on another python program.
I have tried setting it as global variable and changing its scope but I am not getting anything.
I need to use the value of 'Username' outside the function Login(). Please provide your insights.
Think about scope for a moment. When your program ends, all memory (meaning variables, objects, etc.) are released. The only 2 ways I can think of to pass something from one program to another is:
1) Write the username value to a file which the next program can read as part of its startup.
2) Have a third "controller" or "launcher" program that runs the program above, takes a return value from that program, then passes that value as a parameter to the next program.
But in any case, you will have to save that value past the scope of the program above.
1) Create a python file say 'global_vars.py' and add this line in it.
#global_vars.py
global_V = ''
2) Import this global_vars.py wherever you want set the variable as below:
#main.py
from Tkinter import *
import global_vars
root = Tk()
root.geometry("230x100")
L1 = Label(root, text="Login page", bg = "blue", fg = "white")
L1.pack(fill = X, ipadx = 5, ipady = 5)
V = StringVar(root, value='Enter username here')
#Set the global variable
global_vars.global_V = V
E1 = Entry(root, textvariable=V)
E1.pack(side = LEFT, padx = 5, pady = 5)
3) Consider you want to use this value in python program present in file "test.py". Just import global_vars.py and use this variable
#test.py
import global_vars.py
def printUserName():
print "Username is -", global_vars.global_V
If you have to python files, one called main.py that contains your main program (I assumed it was a GUI program) and the login.py file that contains the login program.
main.py
from tkinter import Tk, Label
from login import LoginGUI
class mainGUI(Tk):
def __init__(self):
Tk.__init__(self)
Label(self, text="You need to login first",
bg="blue", fg="white").pack(fill="x", ipadx=5, ipady=5)
# open login dialog
login = LoginGUI(self)
# wait for the user to log in
self.wait_window(login)
username = login.getLogin()
Label(self,
text="Your username is " + username).pack(fill="x", ipadx=5, ipady=5)
self.mainloop()
if __name__ == '__main__':
mainGUI()
login.py
from tkinter import Toplevel, StringVar, Entry, Button, Label
from tkinter import Toplevel, StringVar, Entry, Button, Label
class LoginGUI(Toplevel):
def __init__(self, master):
Toplevel.__init__(self, master)
self.transient(master)
self.geometry("230x100")
Label(self, text="Login page",
bg="blue", fg="white").pack(fill="x", ipadx=5, ipady=5)
self.username = ""
self.usernameVar = StringVar(self, value='Enter username here')
E1 = Entry(self,
textvariable=self.usernameVar)
E1.pack(side="left", padx=5, pady=5)
Button(self, text="Login",
command=self.Login).pack(side="right", fill="x", pady=5)
E1.focus_set()
def Login(self):
self.username = self.usernameVar.get()
self.destroy()
def getLogin(self):
return self.username
If your main program have no GUI, replace Toplevel by Tk in login.py and add a self.mainloop at the end of the __init__ method.
You can launch the other program using subprocess, or refactor the other program so the username can be passed as the parameter of a function, and import that program as module of your main program.
I know that there are a lot of questions dealing with tkinter but I have looked at a bunch of them and none of them seem to help me.
import tkinter
class Calculator:
def __init__(self):
window = tkinter.Tk()
window.geometry("200x300")
window.title("Calculator")
lbl = tkinter.Label(window, text="placeholder", bg="blue", textvariable="labelText")
lbl.grid(row=0, column=0, columnspan=3)
self.firstNumArray = []
self.secondNumArray = []
self.operation = ""
self.currentNum = "first"
def appendNumber(self, number):
print("Appending Number")
if self.currentNum == "first":
self.firstNumArray.append(number)
print("".join(str(x) for x in self.firstNumArray))
lbl.config(text="".join(str(x) for x in self.firstNumArray))
window.update()
else:
self.secondNumArray.append(number)
for i in range(1,4):
string = "Creating button at ({0},{1})".format(0,i)
print(string)
button = tkinter.Button(text=i, command=lambda: appendNumber(self, i))
button.grid(row=1, column=i-1)
for i in range(1,4):
string = "Creating button at ({0},{1})".format(1,i)
print(string)
button = tkinter.Button(text=i+3, command=lambda: appendNumber(self, i+3))
button.grid(row=2, column=i-1)
for i in range(1,4):
string = "Creating button at ({0},{1})".format(2,i)
print(string)
button = tkinter.Button(text=i+6, command=lambda: appendNumber(self, i+6))
button.grid(row=3, column=i-1)
div = tkinter.Button(text="/")
mult = tkinter.Button(text="*")
add = tkinter.Button(text="+")
sub = tkinter.Button(text="-")
add.grid(row=1, column=3)
sub.grid(row=2, column=3)
mult.grid(row=3, column=3)
div.grid(row=4, column=3)
button = tkinter.Button(text="0")
button.grid(row=4, column=1)
window.mainloop()
calc = Calculator()
When I launch the program the window opens. When I click on a button the text in the label does not change. I have tried using a StringVar as the textvariable and then calling the set() function, but that did not work either. I think it has to do with the scope of the function. I had to place the appendNumber() function inside the __init__() because for some reason self.lbl = tkinter.Label() makes nothing pop up at all.
There are a few problems with your code.
labelText should, of course, be a StringVar and not a string...
labelText = tkinter.StringVar()
lbl = tkinter.Label(window, bg="blue", textvariable=labelText)
lbl.grid(row=0, column=0, columnspan=3)
Now you can use labelText.set to update the text. Also, no need for self parameter or window.update
def appendNumber(number):
if self.currentNum == "first":
self.firstNumArray.append(number)
labelText.set("".join(str(x) for x in self.firstNumArray))
else:
self.secondNumArray.append(number)
You can put all the buttons in one loop using // (integer (!) division) and % (modulo) operations. Also, be aware that the variable in the lambda is evaluated when the function is called, not when it is declared, i.e. all the lambdas will use the last value of i (9 in this case) -- see e.g. here. As a remedy, use lambda n=i+1: appendNumber(n).
for i in range(9):
btn = tkinter.Button(text=i+1, command=lambda n=i+1: appendNumber(n))
btn.grid(row=i//3+1, column=i%3)
Not really a problem, but since you don't need a reference to those buttons, you can make your code a bit more compact (same for the others):
tkinter.Button(text="/").grid(row=1, column=3)