I have built a simple to-do list and I am trying to get the checkbox to remove itself when it is checked(to signify that the task has been completed)
I am not sure how I need to be implementing the function in order to remove itself. Can anyone help me out with this. I've combed through a list of pages and none of them have really indicated how you do this.
class App(object):
def __init__(self, master):
self.master = master
self.frame = Frame(master)
self.frame.grid()
self.addFrame = Frame(master)
self.addFrame.grid(row=0, column=0, columnspan=2, sticky='N')
self.listFrame = Frame(master)
self.listFrame.grid(row=1, column=0, columnspan=2, sticky='NW')
self.todoList = []
self.initUI()
def initUI(self):
self.entryBox = Entry(self.frame, width = 15)
self.entryBox.grid(row=0, column=0, sticky='N')
self.addButton = Button(self.frame, text="<-ADD->", command=self.add)
self.addButton.grid(row=0, column=1, sticky='N')
def removeCheckButton(self):
# - CONFUSED HOW TO REMOVE THE SPECIFIC CHECKBUTTON
pass
def add(self):
entry = self.entryBox.get()
self.entryBox.delete(0, END)
self.todoList.append(entry)
print self.todoList
var1 = IntVar()
self.buttonList = []
for n in range(len(self.todoList)):
lx = Checkbutton(self.listFrame, text=self.todoList[n], variable=self.todoList[n], command=removeCheckButton)
lx.grid(row=n, column=0, sticky='NW')
self.buttonList.append(lx)
print self.buttonList
Have a look at this. your add is a bit strangely designed (and incorrectly IMO), so I modified it slightly as well as other parts.
from tkinter import *
class App(object):
def __init__(self, master):
self.master = master
self.frame = Frame(master)
self.frame.grid()
self.addFrame = Frame(master)
self.addFrame.grid(row=0, column=0, columnspan=2, sticky='N')
self.listFrame = Frame(master)
self.listFrame.grid(row=1, column=0, columnspan=2, sticky='NW')
self.todoList = []
self.buttonList = [] #<--- button list is here now
self.initUI()
def initUI(self):
self.entryBox = Entry(self.frame, width = 15)
self.entryBox.grid(row=0, column=0, sticky='N')
self.addButton = Button(self.frame, text="<-ADD->", command=self.add)
self.addButton.grid(row=0, column=1, sticky='N')
def removeCheckButton(self, button_no):
# - CONFUSED HOW TO REMOVE THE SPECIFIC CHECKBUTTON
# print(button_no, self.buttonList[button_no])
#self.buttonList[button_no].grid_forget()
self.buttonList[button_no].destroy()
# del self.buttonList[button_no]
# del self.todoList[button_no]
def add(self):
entry = self.entryBox.get()
self.entryBox.delete(0, END)
self.todoList.append(entry)
print(self.todoList)
var1 = IntVar()
#self.buttonList = [] #<--- not sense having this here
# for n in range(len(self.todoList)): #<-- this for also very strange here.
n = len(self.buttonList)
lx = Checkbutton(self.listFrame,
text=self.todoList[n],
variable=self.todoList[n],
command=lambda ni=n: self.removeCheckButton(ni))
lx.grid(row=n, column=0, sticky='NW')
self.buttonList.append(lx)
# print(self.buttonList)
root = Tk()
app = App(root)
root.mainloop()
P.S.
I use python 3, but except the import part, the code should execute for you. Probably it needs more fixing, but the checkboxes get destroyed now as they supposed to.
Related
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))
...
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
I have the following code to generate a two entry input dialog box and a button to close the "app".
However I cannot cannot get the values out of the outputs. They always come out as x and N. The code was not developed by me since I am a beginner with python. Can anyone give me hand with this?
from tkinter import Tk, Text, TOP, BOTH, X, N, LEFT, RIGH
from tkinter.ttk import Frame, Label, Entry, Button
class SimpleDialog(Frame):
def __init__(self):
super().__init__()
self.output1 = ""
self.output2 = ""
self.initUI()
def initUI(self):
self.master.title("Simple Dialog")
self.pack(fill=BOTH, expand=True)
frame1 = Frame(self)
frame1.pack()
lbl1 = Label(frame1, text="Input1", width=6)
lbl1.pack(side=LEFT, padx=5, pady=10)
self.entry1 = Entry(frame1)
self.entry1.pack(padx=5, expand=True)
frame2 = Frame(self)
frame2.pack()
lbl2 = Label(frame2, text="Input2", width=6)
lbl2.pack(side=LEFT, padx=5, pady=10)
self.entry2 = Entry(frame2)
self.entry2.pack(padx=5, expand=True)
frame3 = Frame(self)
frame3.pack()
btn = Button(frame3, text="Submit", command=self.onSubmit)
btn.pack(padx=5, pady=10)
def onSubmit(self):
self.output1 = self.entry1.get()
self.output2 = self.entry2.get()
self.quit()
def main():
# This part triggers the dialog
root = Tk()
root.geometry("250x150+300+300")
app = SimpleDialog()
root.mainloop()
user_input = (app.output1, app.output2)
try:
root.destroy()
except:
pass
return user_input
if __name__ == '__main__':
main()
kind regards!
I am trying to change the Label's text, but I have no idea how to access it. I have added the label and a button and I want to change the label's text on button click. However, I cannot access the label from the function - see the line with the question marks. What should I change it to?
When I try the code as is I get "Example instance has no attribute 'frame2'"
I am using Python 2.7
============== update =========
changed frame2 to self.frame2, but it did not solve the problem
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.all = []
self.path = ""
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("SomeName")
self.style = Style()
self.style.theme_use("default")
self.frame2 = Frame(self, relief=FLAT, borderwidth=2)
self.frame2.pack(side=TOP, fill=BOTH, expand=False)
# this is my label
usrLable = Label(self.frame2, text="Username: ")
usrLable.pack(side=LEFT, padx=5, pady=1)
frame6 = Frame(self, relief=FLAT, borderwidth=2)
frame6.pack(fill=BOTH, expand=True)
# this is my button
stopButton = Button(frame6, text="Stop", command=self.stopButtonClick)
stopButton.pack(side=LEFT)
def stopButtonClick(self):
try:
self.frame2.usrLable.configure(text="hello") # ?????????????
except Exception,e:
print str(e)
return
You need to replace the following line:
frame2 = Frame(self, relief=FLAT, borderwidth=2)
frame2.pack(side=TOP, fill=BOTH, expand=False)
with:
self.frame2 = Frame(self, relief=FLAT, borderwidth=2)
self.frame2.pack(side=TOP, fill=BOTH, expand=False)
to make frame2 an instance attribute instead of local variable.
And also change the references to frame2 to self.frame2 accordingly.
Same for the usrLable.
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.all = []
self.path = ""
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("SomeName")
self.style = Style()
self.style.theme_use("default")
self.frame2 = Frame(self, relief=FLAT, borderwidth=2)
self.frame2.pack(side=TOP, fill=BOTH, expand=False)
self.usrLable = Label(self.frame2, text="Username: ")
self.usrLable.pack(side=LEFT, padx=5, pady=1)
self.frame6 = Frame(self, relief=FLAT, borderwidth=2)
self.frame6.pack(fill=BOTH, expand=True)
stopButton = Button(self.frame6, text="Stop", command=self.stopButtonClick)
stopButton.pack(side=LEFT)
def stopButtonClick(self):
self.usrLable.configure(text="hello")
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()
...