How to get value from a text field in another module? - python

I've written a simple program with a tkinter GUI. The entire code is in one big module and I'd like to split it into two or three modules to separate the logic from the GUI.
This is the example code:
main.py:
import gui
inst1 = gui.guitest()
gui.py:
import tkinter, defs
class guitest:
def __init__(self):
win1 = tkinter.Tk()
self.field1 = tkinter.Text(win1)
self.field1.grid(column = 0, row = 0)
self.but1 = tkinter.Button(win1, text='click',
command=defs.getVar)
self.but1.grid(column = 1, row = 0)
win1.mainloop()
defs.py:
def getVar():
captured = str(field1.get(1.0))
I can't get getVar to work; I'd like it to get the value from the Text field, but after trying different solutions all I get are Name or Attribute Errors.
Is there any possibility to make it work that way? Or maybe my idea is completely wrong? If it is, then please let me know how to do it. I wonder if there are more problems with this code.

Alright, let's start from the beginning, here's a working example of your code:
import tkinter
class guitest:
def __init__(self):
win1 = tkinter.Tk()
self.field1 = tkinter.Text(win1)
self.field1.grid(column=0, row=0)
self.but1 = tkinter.Button(win1, text='click', command=self.getVar)
self.but1.grid(column=1, row=0)
win1.mainloop()
def getVar(self):
captured = str(self.field1.get("1.0", tkinter.END))
print captured
inst1 = guitest()
Now, before breaking down that piece of code, you should ask yourself if the reason you want to is strong enough. In case your answer is affirmative (think it twice) one possible way to do it would be this:
# main.py
import gui
inst1 = gui.guitest()
# gui.py
import tkinter
import defs
class guitest:
def __init__(self):
win1 = tkinter.Tk()
self.field1 = tkinter.Text(win1)
self.field1.grid(column=0, row=0)
self.but1 = tkinter.Button(win1, text='click', command=self.getVar)
self.but1.grid(column=1, row=0)
win1.mainloop()
def getVar(self):
defs.getVar(self)
# defs.py
import tkinter
def getVar(guitest_inst):
captured = str(guitest_inst.field1.get("1.0", tkinter.END))
print captured
But again, think twice before breaking down widgets like this... just saying :)

Related

How to display input and output in same GUI for tkinter in Python

I am trying to make the user input a string for my implemented DFA diagram, and I want the input box to be displayed along with its output right under it in the same GUI box. I'm only including one of my functions to show how I used tkinter's messagebox to display the output.
import tkinter as tk
from tkinter import simpledialog
from tkinter import messagebox
import tkinter
def q3(s, i) :
if (i == len(s)) :
tkinter.messagebox.showinfo('Answer',"REJECTED")
return;
if (s[i] == 'a') :
q3(s, i + 1);
elif (s[i] == 'b'):
q3(s, i + 1);
root = tk.Tk()
root.withdraw()
user_inp = simpledialog.askstring(title="DFA", prompt="Enter a string within the alphabet {a,b}* Suffix must be bb")
This code works to display the results correctly, like this.
AKA, when the user inputs the string and presses OK, it opens another GUI to display the results. Please help me so that I can have a GUI that displays both in the same box. It's even harder because all of my DFA functions (I have one for q0, q1, q2, and q3) have different results for the output as rejected/accepted. I'm not sure if I have to create a variable for the each of them. (The only one that is accepted is q2). I'm also not sure if I need to use any Labels. In your answer, if there's imports I must include, please include that as well.
Well I tried to understand what you really want, but couldnt get it, so I put together what I feel that you might want, with an example:
from tkinter import *
class Custombox:
def __init__(self, title, text):
self.title = title
self.text = text
def store():
self.new = self.entry.get() #storing data from entry box onto variable
if self.new == 'Hello World': #checking
a.change('ACCEPTED') #changing text
else:
a.change('REJECTED') #else, changing text
self.win = Toplevel()
self.win.title(self.title)
# self.win.geometry('400x150')
self.win.wm_attributes('-topmost', True)
self.label = Label(self.win, text=self.text)
self.label.grid(row=0, column=0, pady=(20, 10),columnspan=3,sticky='w',padx=10)
self.l = Label(self.win)
self.entry = Entry(self.win, width=50)
self.entry.grid(row=1, column=1,columnspan=2,padx=10)
self.b1 = Button(self.win, text='Ok', width=10,command=store)
self.b1.grid(row=3, column=1,pady=10)
self.b2 = Button(self.win, text='Cancel', width=10,command=self.win.destroy)
self.b2.grid(row=3, column=2,pady=10)
def __str__(self):
return str(self.new)
def change(self,ran_text):
self.l.config(text=ran_text,font=(0,12))
self.l.grid(row=2,column=1,columnspan=3,sticky='nsew',pady=5)
root = Tk()
root.withdraw()
a = Custombox('Custom box', 'Enter a string within the alphabet {a,b}*. Suffix must be bb.')
root.mainloop()
Over here im creating a window using basic tkinter properties and placements and all you have to understand is that store() inside that class is similar to your q3() as I couldnt understand what was going on there, I just made my own function. So you will have to replace store() with what works for you, but do not change the self.new = self.entry.get(). Yes this might seem a bit shady, but it was the quickest i could do, because im a beginner as well.
Anyways here, a has the value of whatever you type into the entry widget, BUT while using a, make sure to use str(a) or you wont get correct results as type(a) returns <class '__main__.Custombox'>. Do let me know if you face any difficulty in the implementation of this class. I know there are mistakes here, feel free to edit those mistakes out or let me know.

