What causes this white border around tkinter label widgets? - python

I am creating a chess board and after creating Canvas widgets for each of the chess board pieces. I have put labels around the board however the show up with this weird white border than i have no idea how to remove.
def createGrid(self):
colour = True
self.grid_list = []
for rows in range(8):
label = Label(self.canvas, text='{}'.format(rows+1), bg='#727272', highlightthickness=0)
label.grid(row=rows, column=0)
row_list = []
self.grid_list.append(row_list)
colour = not colour
for columns in range(8):
label = Label(self.canvas, text='{}'.format(self.letters[columns]), bg='#727272',
fg='white', highlightthickness=0, height = 2)
label.grid(row=8, column=columns+1)
if colour:
grid_piece = Canvas(self.canvas, width=self.size / 8, height=self.size / 8, bg=self.colour1,
highlightthickness=0, highlightbackground='#727272')
grid_piece.grid(row=rows, column=columns+1, padx = 0, pady = 0)
else:
grid_piece = Canvas(self.canvas, width=self.size / 8, height=self.size / 8, bg=self.colour2,
highlightthickness = 0)
grid_piece.grid(row=rows, column=columns+1)
colour = not colour
row_list.append(grid_piece)
Board with weird borders

There isn't enough code in your question for others to run it, so I added my own and was able to reproduce the problem after a lot of trial and error. I think the border is being caused by not specify borderwidth=0, highlightthickness=0 everywhere it's needed, so I added it around the Frame subclass and the main Canvas it contains.
Here's the result:
And here's the code used:
from tkinter import *
class Foo(Frame):
def __init__(self, *args):
super(Foo, self).__init__(*args, bg='#727272', borderwidth=0,
highlightthickness=0)
self.pack()
self.canvas = Canvas(self, borderwidth=0, bg='#727272', highlightthickness=0)
self.canvas.pack()
self.letters = list('ABCDEFHI')
self.size = 768
self.colour1 = '#7C1900'
self.colour2 = '#FFDFC4'
def createGrid(self):
colour = True
self.grid_list = []
for rows in range(8):
label = Label(self.canvas, text='{}'.format(rows+1), bg='#727272',
highlightthickness=0)
label.grid(row=rows, column=0)
row_list = []
self.grid_list.append(row_list)
colour = not colour
for columns in range(8):
label = Label(self.canvas, text='{}'.format(self.letters[columns]),
bg='#727272', fg='white', highlightthickness=0, height=2)
label.grid(row=8, column=columns+1)
if colour:
grid_piece = Canvas(self.canvas, width=self.size / 8,
height=self.size / 8, bg=self.colour1,
highlightthickness=0,
highlightbackground='#727272')
grid_piece.grid(row=rows, column=columns+1, padx=0, pady=0)
else:
grid_piece = Canvas(self.canvas, width=self.size / 8,
height=self.size / 8, bg=self.colour2,
highlightthickness=0)
grid_piece.grid(row=rows, column=columns+1)
colour = not colour
row_list.append(grid_piece)
root = Tk()
foo = Foo()
foo.createGrid()
root.mainloop()

Related

can you insert a canvas inside a frame in tkinter? [duplicate]

