Search code examples
python-3.xsqlitetkinter

Remove curly brackets in tkinter list box


Hi I am trying to remove the curly brackets in the tkinter listbox, however I need to maintain it as a tuple so when I use curselection I can populate the entry boxes. Here is my code:

import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter.ttk import *

import sqlite3

def connect():
    conn=sqlite3.connect("Section_25_GUI_and_Postgres/books2.db")
    cur=conn.cursor()
    cur.execute("CREATE TABLE IF NOT EXISTS book (id INTEGER PRIMARY KEY, title text, author text, year integer, isbn integer)")
    conn.commit()
    conn.close()
    
def insert(title, author, year, isbn):
    conn=sqlite3.connect("Section_25_GUI_and_Postgres/books2.db")
    cur=conn.cursor()
    cur.execute("INSERT INTO book VALUES (NULL, ?, ?, ?, ?)", (title, author, year, isbn))
    conn.commit()
    conn.close()

def view():
    conn=sqlite3.connect("Section_25_GUI_and_Postgres/books2.db")
    cur=conn.cursor()
    cur.execute("SELECT * FROM book")
    rows=cur.fetchall()
    conn.close()
    return rows 

# connect()
# insert("My Book 2", "Kevin Medri", 2020, 269494945)

def get_selected_row(event):
    
    try:
        global selected_tuple
        index = li1.curselection()[0]
        selected_tuple = li1.get(index)
        print(selected_tuple)
        e1.delete(0, END)
        e1.insert(END, selected_tuple[1])
        e2.delete(0, END)
        e2.insert(END, selected_tuple[2])
        e3.delete(0, END)
        e3.insert(END, selected_tuple[3])
        e4.delete(0, END)
        e4.insert(END, selected_tuple[4])
    except IndexError:
        pass

def view_command():
    li1.delete(0, END)
    for row in view():
        li1.insert(END, row)
        
def close_command():
        window.destroy()

window = tk.Tk()

window.title('Book Case')
window.geometry('-50+50')
window.resizable(False, False)
window.attributes('-alpha',0.9)
window.configure(background='#d7e1ff')

# UI options
paddings = {'padx': 5, 'pady': 5}
entry_font = {'font': ('Arial', 10)}

# configure style globally for labels and buttons
window.style = Style(window)
window.style.configure('TLabel', anchor='e', background='#d7e1ff', font=('Arial', 10))
window.style.configure('TButton', anchor='w', background='#d7e1ff', font=('Arial', 10))

l1 = Label(window, text='Title', **entry_font)
l1.grid(row=0, column=0, **paddings)

l2 = Label(window, text='Author', **entry_font)
l2.grid(row=0, column=2, **paddings)

l3 = Label(window, text='Year', **entry_font)
l3.grid(row=1, column=0, **paddings)

l3 = Label(window, text='ISBN', **entry_font)
l3.grid(row=1, column=2, **paddings)

title_text = StringVar()
e1 = Entry(window, textvariable=title_text, **entry_font)
e1.grid(row=0, column=1, **paddings)

author_text = StringVar()
e2 = Entry(window, textvariable=author_text, **entry_font)
e2.grid(row=0, column=3, **paddings)

year_text = StringVar()
e3 = Entry(window, textvariable=year_text, **entry_font)
e3.grid(row=1, column=1, **paddings)

isbn_text = StringVar()
e4 = Entry(window, textvariable=isbn_text, **entry_font)
e4.grid(row=1, column=3, **paddings)


li1 = Listbox(window, height=13, width=35, **entry_font)
li1.grid(row=2, column=0, rowspan=6, columnspan=2, **paddings)

sb1 = ttk.Scrollbar(window, orient='vertical', command=li1.yview)
sb1.grid(row=2, column=2, rowspan=6, sticky=tk.NS, **paddings)

li1.configure(yscrollcommand=sb1.set)
sb1.configure(command=li1.yview)

li1.bind('<<ListboxSelect>>', get_selected_row)

b1 = ttk.Button(window, text='View All', command=view_command)
b1.grid(row=2, column=3, **paddings)

b6 = ttk.Button(window, text='Close', command=close_command)
b6.grid(row=7, column=3, **paddings)

window.mainloop()

Here is result of my code when I click on View All

On View All

I need the entry boxes to fill when I click on one of the items in the list box but with no curly brackets in the listbox

On click


Solution

  • Basically the reason for {} appearing is already explained: I am getting { } on the end of my output. What is causing this and how do I remove it?

    Now when you convert it to a string with ' '.join(map(str, row))) you will notice, it is fine. But when you try to insert it into the entry boxes, you will face problem because it is no longer a tuple, it is a str and using e1.insert(END, selected_tuple[1]) won't work the way you expect.

    So you need a way to convert the string back to a tuple. So you could use something like selected_tuple = selected_tuple.split(' '). But here you are splitting with every empty space. And there can be empty space between each item AND also inside the same item too, like My Book Two. So what you can do is, create two versions, one where each element is split using ' ' and other where it is split using '-' and create a link between them:

    { 'this is item one': 'this-is-item-one' }
    

    Then your view function will be like:

    mapper = {}
    
    def view_command():
        li1.delete(0, END)
        for row in view():
            items_hyphen = '-'.join(map(str, row)) # Hyphened
            items_space = ' '.join(map(str, row)) # Spaced
            
            li1.insert(END, items_space)
            
            mapper[items_space] = items_hyphen # Add to dictionary
    

    And your get function will be like:

    def get_selected_row(event):
        try:
            index = event.widget.curselection()
            selected_item_space = li1.get(index) # Get string from listbox
            selected_item_hyphen = mapper[selected_item_space] # Get corresponding hyphenated value from dictionary
            selected_list = selected_item_hyphen.split('-')[1:] # Slide to remove the ID
    
            ents = [e1, e2, e3, e4]
            for ent, value in zip(ents, selected_list): # Loop through `ents` and `selected_list` at the same time
                ent.delete(0, END) # Clear
                ent.insert(END, value) # Then insert
    
        except IndexError:
            pass
    

    Alternatively, instead of using hyphened value, you could store the tuple itself as said by @acw1668:

    def get_selected_row(event):
        try:
            ...
            selected_item_tuple = mapper[selected_item_space] # Get corresponding tuple from dictionary
            ...
            for ent,value in zip(ents, selected_item_tuple):
                ...
    
        except IndexError:
            pass
    
    def view_command():
        li1.delete(0, END)
        for row in view():
            items_space = ' '.join(map(str, row)) # Spaced
            li1.insert(END, items_space)
            
            mapper[items_space] = row # Add to dictionary