getting information from Entry

my name is Rod. I recently started programming with OOP and it's not yet quite clear to me. I want to make my Button get information from my four entries but i don't know how to say to the program to get it from the four of them at the same time. I know i have to use the get() method but i don't understand how to insert it in the class so it will recognize my four Entries. Thanks!
from tkinter import *
from tkinter import ttk
class Application(Frame):
def __init__(self):
Frame.__init__(self)
self.grid()
def createButton(self,b_text,b_command,r,c):
self.newButton = Button(self, text=b_text,command=b_command)
self.newButton.grid(padx=20, pady=10, row=r,column=c)
def createEntry(self,px,r,c):
text = StringVar()
self.newEntry = Entry(self,width=8,textvariable=text)
self.newEntry.grid(padx=px, pady=10,row=r,column=c)
def printEntryData():
#code here
app = Application()
entry1 = app.createEntry(20,0,0)
entry2 = app.createEntry(20,0,1)
entry3 = app.createEntry(20,0,2)
entry4 = app.createEntry(20,0,3)
app.createButton("add",printEntryData,1,6)
app.mainloop()
Every time you make an entry you overwrite the previous value of text. All those previous Entry boxes now are orphans: there's no way to access them to get the information out. (they would have been inaccessible anyway since they are local variables).
Instead, you could add the new StringVars to a container like a list, so that you have access to all of them.
from tkinter import *
from tkinter import ttk
class Application(Frame):
def __init__(self):
Frame.__init__(self)
self.entry_list = []
self.grid()
def createButton(self,b_text,b_command,r,c):
self.newButton = Button(self, text=b_text,command=b_command)
self.newButton.grid(padx=20, pady=10, row=r,column=c)
def createEntry(self,px,r,c):
text = StringVar()
self.newEntry = Entry(self,width=8,textvariable=text)
self.newEntry.grid(padx=px, pady=10,row=r,column=c)
self.entry_list.append(text)
def printEntryData():
for entry in app.entry_list:
print(entry.get())
app = Application()
app.createEntry(20,0,0)
app.createEntry(20,0,1)
app.createEntry(20,0,2)
app.createEntry(20,0,3)
app.createButton("add",printEntryData,1,6)
app.mainloop()

Label variables for exchange rate calculator [duplicate]

