Akascape / CTkListbox

A simple listbox for customtkinter (extenstion/add-on)
MIT License
130 stars 14 forks source link

Listbox not allowing additional items. #20

Closed codedreamin closed 6 months ago

codedreamin commented 9 months ago

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.

codedreamin commented 9 months ago

@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.

codedreamin commented 9 months ago

@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.

Akascape commented 6 months ago

@codedreamin Fixed, update the package.