How to call a function from the top level module function? - python

I'm Python noob and I want to develop a windows app with multiprocessing support. I have found an example here: http://zetcode.com/articles/tkinterlongruntask/. But now my problem is that, I can't update the scrollable text from the generatePI method which is a top level module function.
Could any of you guys give me a solution or point me to the right direction?
The complete code:
from tkinter import (Tk, BOTH, Text, E, W, S, N, END,
NORMAL, DISABLED, StringVar)
from tkinter.ttk import Frame, Label, Button, Progressbar, Entry
from tkinter import scrolledtext
from multiprocessing import Process, Manager, Queue
from queue import Empty
from decimal import Decimal, getcontext
DELAY1 = 80
DELAY2 = 20
# Queue must be global
q = Queue()
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent, name="frame")
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Pi computation")
self.pack(fill=BOTH, expand=True)
self.grid_columnconfigure(4, weight=1)
self.grid_rowconfigure(3, weight=1)
lbl1 = Label(self, text="Digits:")
lbl1.grid(row=0, column=0, sticky=E, padx=10, pady=10)
self.ent1 = Entry(self, width=10)
self.ent1.insert(END, "4000")
self.ent1.grid(row=0, column=1, sticky=W)
lbl2 = Label(self, text="Accuracy:")
lbl2.grid(row=0, column=2, sticky=E, padx=10, pady=10)
self.ent2 = Entry(self, width=10)
self.ent2.insert(END, "100")
self.ent2.grid(row=0, column=3, sticky=W)
self.startBtn = Button(self, text="Start",
command=self.onStart)
self.startBtn.grid(row=1, column=0, padx=10, pady=5, sticky=W)
self.pbar = Progressbar(self, mode='indeterminate')
self.pbar.grid(row=1, column=1, columnspan=3, sticky=W+E)
self.txt = scrolledtext.ScrolledText(self)
self.txt.grid(row=2, column=0, rowspan=4, padx=10, pady=5,
columnspan=5, sticky=E+W+S+N)
def onStart(self):
self.startBtn.config(state=DISABLED)
self.txt.delete("1.0", END)
digits = int(self.ent1.get())
accuracy = int(self.ent2.get())
self.p1 = Process(target=generatePi, args=(q, digits, accuracy))
self.p1.start()
self.pbar.start(DELAY2)
self.after(DELAY1, self.onGetValue)
def onGetValue(self):
if (self.p1.is_alive()):
self.after(DELAY1, self.onGetValue)
return
else:
try:
self.txt.insert('end', q.get(0))
self.txt.insert('end', "\n")
self.pbar.stop()
self.startBtn.config(state=NORMAL)
except Empty:
print("queue is empty")
# Generate function must be a top-level module funtion
def generatePi(q, digs, acc):
getcontext().prec = digs
pi = Decimal(0)
k = 0
n = acc
while k < n:
pi += (Decimal(1)/(16**k))*((Decimal(4)/(8*k+1)) - \
(Decimal(2)/(8*k+4)) - (Decimal(1)/(8*k+5))- \
(Decimal(1)/(8*k+6)))
k += 1
q.put(pi)
def main():
root = Tk()
root.geometry("400x350+300+300")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
PS: credit to zetcode.com

Related

How can I remove an object from a list using its method?

