Python Tkinter Checkbutton-text Alignment Issue - python

I am fooling around with GUI programming using Tkinter on python, with the goal being a GUI app which will allow a user to add a task or delete (to be saved to a txt file).
Right now, I am just trying to figure out the basics of adding/removing checkbuttons.
The issue I am having is that when I run the script, the check boxes are not aligned with the text for them. The picture below shows the issue.
The code used to pull tasks from a txt file and add them as checkbuttons is as follows:
tasks = []
with open(r"C:\Users\patte\Desktop\tasks.txt") as file:
tasks = file.readlines()
row = 2
for task in tasks:
self.task_checkbox = Checkbutton(self.master,text=task,font=("Arial",12),relief='groove')
self.task_checkbox.grid(row=row,column=0,sticky=W)
row+=1
Note that row is initialized to 2 as the title and entry bar take up rows 0 and 1. I have tried changing fonts, etc., but the result stays the same.
Any sort of advice or criticism is greatly appreciated.
The full code is as follows:
from tkinter import *
class ToDo():
def __init__(self,master):
self.master = master # Geometry and layout when initialized
master.geometry("800x800")
master.title("TO DO")
self.gui_title = Label(self.master,text="Tasks:",font = ("Arial Bold",26))
self.gui_title.grid(row=0,column=0,sticky=W)
self.task_entry_label = Label(self.master,text="Enter Task:",font = ("Arial",12))
self.task_entry_label.grid(row=2,column=0,sticky=W)
self.task_entry = Entry(self.master)
self.task_entry.grid(row=2,column=1,sticky=W)
self.task_entry.focus_set()
tasks = []
with open(r"C:\Users\patte\Desktop\tasks.txt") as file:
tasks = file.readlines()
row = 3
for task in tasks:
self.task_checkbox = Checkbutton(self.master,text=task,font=("Arial",12),relief='groove')
self.task_checkbox.grid(row=row,column=0,sticky=W)
row+=1
self.QuitButton = Button(self.master,text="Quit",font=("Arial Bold",12),command = lambda: self.master.quit())
self.QuitButton.grid(sticky=SW,row=7)
root = Tk()
Tasks = ToDo(root)
root.mainloop()
Thanks!

Related

How can I pass the 2nd item of sqlite 3 table of every item in a label in tkinter python module?

I have a problem, the problem is i want to create a post-it tkinter gui app and I want to store all the posts the user create so they can open it when they rerun the app, so i used sqlite 3 module to achieve this, but im stuck at the moment when the user opens the existing post-its bcs it opens the last content of the for loop
In case u dont get it here is the code:
"""
from tkinter import *
import sqlite3
conn = sqlite3.connect("post-it.db")
row = 1
cursor = conn.cursor()
posts = cursor.execute("SELECT rowid, * FROM postits")
postsFetch = posts.fetchall()
print(f"{postsFetch}")
def createPost():
pass
def openPost(name):
print(name)
post = Tk()
text = Label(post,text=name)
text.pack()
post.mainloop()
window = Tk()
window.geometry("400x400")
window.config(bg="blue")
createNew = Button(text="Create new Post-it",command=createPost)
createNew.grid(column=1,row=1)
createName = Entry()
createName.grid(column=1,row=2)
frame = Frame()
frame.grid(column=2)
#the problem is at this for loop it opens the last item text
for postit in postsFetch:
postitBtn = Button(frame,text=postit[1],command=lambda: openPost(postit[2]))
postitBtn.grid(column=8,row=row)
row += 1
conn.commit()
window.mainloop()
conn.close()
"""
if u know the answer please help
Firstly, don't use Tk more than once in a program - it can cause problems later on. For all other windows, use Toplevel. Replace post = Tk() with post = Toplevel().The reason your loop doesn't work is explained here. To fix it, change your lambda function to lambda postit = postit: openPost(postit[2]))

How to make a Tkinter loading screen that runs side-by-side the main program

