Akascape/CTkListbox

Listbox not allowing additional items.

codedreamin opened this issue · 3 comments

Hi @Akascape ,

As usual, thank you for the great addition to customtkinter. I recently ran into a very strange issue.

I have a listbox that stores a number of curves that can be added to a graph.
image

In order to import new curves I have a dialog box with a listbox in it.
image

Once the number of imported curves no longer fits in the original listbox (in my case its 6 items) it will no longer allow items to be added to it.
image

I can also delete curve three for instance and it will populate one of the previously hidden items
image

This then affects any other listboxes that I have. If a listbox previously scrolled it still does after this occurs, but it also stops showing any items that are added afterwards.

Edit: I should note that I don't get any errors from this.

@Akascape
I did a bit more investigating and it appears that what is causing the issue is when a listbox on a different toplevel exceeds the maximum number of items that fit in any listbox on the base toplevel.

@Akascape
`import tkinter
import customtkinter
from typing import Union, Tuple, Optional
from customtkinter import CTkButton
from customtkinter import ThemeManager
from customtkinter import CTkToplevel
from CTkListbox import *

customtkinter.set_appearance_mode("dark")
customtkinter.set_default_color_theme("blue")

class TestDialog(CTkToplevel):
def init(self,
App,
fg_color: Optional[Union[str, Tuple[str, str]]] = None,
text_color: Optional[Union[str, Tuple[str, str]]] = None,
button_fg_color: Optional[Union[str, Tuple[str, str]]] = None,
button_hover_color: Optional[Union[str, Tuple[str, str]]] = None,
button_text_color: Optional[Union[str, Tuple[str, str]]] = None,
entry_fg_color: Optional[Union[str, Tuple[str, str]]] = None,
entry_border_color: Optional[Union[str, Tuple[str, str]]] = None,
entry_text_color: Optional[Union[str, Tuple[str, str]]] = None,

             title: str = "Results Settings",
             text: str = "Settings"):

    super().__init__(fg_color=fg_color)
    self._fg_color = ThemeManager.theme["CTkToplevel"]["fg_color"] if fg_color is None else self._check_color_type(fg_color)
    self._text_color = ThemeManager.theme["CTkLabel"]["text_color"] if text_color is None else self._check_color_type(button_hover_color)
    self._button_fg_color = ThemeManager.theme["CTkButton"]["fg_color"] if button_fg_color is None else self._check_color_type(button_fg_color)
    self._button_hover_color = ThemeManager.theme["CTkButton"]["hover_color"] if button_hover_color is None else self._check_color_type(button_hover_color)
    self._button_text_color = ThemeManager.theme["CTkButton"]["text_color"] if button_text_color is None else self._check_color_type(button_text_color)
    self._entry_fg_color = ThemeManager.theme["CTkEntry"]["fg_color"] if entry_fg_color is None else self._check_color_type(entry_fg_color)
    self._entry_border_color = ThemeManager.theme["CTkEntry"]["border_color"] if entry_border_color is None else self._check_color_type(entry_border_color)
    self._entry_text_color = ThemeManager.theme["CTkEntry"]["text_color"] if entry_text_color is None else self._check_color_type(entry_text_color)

    self._user_input: Union[str, None] = None
    self._running: bool = False
    self._text = text

    self.title(title)
    self.geometry(f"{400}x{300}")
    self.lift()  # lift window on top
    self.attributes("-topmost", False)  # stay on top
    self.protocol("WM_DELETE_WINDOW", lambda: self._on_closing(App))
    self.after(10, self._create_widgets(App))  # create widgets with slight delay, to avoid white flickering of background
    self.resizable(False, False)
    self.grab_set()  # make other windows not clickable

def _create_widgets(self, App):
    self._add_item_button = CTkButton(master=self, text='Add', command=lambda: self._add_item(App))
    self._add_item_button.grid(row=0, rowspan=1, column=0, columnspan=1, padx=10, pady=(25, 15))
    self._item_listbox = CTkListbox(master=self, justify='center')
    self._item_listbox.grid(row=0, rowspan=1, column=1, columnspan=1, padx=10, pady=(25, 15), sticky='nsew')
    self._update_saved_graphs_listbox(App)

def _add_item(self, App):
    App.listbox_items.append('item')
    self._update_saved_graphs_listbox(App)

def _update_saved_graphs_listbox(self, App):
    # Clear old list
    if self._item_listbox.size() > 0:
        self._item_listbox.delete("all")
    # Create new list
    for g in range(len(App.listbox_items[:])):
        self._item_listbox.insert(g, 'Item' + str(g))

def _on_closing(self, App):
    App.update_main_listbox()
    self.grab_release()
    self.destroy()

class App(customtkinter.CTk):
def init(self):
super().init()

    self.listbox_items = []
    # configure window
    self.title("CustomTkinter complex_example.py")
    self.geometry(f"{350}x{300}")

    # configure grid layout (4x4)
    self.grid_columnconfigure(0, weight=1)
    self.grid_rowconfigure((0), weight=1)

    self.open_dialog_button = customtkinter.CTkButton(self,
                                                      text='Open Dialog',
                                                      command=self.open_input_dialog_event)
    self.open_dialog_button.grid(row=0, rowspan=1, column=0, columnspan=1, padx=10, pady=(25, 15))
    self.main_listbox = CTkListbox(master=self, justify='center')
    self.main_listbox.grid(row=0, rowspan=1, column=1, columnspan=1, padx=10, pady=(25, 15), sticky='nsew')

def update_main_listbox(self):
    # Clear old list
    if self.main_listbox.size() > 0:
        self.main_listbox.delete("all")
    # Create new list
    for g in range(len(self.listbox_items[:])):
        self.main_listbox.insert(g, 'Item' + str(g))

def open_input_dialog_event(self):
    TestDialog(self)

if name == "main":
app = App()
app.mainloop()`

Here is a quick example I threw together, if you open up the dialog and add about 7 or so items then close the dialog it will add them to the main listbox and then freeze it.

@codedreamin Fixed, update the package.