I am having trouble with using a key binding to change the value of a label or any parameter.
This is my code:
from tkinter import*
class MyGUI:
def __init__(self):
self.__mainWindow = Tk()
#self.fram1 = Frame(self.__mainWindow)
self.labelText = 'Enter amount to deposit'
self.depositLabel = Label(self.__mainWindow, text = self.labelText)
self.depositEntry = Entry(self.__mainWindow, width = 10)
self.depositEntry.bind('<Return>', self.depositCallBack)
self.depositLabel.pack()
self.depositEntry.pack()
mainloop()
def depositCallBack(self,event):
self.labelText = 'change the value'
print(self.labelText)
myGUI = MyGUI()
When I run this, I click the entrybox and hit enter, hoping that the label will change value to 'change the value'. However, while it does print that text, the label remains unchanged.
From looking at other questions on similar problems and issues, I have figured how to work with some of this outside a class, but I'm having some difficulties with doing it inside a class.
self.labelText = 'change the value'
The above sentence makes labelText change the value, but not change depositLabel's text.
To change depositLabel's text, use one of following setences:
self.depositLabel['text'] = 'change the value'
OR
self.depositLabel.config(text='change the value')
You can also define a textvariable when creating the Label, and change the textvariable to update the text in the label.
Here's an example:
labelText = StringVar()
depositLabel = Label(self, textvariable=labelText)
depositLabel.grid()
def updateDepositLabel(txt) # you may have to use *args in some cases
labelText.set(txt)
There's no need to update the text in depositLabel manually. Tk does that for you.
Use the config method to change the value of the label:
top = Tk()
l = Label(top)
l.pack()
l.config(text = "Hello World", width = "50")
Here is another one, I think. Just for reference.
Let's set a variable to be an instantance of class StringVar
If you program Tk using the Tcl language, you can ask the system to let you know when a variable is changed. The Tk toolkit can use this feature, called tracing, to update certain widgets when an associated variable is modified.
There’s no way to track changes to Python variables, but Tkinter
allows you to create variable wrappers that can be used wherever Tk
can use a traced Tcl variable.
text = StringVar()
self.depositLabel = Label(self.__mainWindow, text = self.labelText, textvariable = text)
# ^^^^^^^^^^^^^^^^^^^
def depositCallBack(self,event):
text.set('change the value')
I made a small tkinter application which is sets the label after button clicked
#!/usr/bin/env python
from Tkinter import *
from tkFileDialog import askopenfilename
from tkFileDialog import askdirectory
class Application:
def __init__(self, master):
frame = Frame(master,width=200,height=200)
frame.pack()
self.log_file_btn = Button(frame, text="Select Log File", command=self.selectLogFile,width=25).grid(row=0)
self.image_folder_btn = Button(frame, text="Select Image Folder", command=self.selectImageFile,width=25).grid(row=1)
self.quite_button = Button(frame, text="QUIT", fg="red", command=frame.quit,width=25).grid(row=5)
self.logFilePath =StringVar()
self.imageFilePath = StringVar()
self.labelFolder = Label(frame,textvariable=self.logFilePath).grid(row=0,column=1)
self.labelImageFile = Label(frame,textvariable = self.imageFilePath).grid(row = 1,column=1)
def selectLogFile(self):
filename = askopenfilename()
self.logFilePath.set(filename)
def selectImageFile(self):
imageFolder = askdirectory()
self.imageFilePath.set(imageFolder)
root = Tk()
root.title("Geo Tagging")
root.geometry("600x100")
app = Application(root)
root.mainloop()
There are many ways to tackle a problem like this. There are many ways to do this. I'm going to give you the most simple solution to this question I know. When changing the text of a label or any kind of wiget really. I would do it like this.
Name_Of_Label["text"] = "Your New Text"
So when I apply this knowledge to your code. It would look something like this.
from tkinter import*
class MyGUI:
def __init__(self):
self.__mainWindow = Tk()
#self.fram1 = Frame(self.__mainWindow)
self.labelText = 'Enter amount to deposit'
self.depositLabel = Label(self.__mainWindow, text = self.labelText)
self.depositEntry = Entry(self.__mainWindow, width = 10)
self.depositEntry.bind('<Return>', self.depositCallBack)
self.depositLabel.pack()
self.depositEntry.pack()
mainloop()
def depositCallBack(self,event):
self.labelText["text"] = 'change the value'
print(self.labelText)
myGUI = MyGUI()
If this helps please let me know!

Destroying widgets from a different subroutine in tkinter