I am trying to create a small python app with Tkinter which involves collecting data in several lists, like this:
def main_process():
list1 = []
list2 = []
list3 = []
#Data collection process
#Resulting lists ready
The data collection process takes about 10 seconds, so I wanted to make a "Loading Screen" that works side-by-side the data collection process, without one following the other. For the status bar, I thought of introducing a variable n with value starting from 0, and increasing its value as and when each resultant lists get ready.
I attempted to create a function loading_screen(n) which will be called before the data processing, with n being the aforementioned variable containing a numeric value. And as the data_processing occurs, I shall run the loading_screen function to introduce the updated values of n, like so:
def main_process():
def loading_screen(n):
root = Tk()
root.title('Stock Market App')
root.geometry('800x300')
status_label = Label(root, text = n)
status_label.pack()
loading_screen(0)
# list1 Ready
n += 10
root.after(0, lambda: loading_screen(n))
# list2 ready
n += 10
root.after(0, lambda: loading_screen(n))
# And so on...
But it ended up showing me the loading screen after all the data processing has occurred. Can somebody please help me on this?
Thanks.
Putting function inside a function is not a good idea, better to create a class.
Then create two separate Tk windows.
Also, after is able to pass parameters so lambda is not necessary.
I've made a few small adjustments to conform to your question. The windows will now sit side by side.
Is this what you were looking for?
import tkinter as tk
class main_process:
def loading_screen( self, n ):
self.status_label[ 'text' ] = '{}'.format( n )
self.root.deiconify()
self.status_label.focus()
self.root.update()
# insert processing here
def __init__( self, x ):
self.root = tk.Tk()
self.root.withdraw()
self.root.title('Stock Market App')
self.root.geometry( f'700x300+{x}+240')
self.status_label = tk.Label( self.root, font = 'Helvetica 20 normal')
self.status_label.pack()
self.root.update()
screen_1 = main_process( 0 )
screen_1.root.after( 10, screen_1.loading_screen, 1 )
screen_2 = main_process( 705 )
screen_2.root.after( 10, screen_2.loading_screen, 2 )
screen_2.root.mainloop()
Hi you can remove the gui like this
Labelone.destroy()
.
.
.
Loading_screen.place(...)
#you data collection code
Loading_screen.destroy()
Labelone.place(...)
.
.
.
So your data collection is going background and loading gui is place so user sees loading while python is collecting data

Global variable are not working in this Python code

