4

I am just getting started with tkinter widgets and am trying to create Checkbuttons with both images and text labels. Unfortunately, this cannot be done with basic Checkbutton(master=, image=, text=) as setting the image suppresses the text.

Here's a silly yet reproducible example of what I'm trying to do.

from tkinter import Tk, Frame, Checkbutton, Label
from PIL import ImageTk, Image
import requests

def getImgFromUrl(url): # using solution from : https://stackoverflow.com/a/18369957/2573061
   try:
       r = requests.get(url, stream=True)
       pilImage = Image.open(r.raw)
       phoImage = ImageTk.PhotoImage(pilImage)
       return phoImage
   except Exception as e:
       print('Error ' + repr(e) )
       return None


class AnimalPicker(Frame):
    def __init__(self):
        super().__init__()
        self.initUI()        
    
    def initUI(self):
        self.master.title("Animal Picker")

        
def main(): 
    root = Tk()
    root.geometry("250x450+300+300")
    app = AnimalPicker()
    
    imageUrls = ['http://icons.iconarchive.com/icons/martin-berube/flat-animal/64/dachshund-icon.png',
             'http://icons.iconarchive.com/icons/iconka/meow/64/cat-walk-icon.png',
             'http://icons.iconarchive.com/icons/sonya/swarm/64/Unicorn-icon.png']

    labels = ['Dog','Cat','Unicorn']
    
    images = [getImgFromUrl(x) for x in imageUrls]
    
    for i in range(len(images)):
        cb = Checkbutton(root, text=labels[i], image = images[i])
        cb.pack(anchor = 'w', padx=5,pady=5) 
    root.mainloop()  

if __name__ == '__main__':
    main()   

Gives me:

enter image description here

But I would like to have the labels "Cat", "Dog", and "Unicorn" either underneath or to the side of the images.

It's also important that the solution work for an arbitrary number of Checkbuttons, as in the for loop above.

Should I be using Grid and stacking these Checkbuttons next to Labels? I've managed to avoid learning it so far. Or is it easy to do with Pack?

Ben the Coder
  • 539
  • 2
  • 5
  • 21
C8H10N4O2
  • 18,312
  • 8
  • 98
  • 134
  • 2
    _" Unfortunately, this cannot be done with basic Checkbutton(..., image= , text= ) as setting the image suppresses the text."_ - read up on the `compound` option. – Bryan Oakley Jan 03 '18 at 22:02
  • @Bryan Doh - well, that was easy -- the answer is yours if you want it! – C8H10N4O2 Jan 03 '18 at 22:07
  • Also, a bad workaround would be to define a new class inheriting from frame including checkbutton + label + label. – Nae Jan 03 '18 at 22:17
  • This question could use better titling. – Nae Jan 03 '18 at 22:56

1 Answers1

5

I would like to have the labels ("Cat", "Dog", "Unicorn") either underneath or to the side of the images.

As suggested in Bryan's comment, this can be done by configuring compound option of Checkbutton.

Simply replace:

cb = Checkbutton(root, text=labels[i], image = images[i])

with:

cb = Checkbutton(root, text=labels[i], image = images[i], compound='left')

or set compound option to an element of ['bottom', 'center', 'left', 'right', 'top'] which is by default None:

cb['compound'] = 'top'

Below example produces an example for most Windows users:

import tkinter as tk
from PIL import Image, ImageTk

root = tk.Tk()

mypath = r"C:\Users\Public\Pictures\Sample Pictures\Koala.jpg"
img = Image.open(mypath)
glb_img = ImageTk.PhotoImage(img)
tk.Checkbutton(root, text="Koala", image=glb_img, compound='top').pack()

root.mainloop()

Also it's worth noting that importing PIL is redundant for .png format, one could use either tk.PhotoImage(data=image_data) or tk.PhotoImage(file=image_file).

Nae
  • 14,209
  • 7
  • 52
  • 79
  • Yeah, it was kind of a trivial question, but in my defense the `tkinter` docs showing in Google results are surprisingly not helpful. E.g., the same book you link to, in the [Checkbutton](http://effbot.org/tkinterbook/checkbutton.htm#reference) page, doesn't list the non-default arguments to the option. The entry `help(Checkbutton)` is too long to read in my IDE -- trying to figure out how to paginate it. – C8H10N4O2 Jan 04 '18 at 18:49
  • @C8H10N4O2 Yeah, I've read label's explanation on `compound` instead. – Nae Jan 04 '18 at 19:01