This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 6 months ago.
I'm trying to display a frame with a canvas inside in order I'll be able to change of frame with a button, but when the code is executed it does not even display the button, I don't know if it happens because of all is on a function, if doing what I think is even possible or if I'm missing something
from tkinter import *
window = Tk()
window.geometry("1200x700")
window.configure(bg = "#ffffff")
def btn_clicked():
print("Button Clicked")
frame1 =Frame(window, width=1200, height=700)
frame1.grid(row=0, column=0)
def load_page():
frame1.tkraise()
frame1.pack_propagate(False)
canvas = Canvas(
frame1,
bg = "#263ff8",
height = 700,
width = 1200,
bd = 0,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
background_img = PhotoImage(file = f"background.png")
background = canvas.create_image(
601.0, 341.0,
image=background_img)
img0 = PhotoImage(file = f"img0.png")
boton = Button(
image = img0,
borderwidth = 0,
highlightthickness = 0,
command = btn_clicked,
relief = "flat")
boton.place(
x = 85, y = 71,
width = 430,
height = 99)
load_page()
window.resizable(False, False)
window.mainloop()
Rephrased the entire code and including image:
To see button display. I had to reduced height and width in Canvas. Also The button had to reduced. In line 21, I changed bd = 10. You can comment in , because I don't used PhotoImage. you can debug see in image.
from tkinter import *
window = Tk()
window.geometry("1200x700")
window.configure(bg = "#ffffff")
def btn_clicked():
print("Button Clicked")
frame1 =Frame(window, width=1200, height=700)
frame1.grid(row=0, column=0)
def load_page():
frame1.tkraise()
frame1.pack_propagate(False)
canvas = Canvas(
frame1,
bg = "#263ff8",
height = 100,
width = 200,
bd = 10,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
#background_img = PhotoImage(file = f"background.png")
#background = canvas.create_image(
#601.0, 341.0,
#image=background_img)
#img0 = PhotoImage(file = f"img0.png")
boton = Button(frame1,
#image = img0,
borderwidth = 0,
highlightthickness = 0,
command = btn_clicked,
relief = "flat")
boton.place(
x = 85, y = 71,
width = 30,
height =29)
load_page()
window.resizable(False, False)
window.mainloop()
Output result. you can see debug.

how to draw rectangle over Tkinter scale?

I have the following GUI as shown in the Figure below. Instead of the black box, I wanted to draw a transparent rectangle on top of all the scales covering values 1, 0, and -1 of the scale.
Is there a way to make the Tkinter canvas transparent? If it is not the correct way to do it, what are the alternatives that I could try? I shared the sample code I use. That can be used to reproduce this GUI.
from tkinter import *
import itertools
root = Tk()
root.geometry('840x420')
root.title('Test Window')
variables = {"var1", "var2", "var3", "var4"}
pair_list = list(itertools.combinations(list(variables), 2))
pair_result_dictionary = dict.fromkeys(pair_list)
my_canvas = Canvas()
my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
my_scrollbar = Scrollbar(root, orient=tk.VERTICAL, command=my_canvas.yview)
my_scrollbar.pack(side=RIGHT, fill=Y)
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox("all")))
second_frame = Frame(my_canvas)
my_canvas.create_window((0, 0), window=second_frame, anchor="nw")
i = 0
heading_label = Label(second_frame, text="Test Window", font=('Arial',16))
heading_label.grid(column=0, row=0, sticky=tk.NW, columnspan=2, padx=(52, 0), pady=(20, 10))
for pair in pair_list:
sample_scale = tk.Scale(second_frame, from_=9, to=-9, length=600, orient=tk.HORIZONTAL, font=('Arial', 15),
tickinterval=1,resolution=1)
label_left = tk.Label(second_frame, text=pair[0], font=('Arial', 15))
label_left.grid(column=0, row=2 + i, sticky=tk.W, padx=(52, 0), pady=5)
sample_scale.set(((sample_scale['from'] - sample_scale['to']) / 2) + sample_scale['to'])
sample_scale.grid(column=1, row=2 + i, sticky=tk.W, padx=(5, 0), pady=5)
label_right = tk.Label(second_frame, text=pair[1], font=('Arial', 15))
label_right.grid(column=2, row=2 + i, sticky=tk.W, padx=(5, 5), pady=5)
i = i + 100
rectangle_holder_canvas = tk.Canvas(second_frame, width=100, height=70, bd=0, background='#000000')
rectangle_holder_canvas.grid(column=1, row=2, sticky=tk.S, padx=(0, 0), pady=0)
rec = rectangle_holder_canvas.create_rectangle(3, 3, 100, 70, outline='blue', fill='')
rectangle_holder_canvas.tag_raise(rec, 'all')
root.mainloop()
If I use the following code lines, it makes the entire square transparent and will see what's underneath the main window which is not what I want sadly.
root.wm_attributes("-transparentcolor", 'grey')
rectangle_holder_canvas = tk.Canvas(second_frame, width=100, height=70, bd=0, bg="grey")
Appreciate your thoughts and time on how to achieve this.
I read that, "tag_raise" method does not affect canvas window items. To change a window item's stacking order, use a lower or lift method on the window.. So I tried to draw a rectangle on my_canvas by setting second_frame.lower() as shown below code. Then I only see the rectangle but not the scales or labels on the second frame.
my_canvas.create_window((0, 0), window=second_frame.lower(), anchor=CENTER)
rec = my_canvas.create_rectangle(50, 50, 200, 200, outline='blue', fill='blue')
Your question has no easy answer.
The organisation of canvas objects is divided in two groups.
Ordinary graphical objects like rectangle, polygon etc are stacked in the order
of their creation, with the first object in the background and the last object
in the foreground. The stacking order of such objects can be changed via
canvas.lift, canvas.lower, canvas.tag_raise and canvas.tag_lower.
The second group are the canvas window objects, these are created using a
fixed stacking order that ALLWAYS sit above graphical objects.
Therefore it is not possible to place ordinary graphical objects above window
objects.
This would seem to make your objective impossible, however there is (at least)
one solution.
The following code achieves your objective by using a Toplevel window that is
positioned above the canvas. This window uses wm_attributes("-transparentcolor", color)
and overrideredirect(1), it also sets wm_attributes("-topmost", True).
The main window and top window are then bound together via the "Configure"
binding so that moving main window will automatically move top window.
This creates the effect you are looking for, although it may not suit your needs.
I've used one of your Scale objects placed in a canvas window object to simulate
a fragment of your code.
import tkinter as tk
color = "red"
class transParent(tk.Tk):
def __init__(self):
super().__init__()
self.withdraw()
self.columnconfigure(0, weight = 1)
wide, high = 606, 106
self.geometry(f"{wide}x{high}+20+20")
self.canvas = tk.Canvas(
self, background = color, highlightthickness = 0, borderwidth = 0)
self.canvas.grid(sticky = tk.NSEW)
self.s_scale = tk.Scale(
self.canvas, from_ = 9, to = -9, length = 600,
orient = tk.HORIZONTAL, font = "Arial 15",
takefocus = 1, tickinterval = 1, resolution = 1)
self.s_scale.set(0)
self.s_scale.grid(
column = 0, row = 0, sticky = tk.W, padx = 5, pady = 5)
self.sample_window = self.canvas.create_window(
0, 0, window = self.s_scale, anchor = tk.NW)
self.deiconify()
self.wait_visibility()
# build transparency toplevel : width, height, borderwidth
w, h, bw = 100, 100, 4
self.top = tk.Toplevel(
self, padx = 0, pady = 0, background = color,
highlightthickness = 0, relief = "solid", borderwidth = bw)
self.X, self.Y = self.winfo_x, self.winfo_y
self.top.geometry(f"{w}x{h}+{self.X()}+{self.Y()}")
self.top.wm_attributes("-transparentcolor", color)
self.top.overrideredirect(1)
self.top.wm_attributes("-topmost", True)
# estimate top position > trial & error?
self.xx, self.yy = int(wide / 2 - w / 2.4), int(high / 3.4)
# primary bindings
self.bind("<Configure>", self.moveit)
self.top.event_add(
"<<HOOD>>", "<Button-1>", "<Button-2>", "<Button-3>")
self.top.bind("<<HOOD>>", self.focal)
self.focus_force()
def moveit(self, ev):
self.top.geometry(f"+{self.X()+self.xx}+{self.Y()+self.yy}")
self.top.lift()
def focal(self, ev):
self.s_scale.focus_set()
if __name__ == "__main__":
app = transParent()
app.mainloop()