I have a student that is working on a task and trying to use global variables within a couple functions across different files. I have had to include excerpts of the files. The first file is the main one and when you click the results button in that program (from the main window it creates) it should call the other file and pass a variable. But, he gets the following error...
Results.py", line 44, in GiveResults if row[0] == sname: NameError: name 'sname' is not defined
I'm hoping that someone with much better ability and knowledge might be able to point us in the right direction to remedy this. If there is a better way to share the code on here then please also let me know.
Thanks,
Scott
'Solution.py'
#This imports the tkinter module of python
from tkinter import *
#This imports the other windows for use later
import Results, New_User, Edit_User
#This part forms the main window and controls things such as size, colour, and message
main = Tk()
main.title('Hello there')
main.geometry("1000x600")
main['background']='light blue'
#This creates a frame for use later
window = Frame(main).pack()
#Defines a function that when called will convert whatever is in the textboxes to variables
def retrieve():
global sname
sname = selectedname.get()
global sboss
sboss = selectedname.get()
'Results.py'
from tkinter import *
#This is defining the function that the first window is calling upon
def GiveResults():
#This is defining the variables as globe for use across windows (Although it isnt working)
global sname
global sboss
global inputt
#Defines a quit function to close the window when called
def quit():
ResultsGiven.destroy()
#This is making the window
ResultsGiven = Tk()
ResultsGiven.title('You did the program')
ResultsGiven.geometry("600x400")
ResultsGiven['background']='light blue'
#Creating a frame
windowr = Frame(ResultsGiven, bg = 'light blue')
#Creating a title
titlefont = ('papyrus', 30)
title = Label(windowr, text='Results', font=titlefont)
title.config(height=1, width=400)
title.pack(side=TOP, fill = 'x')
#Creating a canvas
canvasr = Canvas(windowr, width = 400, height = 400, background = 'light blue')
canvasr.pack()
#This is importing the csv module of python
import csv
#This is opening the csv file created when a new user is made
#It is then creating a reader to check the first column for the name entered in the main window
#When it finds a match it moves along that row to find the class
#(Unfinished)
with open("userbase.csv") as f:
for row in csv.reader(f):
if row[0] == sname:
sclass = str(column[2])```

how to generate multiple buttons with a loop?

I have programmed software that displays a "tuile".
Definition of a tuile:
A tuile is a Frame which contains a button which displays an image and an explanatory text.
I would like to display 3 tuiles with 3 different settings.
listes_icones = ["icone1.png","icone2.png","icone3.png"]
listes_relx = [".3",".4",".5"]
listes_text = ["SYSTEM", "USER", "GAME"]
for i in range(3):
gen_img = PhotoImage(file=listes_icones[i])
gen_cadre = Frame(home,width=100, height=100,bg=bg_root)
gen_cadre.place(anchor="c", relx=listes_relx[i], rely=.5)
gen_img_bouton = Button(gen_cadre, image=gen_img, relief="flat",bg=bg_root)
gen_img_bouton.pack()
gen_text = Label(gen_cadre, text=listes_text[i], bg=bg_root, fg=text_color,font="blocktastic 18")
gen_text.pack()
I manage to display the text but not the button and the image, the variable is overwritten. How to solve this problem?
The problem that you are facing is like you said, the variable is overwritten in your loop. To solve this you need to keep track of your generated images. A simple solution is to store them in a list and get them in the next step. Here is an exampel:
import tkinter as tk
import PIL
listes_icones = ["icone1.png","icone2.png","icone3.png"]
gen_icons = []
listes_relx = [".3",".4",".5"]
listes_text = ["SYSTEM", "USER", "GAME"]
home = tk.Tk()
for i in range(3):
gen_img = tk.PhotoImage(file=listes_icones[i])
gen_icons.append(gen_img)
gen_cadre = tk.Frame(home,width=100, height=100)
gen_cadre.place(anchor="c", relx=listes_relx[i], rely=.5)
gen_img_bouton = tk.Button(gen_cadre, image=gen_icons[i], relief="flat")
gen_img_bouton.pack()
gen_text = tk.Label(gen_cadre, text=listes_text[i], font="blocktastic 18")
gen_text.pack()
home.mainloop()

Remove buttons created in for loop python tkinter

I want that when I go to secondpage and back to the mainpage it removes the buttons created in the mainloop. So when I open the second page again, it needs to make the buttons again. with the updated list
Now it shows the buttons 2 times. I know to not add it into a function it will render just 1 time but the point is it will be removed when it is in a function and it need to remaked every time I open the mainpage. So that I can edit for example the list when the application is open and it will be rendered again.
Here is my code:
from tkinter import *
items = ['ijs', 'water', 'lolly', 'laptop']
root = Tk()
def buttonmaker():
for x in items:
button = Button(master=secondpage, text=x ).pack()
def mainpagetosecondpage():
mainpage.pack_forget()
buttonmaker()
secondpage.pack()
def secondpagetomainpage():
secondpage.pack_forget()
mainpage.pack()
#mainpage
mainpage = Frame(master=root)
main_to_second_button = Button(master=mainpage, text='secondpage', command=mainpagetosecondpage).pack()
#scondpage
secondpage = Frame(master=root)
Second_to_main_button = Button(master=secondpage, text='mainpage', command=secondpagetomainpage).pack()
mainpage.pack()
root.mainloop()
If something is unclear, please ask
You need to call buttonmaker only once, during the setup of the second frame:
from tkinter import *
root = Tk()
def buttonmaker():
items = ['ijs', 'water', 'lolly', 'laptop']
for x in items:
button = Button(master=secondpage, text=x )
button.pack()
def mainpagetosecondpage():
mainpage.pack_forget()
secondpage.pack()
def secondpagetomainpage():
secondpage.pack_forget()
mainpage.pack()
#mainpage
mainpage = Frame(master=root)
main_to_second_button = Button(master=mainpage, text='secondpage', command=mainpagetosecondpage)
main_to_second_button.pack()
#scondpage
secondpage = Frame(master=root)
Second_to_main_button = Button(master=secondpage, text='mainpage', command=secondpagetomainpage)
Second_to_main_button.pack()
buttonmaker()
mainpage.pack()
root.mainloop()
Also, you need to avoid putting the layout on the same line as the initialization. Code like variable = Widget(args).pack() will lead to bugs. Use 2 lines like I did above.

Categories