0

Based on the excellent answer of this question: Show Large Image using Scrollbar in Python

… I have been able to create a scrollable image frame, using this code, in Windows, Python 3:

import tkinter
from PIL import ImageTk, Image

class ScrollableImage(tkinter.Canvas):
    def __init__(self, master=None, **kw):
        self.image = kw.pop('image', None)
        super(ScrollableImage, self).__init__(master=master, **kw)
        self['highlightthickness'] = 0
        self.propagate(0)  # wont let the scrollbars rule the size of Canvas
        self.create_image(0,0, anchor='nw', image=self.image)
        # Vertical and Horizontal scrollbars
        self.v_scroll = tkinter.Scrollbar(self, orient='vertical', width=6)
        self.h_scroll = tkinter.Scrollbar(self, orient='horizontal', width=6)
        self.v_scroll.pack(side='right', fill='y')
        self.h_scroll.pack(side='bottom', fill='x')
        # Set the scrollbars to the canvas
        self.config(xscrollcommand=self.h_scroll.set, 
                yscrollcommand=self.v_scroll.set)
        # Set canvas view to the scrollbars
        self.v_scroll.config(command=self.yview)
        self.h_scroll.config(command=self.xview)
        # Assign the region to be scrolled 
        self.config(scrollregion=self.bbox('all'))

        self.focus_set()
        self.bind_class(self, "<MouseWheel>", self.mouse_scroll)

    def mouse_scroll(self, evt):
        if evt.state == 0 :
            # self.yview_scroll(-1*(evt.delta), 'units') # For MacOS
            self.yview_scroll( int(-1*(evt.delta/120)) , 'units') # For windows
        if evt.state == 1:
            # self.xview_scroll(-1*(evt.delta), 'units') # For MacOS
            self.xview_scroll( int(-1*(evt.delta/120)) , 'units') # For windows

Now, I would like to add a row of checkboxes with numbers based on a given list numbers. The default option should be that all numbers are checked. One can then uncheck some numbers, and then when a bottom is pressed, all checked numbers should be stored in a new list, i.e. checked_numbers.

This is how it could look like:

enter image description here

This is what I have tried so far:

root = tkinter.Tk()


# Creating the check-boxes using a loop
numbers = [3,16,18,22,45]
for ii in numbers:
    var = tkinter.IntVar()
    c = tkinter.Checkbutton(root, text=str(ii), variable=var)
    c.pack()


# PhotoImage from tkinter only supports:- PGM, PPM, GIF, PNG format.
# To use more formats use PIL ImageTk.PhotoImage
img = tkinter.PhotoImage(file='PATH TO IMAGE')

show_image = ScrollableImage(root, image=img, width=400, height=600)
show_image.pack()

This is how it looks:

enter image description here

There are obviously a lot of flaws and things that I don't know how to implement:

  • How to assign a new variable in every loop ?
  • How to have all checked-boxes in a row instead of a column ?
  • How to store which variable has been checked ?
  • How to store the checked variables as a new list, when a button is pressed ?

Edit

I tried to use the nice answer from @ncica, which works perfectly on its own, and added the scrollable image...

import tkinter as tk
from tkinter import *

root = tk.Tk()


def read_states():
    arry = list(map(lambda var: var.get(), states))  # store which variable has been checked

    checked = []
    result=(zip(numbers,arry))
    for item in result:
        if item[1] == 1:
            checked.append(item[0]) # store the checked variables in a new list "checked"
    print ("Checked are:{}".format(checked))

states = []
numbers = [3,16,18,22,45]
for ii in numbers:
    var = IntVar()
    chk = Checkbutton(root, text=str(ii), variable=var) # assign a new variable in every loop
    chk.grid(row=1,column =numbers.index(ii)) # all checked-boxes put in a row

    states.append(var)
button = tk.Button(root, text='OK', command=read_states)
button.grid(row=1,column =len(numbers)+1)

# PhotoImage from tkinter only supports:- PGM, PPM, GIF, PNG format.
# To use more formats use PIL ImageTk.PhotoImage
img = tk.PhotoImage(file='IMAGE_FILE_PATH')

show_image = ScrollableImage(root, image=img, width=400, height=600)
show_image.pack()



root.mainloop()

...but I get the following error:

TclError                                  Traceback (most recent call last)
<ipython-input-11-1556cebf9634> in <module>()
     31 
     32 show_image = ScrollableImage(root, image=img, width=400, height=600)
---> 33 show_image.pack()
     34 
     35 

~\Anaconda3\lib\tkinter\__init__.py in pack_configure(self, cnf, **kw)
   2138         self.tk.call(
   2139               ('pack', 'configure', self._w)
-> 2140               + self._options(cnf, kw))
   2141     pack = configure = config = pack_configure
   2142     def pack_forget(self):

TclError: cannot use geometry manager pack inside . which already has slaves managed by grid

This can be resolved by replacing the line show_image.pack() with show_image.grid(row=2,column =1, columnspan=len(numbers)+1)

halfer
  • 19,824
  • 17
  • 99
  • 186
henry
  • 875
  • 1
  • 18
  • 48

1 Answers1

1
import Tkinter as tk
from Tkinter import *

root = tk.Tk()


def read_states():
    arry = list(map(lambda var: var.get(), states))  # store which variable has been checked

    checked = []
    result=(zip(numbers,arry))
    for item in result:
        if item[1] == 1:
            checked.append(item[0]) # store the checked variables in a new list "checked"
    print ("Checked are:{}".format(checked))

states = []
numbers = [3,16,18,22,45]
for ii in numbers:
    var = IntVar()
    var.set(1) # by default set Checkbuttons as checked
    chk = Checkbutton(root, text=str(ii), variable=var) # assign a new variable in every loop
    chk.grid(row=1,column =numbers.index(ii)) # all checked-boxes put in a row
    states.append(var)

button = tk.Button(root, text='OK', command=read_states) # on button clicked read_states
button.grid(row=1,column =len(numbers)+1) # put button after all Checkbuttons

root.mainloop()

output:

enter image description here

on button OK, checked objects will be printed

ncica
  • 7,015
  • 1
  • 15
  • 37
  • Thank you so much ! It works on its own, but when I try to in cooperate the scrollable image, then there is a problem. Please have a look at my edit. Thanks ! – henry May 09 '19 at 10:13
  • I see. One has to delete show_image.pack() and replace with `show_image.grid(row=2,column =1, columnspan=len(numbers)+1)`. – henry May 09 '19 at 10:19
  • Another question: How can one have all the numbers checked as default ? – henry May 09 '19 at 10:19
  • Ah, I see how to do it: `var = IntVar(value = 1)` – henry May 09 '19 at 10:28