Here's my unfinished program:
I made a class for a Frame() with input fields and a button.
I then have a + button which creates new instances of this class by adding them to an empty list. Objects .pack() themselves upon initialization, so they appear in the window.
Edit: added working code you can try:
import tkinter as tk
from tkinter import ttk
import tkinter.font as tkFont
class JobItem:
def __init__(self, parent):
self.frame = tk.Frame(parent, bd=2, relief=tk.GROOVE)
self.frame.pack(side=tk.TOP, fill=tk.X, padx=2, pady=2)
self.nameLabel = ttk.Label(self.frame, text="Description:")
self.nameLabel.grid(column=0, row=0, sticky=tk.W, padx=5, pady=5)
self.nameEntry = ttk.Entry(self.frame)
self.nameEntry.grid(column=1, row=0, sticky=tk.W, padx=5, pady=5)
self.jobTypeLabel = ttk.Label(self.frame, text="Job type:")
self.jobTypeLabel.grid(column=3, row=0, sticky=tk.W, padx=5, pady=5)
self.selected_job = tk.StringVar()
self.job_type_cb = ttk.Combobox(self.frame, textvariable=self.selected_job, state='readonly')
self.job_type_cb['values'] = ['Still', 'Animation', 'Model production']
self.job_type_cb.current(0)
self.job_type_cb.grid(column=4, row=0, sticky=tk.W, padx=5, pady=5)
self.x = ttk.Button(self.frame, text="X", command=self.delete_itself)
self.x.grid(column=5, row=0, sticky=tk.E, padx=5, pady=5)
# v v v This method is what I don't know how to do properly v v v
def delete_itself():
pass
job_items = list()
def add_jobItem():
job_items.insert(len(job_items), JobItem(itemListContainer))
root=tk.Tk()
root.title('Estimate generator')
root.geometry('800x500')
headerFrame = tk.Frame(root, height=100)
headerFrame.pack(side=tk.TOP, fill=tk.X)
jobNameLabel = ttk.Label(headerFrame, text="Project name: ")
jobNameLabel.pack(side=tk.LEFT)
jobNameEntry = ttk.Entry(headerFrame)
jobNameEntry.pack(side=tk.LEFT, expand=True, fill=tk.X)
buttonFont = tkFont.Font(weight="bold")
plusButton = tk.Button(headerFrame, text='+', command=add_jobItem, font=buttonFont, fg='#656565', height=0, width=10)
plusButton.pack(side=tk.RIGHT, padx=(100,2), pady=2)
# Item List Frame
itemListContainer = tk.Frame(root)
itemListContainer.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
root.mainloop()
How can I make X button on a given instance remove not only the packed elements, but also the object from job_items list? How would we know what index does it occupy in the list? Or maybe I should take a different approach?
I would suggest to pass a function to JobItem which will be executed inside delete_itself:
class JobItem:
def __init__(self, parent, on_delete=None):
self.on_delete = on_delete
...
def delete_itself(self):
# destroy the frame
self.frame.destroy()
# call self.on_delete if it is not None
if self.on_delete:
# pass JobItem itself to self.on_delete
self.on_delete(self)
job_items = list()
def del_jobItem(item):
# remove the job item from job_items list
job_items.remove(item)
def add_jobItem():
# can use job_items.append(...) instead
#job_items.insert(len(job_items), JobItem(itemListContainer, del_jobItem))
job_items.append(JobItem(itemListContainer, del_jobItem))
...

Is It possible to create multiple form fields in tkinter & python and then submit it to a out to an output textbox in a table column format