Tkinter app doesn't keep proportions when moved in other screen or run through ssh

I've built a GUI using Tkinter. On my dual monitor local machine, the appearance of the gui is as it was designed for.
I have the following issues though:
If I move the window to the second monitor, then the frames inside the main window don't resize according to the dimensions of the new monitor, so the gui looks like so I guess it has to do with the fact that I'm using the size of the monitor that the app is open to columnconfigure my frames.
screen_width = int(window.winfo_geometry().split('x', 1)[0])
tab_Digitizer.columnconfigure(0, minsize=int(0.75*screen_width), weight=80)
The second issue is that, if I connect from a remote machine (MacOS with XQuartz) using ssh, by default a small window opens and my gui looks like so
Oddly enough if I maximize the window, the layout gets completely messed up
Since I just started in Python and Tkinter probably I'm doing something wrong but can't figure out what.
Is there a way to automatically resize/rescale/shrink everything depending on the dimensions of the root window?
Also is it possible to do the same for the children of every parent i.e. widgets inside a frame
The code I have is super big to paste here, so I'm giving a link to it
https://pastebin.com/hHEYJ1bR but I have a snippet that might help
import tkinter as tk
import tkinter.font
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from PIL import ImageTk, Image
import screeninfo
from screeninfo import get_monitors
import os
# Method to make Label(Widget) invisible
def hide_frame(frame):
# This will remove the widget
frame.grid_remove()
# Method to make Label(widget) visible
def show_frame(frame, c, r, S, pdx):
# This will recover the widget
frame.grid(column=c, row=r, sticky=S, ipadx=(pdx,0))
# Method to make Label(widget) visible
def show_frame_padx(frame, c, r, S, pdx):
# This will recover the widget
frame.grid(column=c, row=r, sticky=S, padx=(pdx,0))
def populate(frame, rows):
'''Put in some fake data'''
for row in range(rows):
tk.Label(frame,
text = "%s" % row,
).grid(row=row, column=0)
t="Blah blah blah blah blah blah blah blah %s" %row
tk.Label(frame, text=t).grid(row = row,
column = 1,
sticky = EW
)
#____________________________________________________________________________________________
#This will be the main window
window = tk.Tk()
window.resizable(True, True)
window.attributes('-zoomed', True)
window.title("DICER daq")
default_font = tkinter.font.Font(font='TkDefaultFont')
screen_height = window.winfo_screenheight()
window.update()
screen_width = int(window.winfo_geometry().split('x', 1)[0])
screen_height = int(window.winfo_geometry().split('x', 1)[1].split('+', 1)[0])
#____________________________________________________________________________________________
#Upper frame
frame_logo = Frame(window, bd=10)
frame_logo.place(rely=0.0, relx=0.0, relwidth=1.0)
logo_label = tk.Label(frame_logo, text="daq", fg="red", font='Helvetica 18 bold')
logo_label.pack(anchor=W)
label_version = tk.Label(frame_logo, text="version test.0", fg="blue")
label_version.pack(side=LEFT)
#____________________________________________________________________________________________
#Lower frame
frame_main = Frame(window)
frame_main.place(rely=0.10, relx=0.0, relwidth=1.0)
#Create a tabcontrol
tabControl = ttk.Notebook(frame_main)
tabControl.grid(column=0, row=1)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Digitizer tab
tab_Digitizer = ttk.Frame(tabControl)
tabControl.add(tab_Digitizer, text=' Digitizer ')
tab_Digitizer.columnconfigure(0, minsize=int(0.75*screen_width), weight=80)
tab_Digitizer.columnconfigure(1, minsize=75, weight=10)
tab_Digitizer.columnconfigure(2, minsize=75, weight=10)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#This is to select available digitizer channels
def Digitizer_channel_selection(event):
print ("Digitizer channel selected:", var_digitizer_channel.get() )
pass
lbl_general_board_settings = Label(tab_Digitizer, text="Digitizer channel number", font='-weight bold')
lbl_general_board_settings.grid(column=0, row=0, sticky=W)
opt_digitizer_channel = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
var_digitizer_channel = IntVar(tab_Digitizer)
var_digitizer_channel.set(opt_digitizer_channel[0]) # default value
digitizer_channel = OptionMenu(tab_Digitizer, var_digitizer_channel, *opt_digitizer_channel, command = Digitizer_channel_selection)
digitizer_channel.grid(column=1, row=0, sticky=NSEW)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#General board settings
lbl_general_board_registers = Label(tab_Digitizer,
text = "General board registers",
font = '-weight bold',
)
lbl_general_board_registers.grid(column = 0,
row = 1,
sticky = W
)
btn_hide_general_board_registers = Button(tab_Digitizer,
text = "Hide",
font = '-weight bold',
command = lambda: hide_frame(frame_general_board_registers)
)
btn_hide_general_board_registers.grid(column = 1,
row = 1,
sticky = EW
)
btn_show_general_board_registers = Button(tab_Digitizer,
text = "Show",
font = '-weight bold',
command = lambda: show_frame_padx(frame_general_board_registers, 0, 2, EW, 0)
)
btn_show_general_board_registers.grid(column = 2,
row = 1,
sticky = EW
)
frame_general_board_registers = Frame(tab_Digitizer
)
frame_general_board_registers.columnconfigure(0, minsize=int(0.49*0.75*screen_width), weight=50)
frame_general_board_registers.columnconfigure(1, minsize=int(0.25*0.75*screen_width), weight=25)
frame_general_board_registers.columnconfigure(2, minsize=int(0.25*0.75*screen_width), weight=25)
frame_general_board_registers.config(highlightbackground="black", highlightthickness=3)
frame_general_board_registers.grid(column = 0,
row = 2,
sticky = EW,
ipadx = 0
)
populate(frame_general_board_registers, 35)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Channel settings
lbl_channel_registers = Label(tab_Digitizer,
text = "Channel registers",
font = '-weight bold'
)
lbl_channel_registers.grid(column = 0,
row = 3,
sticky = W
)
btn_hide_channel_registers = Button(tab_Digitizer,
text="Hide",
font="-weight bold",
command=lambda: hide_frame(frame_channel_registers)
)
btn_hide_channel_registers.grid(column = 1,
row = 3,
sticky = EW
)
btn_show_channel_registers = Button(tab_Digitizer,
text = "Show",
font = '-weight bold',
command = lambda: show_frame_padx(frame_channel_registers, 0, 4, W, 0)
)
btn_show_channel_registers.grid(column = 2,
row = 3,
sticky = EW
)
frame_channel_registers = Frame(tab_Digitizer
)
frame_channel_registers.grid(column = 0,
row = 4,
sticky = W
)
frame_channel_registers.columnconfigure(0, minsize=int(0.840*0.75*screen_width), weight=84)
frame_channel_registers.columnconfigure(1, minsize=int(0.075*0.75*screen_width), weight=8)
frame_channel_registers.columnconfigure(2, minsize=int(0.075*0.75*screen_width), weight=8)
frame_channel_registers.config(highlightbackground="black", highlightthickness=3)
##Channel settings - PSD
def onFrameConfigure(event):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
def handle_user_scrolling_up(event):
canvas.yview_scroll(-5, "units")
def handle_user_scrolling_down(event):
canvas.yview_scroll(5, "units")
def handle_scrollbar_scrolling(event):
canvas.configure(scrollregion=canvas.bbox("all"))
lbl_PSD_channel_registers = Label(frame_channel_registers,
text = "DPP-PSD registers",
font = (default_font.actual(), "10", "bold")
)
lbl_PSD_channel_registers.grid(column = 0,
row = 3,
ipadx = 20,
sticky = W)
btn_hide_PSD_channel_registers = Button(frame_channel_registers,
text = "Hide",
font = (default_font.actual(), "10", "bold"),
command = lambda: [hide_frame(canvas), hide_frame(myscrollbar)]
)
btn_hide_PSD_channel_registers.grid(column = 1,
row = 3,
sticky = EW
)
btn_show_PSD_channel_registers = Button(frame_channel_registers,
text = "Show",
font = (default_font.actual(), "10", "bold"),
command = lambda: [show_frame_padx(canvas, 0, 4, EW, 50), show_frame_padx(myscrollbar, 1, 4, NS, 0)])
btn_show_PSD_channel_registers.grid(column = 2,
row = 3,
sticky = EW
)
canvas = tk.Canvas(frame_channel_registers,
height = int(0.20*screen_height)
)
frame_PSD_channel_registers = Frame(canvas
)
frame_PSD_channel_registers.grid(column = 0,
row = 0,
sticky = EW
)
frame_PSD_channel_registers.bind("<Button-4>" , handle_user_scrolling_up)
frame_PSD_channel_registers.bind("<Button-5>" , handle_user_scrolling_down)
frame_PSD_channel_registers.bind("<Configure>", handle_scrollbar_scrolling)
myscrollbar=Scrollbar(frame_channel_registers ,orient="vertical", command=canvas.yview)
canvas.configure(scrollregion=canvas.bbox("all"))
myscrollbar.grid(column = 1,
row = 4,
sticky = NS,
ipadx = 0)
canvas.grid(column = 0,
row = 4,
sticky = EW,
padx = (50,0))
canvas.create_window((0, 0), window=frame_PSD_channel_registers, anchor="nw")
canvas.configure(yscrollcommand=myscrollbar.set)
canvas.columnconfigure(0, minsize=int(0.90*0.84*0.75*screen_width), weight=99)
canvas.columnconfigure(1, minsize=int(0.10*0.84*0.75*screen_width), weight=1)
frame_PSD_channel_registers.columnconfigure(0, minsize=int(0.20*0.84*0.75*screen_width), weight=20)
frame_PSD_channel_registers.columnconfigure(1, minsize=int(0.10*0.84*0.75*screen_width), weight=10)
frame_PSD_channel_registers.columnconfigure(2, minsize=int(0.60*0.84*0.75*screen_width), weight=50)
frame_PSD_channel_registers.config(highlightbackground="black", highlightthickness=1)
populate(frame_PSD_channel_registers, 35)
#This keeps the window open - has to be at the end
window.mainloop()