So I'm using .place to set the location of my widgets at the moment.
def printresults():
SClabelspare=Label(cwindow, text ="Please enter the Customers ID Number:" ).place(x=10,y=560)
I'm looking to call another subroutine that will destroy these widgets. I believe there is something called .destroy() or .place_destroy? I'm not quite sure how these would work though and I have tried to create one that looked like this:
def destroy_widgets():
SClabelspare.destroy()
but it just produces an error code that says NameError: global name 'SClabelspare' is not defined
Any help will be appreciated!
First, place() returns None so SClabelspare==None not a Tkinter ID. Second it is local, so is garbage collected when the function exits. You have to keep a reference to the object which can be done in many ways. A Python tutorial would be a good idea to get the basics before you go further https://wiki.python.org/moin/BeginnersGuide/Programmers Also, programming a Tkinter app without using class structures is a frustrating experience, unless it is something very simple. Otherwise you get errors like yours and have to spend much time and effort trying to overcome them. This is an example that I already have and is meant to to give a general idea of the process.
from Tkinter import *
from functools import partial
class ButtonsTest:
def __init__(self):
self.top = Tk()
self.top.title("Click a button to remove")
Label(self.top, text="Click a button to remove it",
bg="lightyellow").grid(row=0)
self.top_frame = Frame(self.top, width =400, height=400)
self.button_dic = {}
self.buttons()
self.top_frame.grid(row=1, column=0)
Button(self.top_frame, text='Exit', bg="orange",
command=self.top.quit).grid(row=10,column=0, columnspan=5)
self.top.mainloop()
##-------------------------------------------------------------------
def buttons(self):
b_row=1
b_col=0
for but_num in range(1, 11):
## create a button and send the button's number to
## self.cb_handler when the button is pressed
b = Button(self.top_frame, text = str(but_num),
command=partial(self.cb_handler, but_num))
b.grid(row=b_row, column=b_col)
## dictionary key=button number --> button instance
self.button_dic[but_num] = b
b_col += 1
if b_col > 4:
b_col = 0
b_row += 1
##----------------------------------------------------------------
def cb_handler( self, cb_number ):
print "\ncb_handler", cb_number
self.button_dic[cb_number].grid_forget()
##===================================================================
BT=ButtonsTest()
Or, if this is supposed to be very simple, without a lot of hard-to-manage global variables, and if class structures would only introduce needless complexity, you might try something like this (it worked for me in the python3 interpreter from the command line):
from tkinter import *
root = Tk()
def victim():
global vic
vic = Toplevel(root)
vicblab = Label(vic, text='Please bump me off')
vicblab.grid()
def bumper():
global vic
bump = Toplevel(root)
bumpbutt = Button(bump, text='Bump off', command=vic.destroy)
bumpbutt.grid()
victim()
bumper()

Button Command with class in Python

I'm trying to get this right but so far no luck. Would appreciate it if someone can help me with it.
import tkinter
class MyGUI:
def __init__(self):
self.main_window = tkinter.Tk()
self.button1 = tkinter.Button(self.main_window,text='Average',command=self.average)
self.button1.pack()
tkinter.mainloop()
def average(self):
self.mini_window = tkinter.Tk()
self.avg_mess = tkinter.Label(self.mini_window,text='Results:')
self.avg_result_var = tkinter.StringVar()
self.avg_result_display = tkinter.Label(self.mini_window,textvariable=self.avg_result_var)
self.avg_mess.pack()
self.avg_result_display.pack()
self.button2 = tkinter.Button(self.mini_window,text='Calculate',command=self.avg_calc)
self.button2.pack()
def avg_calc(self):
self.avg_result = (100+300+80)/3
self.avg_result_var.set(self.avg_result)
gui = MyGUI()
The problem occurs when the Calculate button is clicked but the avg_result_var does not change its value. And hence the avg.result_display remains blank. I suspect there is something wrong with the function call when the button is pressed. I'm using Python 3.x. Thanks.
You're almost doing it correctly, but there are a couple of problems
First, the result never changes because you use the same numbers each time you do a calculation. The result is always the same so it appears that it is not changing.
The second problem is that you're creating two instances of Tk. Tkinter isn't designed to work like that, and it causes problems such as the one you are observing. If you need additional pop-up windows, use Toplevel rather than Tk.
Here's a modified version of your program, though I've added a random number in the computation so you can see it change each time.
import Tkinter as tkinter
import random
class MyGUI:
def __init__(self):
self.main_window = tkinter.Tk()
self.button1 = tkinter.Button(self.main_window,text='Average',command=self.average)
self.button1.pack()
tkinter.mainloop()
def average(self):
self.mini_window = tkinter.Toplevel()
self.avg_mess = tkinter.Label(self.mini_window,text='Results:')
self.avg_result_var = tkinter.StringVar()
self.avg_result_display = tkinter.Label(self.mini_window,textvariable=self.avg_result_var)
self.avg_mess.pack(fill="both")
self.avg_result_display.pack()
self.button2 = tkinter.Button(self.mini_window,text='Calculate',command=self.avg_calc)
self.button2.pack()
def avg_calc(self):
x = random.randint(100,200)
self.avg_result = (100+300+x)/3
print "result:", self.avg_result
self.avg_result_var.set(self.avg_result)
gui = MyGUI()

Categories