So my problem is that I want to create multiple entry fields like over 30, but every time I reformat it using .pack or .grid it keeps throwing off the formatting. is there a way to fit nearly 30 entry boxes on one window without using anything like SQLite? As we can see from this code, we have 4 fields, how would you go on with shrinking the boxes to put in more entry fields like over 30.
Secondly, I want to output all the typed data entry fields to the Listbox is there a way to add a table column to the list box to show a breakdown of each entry field.
The third is it possible to move the Listbox to another tab on the same window to show all entry fields that were typed in, if so how would you do so.
Here is my current code so far
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from datetime import *
# Import Packages
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter.scrolledtext import *
import tkinter.filedialog
from tkcalendar import Calendar, DateEntry
from tkinter import messagebox
from tkintertable import TableCanvas, TableModel
from tkinter import ttk
# Database
#import sqlite3
import csv
window = Tk()
window.title("TESTTEST")
window.geometry("750x450")
window.config(background='black')
#style = ttk.Style(window)
#style.configure('lefttab.TNotebook', tabposition='wn',)
# TAB LAYOUT
#tab_control = ttk.Notebook(window,style='righttab.TNotebook')
#tab1 = ttk.Frame(tab_control)
#tab2 = ttk.Frame(tab_control)
#tab3 = ttk.Frame(tab_control)
#tab4 = ttk.Frame(tab_control)
#tab5 = ttk.Frame(tab_control)
#tab6 = ttk.Frame(tab_control)
# ADD TABS TO NOTEBOOK
#tab_control.add(tab1, text=f'{"Home":^20s}')
#tab_control.add(tab2, text=f'{"View":^20s}')
#tab_control.add(tab3, text=f'{"Search":^20s}')
#tab_control.add(tab4, text=f'{"Edit":^20s}')
#tab_control.add(tab5, text=f'{"Export":^20s}')
#tab_control.add(tab6, text=f'{"About ":^20s}')
#label1 = Label(tab1, text= 'Python RPA APP',padx=1, pady=1)
#label1.grid(column=0, row=0)
#label2 = Label(tab2, text= 'View',padx=5, pady=5)
#label2.grid(column=0, row=0)
#label3 = Label(tab3, text= 'Search',padx=5, pady=5)
#label3.grid(column=0, row=0)
#label4 = Label(tab4, text= 'Edit/Update',padx=5, pady=5)
#label4.grid(column=0, row=0)
#label5 = Label(tab5, text= 'Export',padx=5, pady=5)
#label5.grid(column=0, row=0)
#label6 = Label(tab6, text= 'About',padx=5, pady=5)
#label6.grid(column=0, row=0)
#tab_control.pack(expand=1, fill='both')
class Main(ttk.Frame):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.punches_list = []
self.ent1 = tk.StringVar()
self.ent2 = tk.StringVar()
self.ent3 = tk.StringVar()
self.ent4 = tk.StringVar()
self.init_ui()
def init_ui(self):
f = ttk.Frame()
# ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW)
## ttk.Label(f, text = "Entry1").pack(side=LEFT, padx=5, pady=5, anchor=NW)
## self.txTest = ttk.Entry(f,textvariable=self.ent).pack(fill=X, padx=5, expand=True, anchor=NW)
# ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW)
# self.txTest1 = ttk.Entry(f, textvariable=self.ent2).pack(side=TOP, anchor=NW)
ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW, fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest1 = ttk.Entry(f, textvariable=self.ent1).pack(side=TOP, anchor=NW, fill=tk.BOTH, pady=5, padx=5, expand=0)
ttk.Label(f, text = "Entry2").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest2 = ttk.Entry(f, textvariable=self.ent2).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
ttk.Label(f, text = "Entry3").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest3 = ttk.Entry(f, textvariable=self.ent3).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
#tkinter.Label(window, text = "Username").grid(row = 0) #'username' is placed on position 00 (row - 0 and column - 0)
#tkinter.Entry(window).grid(row = 0, column = 1) # first input-field is placed on position 01 (row - 0 and column - 1)
ttk.Label(f, text = "Entry4").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest4 = ttk.Entry(f, textvariable=self.ent4).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.lstItems = self.get_listbox(f, 140,140).pack(anchor=N)
w = ttk.Frame()
ttk.Button(w, text="Add",command=self.add_In).pack(side=TOP, anchor=NE)
ttk.Button(w, text="Clear", command=self.clear_Out).pack(side=TOP, anchor=NE)
ttk.Button(w, text="Close", command=self.on_close).pack(side=TOP, anchor=NE)
#f.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
#w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
f.pack(side=tk.LEFT, fill=tk.BOTH, pady=5, padx=5, expand=1)
w.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
def add_In(self,):
#s = "IN {0:>30} {1}".format(str(datetime.now()), self.ent.get())
s = self.ent1.get()
self.set_list(s)
s = self.ent2.get()
self.set_list(s)
s = self.ent3.get()
self.set_list(s)
s = self.ent4.get()
self.set_list(s)
self.ent1.set('')
self.ent2.set('')
self.ent3.set('')
self.ent4.set('')
def clear_Out(self):
#s = "OUT {0:>29} {1}".format(str(datetime.now()), self.ent1.get())
#field_name.set('')
self.ent1.set('')
self.ent2.set('')
self.ent3.set('')
self.ent4.set('')
#self.set_list(s)
def set_list(self,s):
self.punches_list.append(s)
self.lstItems.delete(0, tk.END)
for i in self.punches_list:
self.lstItems.insert(tk.END, i)
def on_set(self):
self.check.set(1)
def on_close(self):
#self.destroy()
self.parent.on_exit()
def get_listbox(self, container, height=750, width=600):
sb = tk.Scrollbar(container,orient=tk.VERTICAL)
w = tk.Listbox(container,
relief=tk.GROOVE,
selectmode=tk.BROWSE,
height=height,
width=width,
background = 'white',
font='TkFixedFont',
yscrollcommand=sb.set,)
sb.config(command=w.yview)
w.pack(side=tk.LEFT,fill=tk.BOTH, expand =1)
sb.pack(fill=tk.Y, expand=1)
return w
class App(tk.Tk):
"""Start here"""
def __init__(self):
super().__init__()
self.protocol("WM_DELETE_WINDOW", self.on_exit)
self.set_style()
self.set_title()
Main(self,)
def set_style(self):
self.style = ttk.Style()
#('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
self.style.theme_use("vista") #change to your liking :)
def set_title(self):
s = "{0}".format('Employee Time-Clock')
self.title(s)
self.destroy()
def on_exit(self):
window.destroy()
#self.destroy()
#sys.exit()
#"""Close all"""
#if messagebox.askokcancel( self.title(), "Do you want to quit?", parent=self):
# self.destroy()
if __name__ == '__main__':
app = App()
app.mainloop()
Your code is a giant mess, brah ;D. What I gather from your question is that you need some kind of table. What I gather from your code is the table should have cells comprised of Label and Entry. You also want an interface to create entries. Below is an example of all of that. I don't really see anything to explain. It's just a bunch of Frame, Label, Entry and Button. The only real action is in Table. All that action is, is mathematically figuring out where to put the next Item. This is all really basic stuff.
import tkinter as tk
from tkinter import ttk
#the entire bottom row of the app.
#has a dependency on self.master.table ~ not good OOP
class EntryManager(tk.Frame):
def __init__(self, master, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.grid_columnconfigure(5, weight=1)
font='Helvetica 10 bold'
tk.Label(self, text='Label', font=font, width=5).grid(row=0, column=0, padx=2)
lbl = tk.Entry(self, width=10, font=font)
lbl.grid(row=0, column=1, padx=2)
tk.Label(self, text='Entry', font=font, width=5).grid(row=0, column=2, padx=2)
ent = tk.Entry(self, width=25, font=font)
ent.grid(row=0, column=3, padx=2)
tk.Button(self, text='add', font=font, command=lambda: self.master.table.addItem(lbl.get(), ent.get())).grid(row=0, column=4, padx=2, sticky='w')
tk.Label(self, text='rows', font=font, width=4).grid(row=0, column=5, padx=2, sticky='e')
r = tk.Entry(self, width=4, font=font)
r.insert('end', self.master.table.rows)
r.grid(row=0, column=6, padx=2)
tk.Label(self, text='cols', font=font, width=4).grid(row=0, column=7, padx=2)
c = tk.Entry(self, width=4, font=font)
c.insert('end', self.master.table.cols)
c.grid(row=0, column=8, padx=2)
tk.Button(self, text='set', font=font, command=lambda: self.master.table.setDims(r.get(), c.get())).grid(row=0, column=9, padx=2, sticky='e')
#generic scrollable frame
class ScrollFrame(tk.Frame):
def __init__(self, master, row=0, column=0, scrollspeed=.02, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.grid(row=row, column=column, sticky='nswe')
self.scrollspeed = scrollspeed
self.canvas = tk.Canvas(self, highlightthickness=0)
self.canvas.grid(column=0, row=0, sticky='nswe')
self.v_scroll = tk.Scrollbar(self, orient='vertical', command=self.canvas.yview)
self.v_scroll.grid(row=0, column=1, sticky='ns')
self.canvas.configure(yscrollcommand=self.v_scroll.set)
self.canvas.bind_all('<MouseWheel>', self.on_mousewheel)
self.frame = tk.Frame(self.canvas, height=0)
self.frame.grid_columnconfigure(0, weight=1)
self.frame.bind('<Configure>', lambda e:self.canvas.configure(scrollregion=self.canvas.bbox("all")))
self.canvas.create_window((0,0), window=self.frame, anchor="nw")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
def on_mousewheel(self, event):
self.canvas.yview_moveto(self.v_scroll.get()[0]+((-event.delta/abs(event.delta))*self.scrollspeed))
#a table cell
class Item(tk.Frame):
#property
def value(self):
return self.__value.get()
#value.setter
def value(self, text):
self.__value.set(text)
def __init__(self, master, text, value, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
tk.Label(self, text=text, width=10, font='none 8 bold').grid(row=0, column=0, pady=5, padx=5)
self.__value = tk.StringVar(value=value)
tk.Entry(self, textvariable=self.__value, width=25).grid(row=0, column=1, pady=5, padx=5)
#the table
class Table(ScrollFrame):
def __init__(self, master, rows=15, cols=3, **kwargs):
ScrollFrame.__init__(self, master, **kwargs)
self.entries = []
self.rows = rows
self.cols = cols
def addItem(self, text, value):
if len(self.entries) < self.rows*self.cols:
self.entries.append(Item(self.frame, text, value))
self.entries[-1].grid(row=(len(self.entries)-1)%self.rows, column=(len(self.entries)-1)//self.rows)
def getItem(self, row, column):
return self.entries[self.rows*column+row].value
def setDims(self, rows, cols):
if rows.isnumeric():
self.rows = int(rows)
if cols.isnumeric():
self.cols = int(cols)
for ent in self.entries:
ent.grid_forget()
for i, ent in enumerate(self.entries):
if i < self.rows*self.cols:
ent.grid(row=i%self.rows, column=i//self.rows)
class App(tk.Tk):
WIDTH, HEIGHT, TITLE = 770, 465, 'Application'
def __init__(self):
tk.Tk.__init__(self)
ttk.Style().theme_use("vista")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.table = Table(self, rows=20, cols=3)
self.table.grid(row=0, column=0, sticky='nswe')
EntryManager(self).grid(row=1, column=0, sticky='nswe', ipady=5)
#junk for testing
for i in range(12):
self.table.addItem(f'entry_{i}', f'data {i}')
if __name__ == '__main__':
app = App()
app.config(background='black')
app.title(App.TITLE)
app.geometry(f'{App.WIDTH}x{App.HEIGHT}')
#app.resizable(width=False, height=False)
app.mainloop()
Might as well dump the table keys in the table and see what happens. The sizes and alignments of things could use some work.

Triggering a button click with the enter key in Python

Please forgive me in advance, as I am very new to Python. I'm putting together this code for a very simple rate calculator and want to make it where when the Enter key is pressed the program calculates the total (executes the calculate command). Python returns an error saying that Calculate is not defined, however I've defined it several lines above. Any ideas?
import tkinter
from tkinter import ttk
from tkinter import *
root = Tk()
root.withdraw()
class Adder(ttk.Frame):
"""The adders gui and functions."""
def __init__(self, parent, *args, **kwargs):
ttk.Frame.__init__(self, parent, *args, **kwargs)
self.root = parent
self.init_gui()
def on_quit(self):
"""Exits program."""
quit()
def calculate(self, *args):
"""Calculates the sum of the two inputted numbers."""
num1 = int(self.num1_entry.get())
num2 = float(self.num2_entry.get())
num3 = ((num1/2000) * num2)
self.answer_label['text'] = num3
def init_gui(self):
self.root.title('Rate Calculator')
self.root.option_add('*tearOff', 'FALSE')
self.grid(column=0, row=0, sticky='nsew')
self.menubar = tkinter.Menu(self.root)
self.menu_file = tkinter.Menu(self.menubar)
self.menu_file.add_command(label='Exit', command=self.on_quit)
self.menu_edit = tkinter.Menu(self.menubar)
self.menubar.add_cascade(menu=self.menu_file, label='File')
self.menubar.add_cascade(menu=self.menu_edit, label='Edit')
self.root.config(menu=self.menubar)
self.num1_entry = ttk.Entry(self, width=5)
self.num1_entry.grid(column=1, row = 2)
self.num2_entry = ttk.Entry(self, width=5)
self.num2_entry.grid(column=3, row=2)
self.calc_button = ttk.Button(self, text='Calculate',
command=self.calculate)
self.calc_button.grid(column=0, row=3, columnspan=4)
self.answer_frame = ttk.LabelFrame(self, text='Answer',
height=100)
self.answer_frame.grid(column=0, row=4, columnspan=4, sticky='nesw')
self.answer_label = ttk.Label(self.answer_frame, text='')
self.answer_label.grid(column=0, row=0)
# Labels that remain constant throughout execution.
ttk.Label(self, text='Rate Calculator').grid(column=0, row=0,
columnspan=4)
ttk.Label(self, text='Weight').grid(column=0, row=2,
sticky='w')
ttk.Label(self, text='Rate').grid(column=2, row=2,
sticky='w')
ttk.Separator(self, orient='horizontal').grid(column=0,
row=1, columnspan=4, sticky='ew')
for child in self.winfo_children():
child.grid_configure(padx=5, pady=5)
root.bind('<Return>', calculate)
if __name__ == '__main__':
root = tkinter.Tk()
Adder(root)
root.mainloop()
I've reorganised your code slightly so it now calls the calculate method either when you press the button or when you hit Enter.
import tkinter as tk
from tkinter import ttk
class Adder(ttk.Frame):
"""The adders gui and functions."""
def __init__(self, parent, *args, **kwargs):
ttk.Frame.__init__(self, parent, *args, **kwargs)
self.root = parent
self.init_gui()
def on_quit(self):
"""Exits program."""
tk.quit()
def calculate(self, *args):
"""Calculates the sum of the two inputted numbers."""
num1 = int(self.num1_entry.get())
num2 = float(self.num2_entry.get())
num3 = ((num1/2000) * num2)
self.answer_label['text'] = num3
def init_gui(self):
self.root.title('Breakbulk Rate Calculator')
self.root.option_add('*tearOff', 'FALSE')
self.grid(column=0, row=0, sticky='nsew')
self.menubar = tk.Menu(self.root)
self.menu_file = tk.Menu(self.menubar)
self.menu_file.add_command(label='Exit', command=self.on_quit)
self.menu_edit = tk.Menu(self.menubar)
self.menubar.add_cascade(menu=self.menu_file, label='File')
self.menubar.add_cascade(menu=self.menu_edit, label='Edit')
self.root.config(menu=self.menubar)
self.num1_entry = ttk.Entry(self, width=5)
self.num1_entry.grid(column=1, row = 2)
self.num2_entry = ttk.Entry(self, width=5)
self.num2_entry.grid(column=3, row=2)
self.calc_button = ttk.Button(self, text='Calculate',
command=self.calculate)
self.calc_button.grid(column=0, row=3, columnspan=4)
self.answer_frame = ttk.LabelFrame(self, text='Answer',
height=100)
self.answer_frame.grid(column=0, row=4, columnspan=4, sticky='nesw')
self.answer_label = ttk.Label(self.answer_frame, text='')
self.answer_label.grid(column=0, row=0)
# Labels that remain constant throughout execution.
ttk.Label(self, text='Breakbulk Rate Calculator').grid(column=0, row=0,
columnspan=4)
ttk.Label(self, text='Weight').grid(column=0, row=2,
sticky='w')
ttk.Label(self, text='Rate').grid(column=2, row=2,
sticky='w')
ttk.Separator(self, orient='horizontal').grid(column=0,
row=1, columnspan=4, sticky='ew')
for child in self.winfo_children():
child.grid_configure(padx=5, pady=5)
self.root.bind('<Return>', lambda event: self.calculate())
if __name__ == '__main__':
root = tk.Tk()
Adder(root)
root.mainloop()
To create a callback with the proper signature for .bind I've used a lambda function that simply discards the Event object that gets passed to it.
I also got rid of the evil from tkinter import * wildcard import.
The problem is coming from this part of your code
root.bind('<Return>', calculate)
change it to
root.bind('<Return>', self.calculate)
it will work.

Python tkinter add new field by a button

It is python 3.4 here, and the program import tkinter module to build gui interface.
I am wondering how to make a button that is able to add new field for user to fill.
Try to apply built-in method vars() and getattr() but it doesn't work.
I just cannot figure out why AttributeError always pop up.
The following is a part of my code:
import tkinter as Tk
from tkinter import ttk
class dictionary(Tk.Frame):
def __init__(self, master=None):
Tk.Frame.__init__(self, master)
#......other line here........
def createWidgets(self):
self.row_c = 0
self.new_0 = Tk.StringVar(self)
self.new_0field = ttk.Entry(self, textvariable=self.new_0)
self.new_0field.grid(row=self.row_c, column=0, columnspan=2, padx=4, pady=6, sticky="NEWS")
self.add_lang = ttk.Button(self, text="add language", command=self.add_field)
self.add_lang.bind("<Return>", self.add_field)
self.add_lang.grid(row=self.row_c, column=3, padx=4, pady=6, sticky="W")
self.row_c += 1
def add_field(self):
#count is a number (string type)
count = str(self.row_c)
vars()["self.new_" + count] = Tk.StringVar(self)
vars()["self.new_" + count + "field"] = ttk.Entry(self, textvariable=getattr(self, "self.new_"+count))
vars()["self.new_" + count + "field"].grid(row=self.row_c+1, column=0, columnspan=2, padx=4, pady=6, sticky="NEWS")
self.add_lang.grid(row=self.row_c+1, column=3, padx=4, pady=6, sticky="W")
if __name__ == '__main__':
root = Tk.Tk()
app = dictionary(master=root)
app.mainloop()
Is it possible to add a field by a button in tkinter?
I would be grateful if there is any suggestion to make it work,
Thanks!
So this is my solution:
import tkinter as tk
from tkinter import ttk
class dictionary(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.fields = []
self.createWidgets()
self.grid(column=0, sticky="NEWS")
def createWidgets(self):
self.add_field()
self.add_lang = ttk.Button(self, text="add language", command=self.add_field)
self.add_lang.bind("<Return>", self.add_field)
self.add_lang.grid(row=len(self.fields), column=3, padx=4, pady=6, sticky="W")
def add_field(self):
self.fields.append({})
n = len(self.fields)-1
self.fields[n]['var'] = tk.StringVar(self)
self.fields[n]['field'] = ttk.Entry(self, textvariable=self.fields[n]['var'])
self.fields[n]['field'].grid(row=n, column=0, columnspan=2, padx=4, pady=6, sticky="NEWS")
if n:
self.add_lang.grid(row=n + 1, column=3, padx=4, pady=6, sticky="W")
if __name__ == '__main__':
root = tk.Tk()
app = dictionary(master=root)
app.mainloop()
I hope this is what you wanted.

python, tkinter: how all variables can be obtained by single button from all notebook tabs?

I need to return all variables from all tabs by clicking on ok button.
I have two tabs. What I want is that when I enter some value in 2nd tab, it should automatically appear in first tab in 'height' entry.
Then if I click 'ok' in first tab, it should return all variables(from first tab and 2nd tab) to my 'main' program for further use.
Thanks
from tkinter import *
from tkinter import ttk
class App1(ttk.Frame):
def createWidgets(self):
#text variables
self.i_height = StringVar()
self.i_weight = StringVar()
self.o_bmi = StringVar()
#labels
self.label1 = ttk.Label(self, text="Enter your weight:").grid(row=0, column=0, sticky=W)
self.label2 = ttk.Label(self, text="Enter your height:").grid(row=1, column=0, sticky=W)
self.label3 = ttk.Label(self, text="Your BMI is:").grid(row=2, column=0, sticky=W)
#text boxes
self.textbox1 = ttk.Entry(self, textvariable=self.i_weight).grid(row=0, column=1, sticky=E)
self.textbox2 = ttk.Entry(self, textvariable=self.i_height).grid(row=1, column=1, sticky=E)
self.textbox3 = ttk.Entry(self, textvariable=self.o_bmi).grid(row=2, column=1, sticky=E)
#buttons
self.button1 = ttk.Button(self, text="Cancel/Quit", command=self.quit).grid(row=3, column=1, sticky=E)
self.button1 = ttk.Button(self, text="Ok", command=self.calculateBmi).grid(row=3, column=2, sticky=E)
def calculateBmi(self):
try:
self.weight = float(self.i_weight.get())
self.height = float(self.i_height.get())
self.bmi = self.weight / self.height ** 2.0
self.o_bmi.set(self.bmi)
except ValueError:
messagebox.showinfo("Error", "You can only use numbers.")
finally:
self.i_weight.set("")
self.i_height.set("")
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.createWidgets()
class App2(ttk.Frame):
def create_widgets(self):
"""Create the widgets for the GUI"""
#1 textbox (stringvar)
self.entry= StringVar()
self.textBox1= ttk.Entry(self, textvariable=self.entry).grid(row=0, column=1)
#5 labels (3 static, 1 stringvar)
self.displayLabel1 = ttk.Label(self, text="feet").grid(row=0, column=2, sticky=W)
self.displayLabel2 = ttk.Label(self, text="is equivalent to:").grid(row=1, column=0)
self.result= StringVar()
self.displayLabel3 = ttk.Label(self, textvariable=self.result).grid(row=1, column=1)
self.displayLabel4 = ttk.Label(self, text="meters").grid(row=1, column=2, sticky=W)
#2 buttons
self.quitButton = ttk.Button(self, text="Quit", command=self.quit).grid(row=2, column=1, sticky=(S,E))
self.calculateButton = ttk.Button(self, text="Calculate", command=self.convert_feet_to_meters).grid(row=2, column=2, sticky=(S,E))
def convert_feet_to_meters(self):
"""Converts feet to meters, uses string vars and converts them to floats"""
self.measurement = float(self.entry.get())
self.meters = self.measurement * 0.3048
self.result.set(self.meters)
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
def button1_click():
root = Tk()
app = App1(master=root)
app.mainloop()
def button2_click():
root = Tk()
app = App2(master=root)
app.mainloop()
def main():
#Setup Tk()
window = Tk()
#Setup the notebook (tabs)
notebook = ttk.Notebook(window)
frame1 = ttk.Frame(notebook)
frame2 = ttk.Frame(notebook)
notebook.add(frame1, text="BMI Calc")
notebook.add(frame2, text="Feet to Meters")
notebook.grid()
#Create tab frames
app1 = App1(master=frame1)
app1.grid()
app2 = App2(master=frame2)
app2.grid()
#Main loop
window.mainloop()
main()
You have some fundamental mistakes in your program -- you cannot have three mainloops running at the same. You should always only have exactly one instance of Tk, and call mainloop exactly once.
Regardless of that, the solution is that you need to create a method or public variable in the app, and then your button callback needs to be able to call that method or access that variable.
For example, you would do it like this:
def callback():
value1 = app1.getValue()
value2 = app2.getValue()
...

Categories

Resources