Creating and Getting values from tkinter check boxes using for loop

This code is a part of my project in which I have to manage the attendance of 50 (or more) students.
The thing I want is that all the checkboxes should initially be 'checked' (showing the present state) and when I uncheck random checkboxes (to mark the absent) and click the Submit button (yet to be created at the bottom of the window), I should get a list with 'entered date' as first element and the roll numbers i.e. 2018-MC-XX as other elements.
For example: ['01/08/2020', '2018-MC-7', '2018-MC-11', '2018-MC-23', '2018-MC-44']
Actually my plan is when I will get a list I will easily write it to a text file. Also, if there is another way of creating multiple scrollable checkboxes without packing them inside a canvas then please do tell!
from tkinter import *
from tkcalendar import DateEntry
root = Tk()
root.geometry('920x600+270+50')
root.minsize(920,600)
Attendance_frame = Frame(root) ### Consider it a Main Frame
Attendance_frame.pack()
attendaceBox = LabelFrame(Attendance_frame, text = 'Take Attendance', bd = 4, relief = GROOVE, labelanchor = 'n',font = 'Arial 10 bold', fg = 'navy blue', width = 850, height = 525) # A Label Frame inside the main frame
attendaceBox.pack_propagate(0)
attendaceBox.pack(pady = 15)
dateFrame = Frame(attendaceBox) # A small frame to accommodate date entry label & entry box
dateFrame.pack(anchor = 'w')
font = 'TkDefaultFont 10 bold'
date_label = Label(dateFrame, text = 'Enter Date : ', font = font).grid(row = 0, column = 0, sticky = 'w', padx = 10, pady = 10)
date_entry = DateEntry(dateFrame, date_pattern = 'dd/mm/yyyy', showweeknumbers = FALSE, showothermonthdays = FALSE)
date_entry.grid(row = 0, column = 1, sticky = 'w')
noteLabel = Label(attendaceBox, text = 'Note: Uncheck the boxes for absentees').pack(anchor = 'w', padx = 10, pady = 5)
canvas = Canvas(attendaceBox, borderwidth=0, background="#ffffff")
checkFrame = Frame(canvas, width = 100, height = 50)
vsb = Scrollbar(canvas, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.pack_propagate(0)
canvas.create_window((4,4), window=checkFrame, anchor="nw")
def onFrameConfigure(canvas):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
checkFrame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
for i in range(0,51): # A loop to create Labels of students roll numbers & names
c = Checkbutton(checkFrame, text = f"{'2018-MC-'+str(i+1)} Student {i+1}")
c.grid(row = i, column = 0, padx = 10, sticky = 'w')
mainloop()
First you need StringVar for each Checkbutton in order to get the state of the Checkbuttons later. Then you can use a list to hold the StringVars so that you can access them later. You can set the onvalue of the checkbuttons to the roll number associated to them.
Also you can use Text widget instead of Canvas+Frame. Below is an example:
import tkinter as tk
root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
text = tk.Text(frame, width=40, height=20)
text.pack(side=tk.LEFT, fill=tk.BOTH)
vars = []
for i in range(51):
rollnum = '2018-MC-'+str(i+1)
var = tk.StringVar(value=rollnum)
cb = tk.Checkbutton(text, text=rollnum, variable=var, onvalue=rollnum, offvalue='', bg='white')
text.window_create('end', window=cb)
text.insert('end', '\n')
vars.append(var)
vsb = tk.Scrollbar(frame, orient=tk.VERTICAL, command=text.yview)
vsb.pack(side=tk.RIGHT, fill=tk.Y)
text.config(yscrollcommand=vsb.set)
def submit():
# extract roll numbers for checked checkbuttons
result = [var.get() for var in vars if var.get()]
print(result)
tk.Button(root, text='Submit', command=submit).pack()
root.mainloop()

tkinter, Image does not show up unless some function added

I have written a code for a basic game but the image and shape don't show up unless I add something like item.pack() or win.mainloop() [which doesn't really make sense] but then the lines below it don't run.
When I don't have anything, the buttons show up but the image doesn't show up.
import tkinter as tk
import random
from tkinter import messagebox
win = tk.Tk()
my_label = tk.Label(win, text="Color of the Baloon Game")
my_label.pack()
my_canvas = tk.Canvas(win, width=400, height=600)
my_canvas.pack()
background_image=tk.PhotoImage(file = "CS_Game_menu.png")
background_label = tk.Label(my_canvas, image=background_image)
background_label.photo = background_image
background_label.grid(row = 0, rowspan = 10, column = 0, columnspan = 10)
def drawCircle():
color = "green"
x1 = 265
y1 = 80
diameter = 90
my_canvas.destroy()
circle_button.destroy()
quit_button.destroy()
my_label.destroy()
my_label1 = tk.Label(win, text="What is the Color of the Baloon?", font="Purisa")
my_label1.pack()
my_canvas1 = tk.Canvas(win, width=400, height=600)
my_canvas1.pack()
image1 = r"CS_Game_baloon.png"
photo1 = tk.PhotoImage(file=image1)
item = my_canvas1.create_image(200, 350, image=photo1)
shape = my_canvas1.create_oval(x1, y1, x1 + diameter, y1 + diameter+20, fill=color)
item.pack()
game1_button = tk.Button(my_canvas1, text = "Green")
game1_button.grid(row= 8, column = 3)
game1_button["command"] = lambda: messagebox.showinfo("Congratulations!", "Correct Answer!")
game2_button = tk.Button(my_canvas1, text = "Blue")
game2_button.grid(row= 8, column = 5)
game2_button["command"] = lambda: messagebox.showinfo("Sorry!", "Incorrect Answer!")
game3_button = tk.Button(my_canvas1, text = "Red")
game3_button.grid(row= 8, column = 7)
game3_button["command"] = lambda: messagebox.showinfo("Sorry", "Incorrect Answer!")
circle_button = tk.Button(win, text="New Game")
circle_button.pack()
circle_button["command"] = drawCircle
quit_button = tk.Button(win, text="Quit")
quit_button.pack()
quit_button['command'] = win.destroy
You are using both the create_... methods and grid methods on your canvas object. It won't behave as you expected.
To achieve what you want, you can create a Frame, put your buttons in it, and then use create_window method on your canvas:
def drawCircle():
...
shape = my_canvas1.create_oval(x1, y1, x1 + diameter, y1 + diameter+20, fill=color)
frame = tk.Frame(my_canvas1)
game1_button = tk.Button(frame, text = "Green")
game1_button.grid(row= 8, column = 3)
game1_button["command"] = lambda: messagebox.showinfo("Congratulations!", "Correct Answer!")
game2_button = tk.Button(frame, text = "Blue")
game2_button.grid(row= 8, column = 5)
game2_button["command"] = lambda: messagebox.showinfo("Sorry!", "Incorrect Answer!")
game3_button = tk.Button(frame, text = "Red")
game3_button.grid(row= 8, column = 7)
game3_button["command"] = lambda: messagebox.showinfo("Sorry", "Incorrect Answer!")
my_canvas1.create_window(200,500,window=frame)
And of course, add win.mainloop() to the bottom of your program if you haven't already.

Categories