Is It possible to create multiple form fields in tkinter & python and then submit it to a out to an output textbox in a table column format

Viewed 282

So my problem is that I want to create multiple entry fields like over 30, but every time I reformat it using .pack or .grid it keeps throwing off the formatting. is there a way to fit nearly 30 entry boxes on one window without using anything like SQLite? As we can see from this code, we have 4 fields, how would you go on with shrinking the boxes to put in more entry fields like over 30.

Secondly, I want to output all the typed data entry fields to the Listbox is there a way to add a table column to the list box to show a breakdown of each entry field.

The third is it possible to move the Listbox to another tab on the same window to show all entry fields that were typed in, if so how would you do so.


Here is my current code so far

import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from datetime import *
# Import Packages
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter.scrolledtext import *
import tkinter.filedialog
from tkcalendar import Calendar, DateEntry
from tkinter import messagebox
from tkintertable import TableCanvas, TableModel
from tkinter import ttk

# Database 
#import sqlite3
import csv
window = Tk()
window.title("TESTTEST")
window.geometry("750x450")
window.config(background='black')

#style = ttk.Style(window)
#style.configure('lefttab.TNotebook', tabposition='wn',)


# TAB LAYOUT
#tab_control = ttk.Notebook(window,style='righttab.TNotebook')
 
#tab1 = ttk.Frame(tab_control)
#tab2 = ttk.Frame(tab_control)
#tab3 = ttk.Frame(tab_control)
#tab4 = ttk.Frame(tab_control)
#tab5 = ttk.Frame(tab_control)
#tab6 = ttk.Frame(tab_control)

# ADD TABS TO NOTEBOOK
#tab_control.add(tab1, text=f'{"Home":^20s}')
#tab_control.add(tab2, text=f'{"View":^20s}')
#tab_control.add(tab3, text=f'{"Search":^20s}')
#tab_control.add(tab4, text=f'{"Edit":^20s}')
#tab_control.add(tab5, text=f'{"Export":^20s}')
#tab_control.add(tab6, text=f'{"About ":^20s}')


#label1 = Label(tab1, text= 'Python RPA APP',padx=1, pady=1)
#label1.grid(column=0, row=0)
 
#label2 = Label(tab2, text= 'View',padx=5, pady=5)
#label2.grid(column=0, row=0)

#label3 = Label(tab3, text= 'Search',padx=5, pady=5)
#label3.grid(column=0, row=0)

#label4 = Label(tab4, text= 'Edit/Update',padx=5, pady=5)
#label4.grid(column=0, row=0)

#label5 = Label(tab5, text= 'Export',padx=5, pady=5)
#label5.grid(column=0, row=0)

#label6 = Label(tab6, text= 'About',padx=5, pady=5)
#label6.grid(column=0, row=0)

#tab_control.pack(expand=1, fill='both')

class Main(ttk.Frame):
    def __init__(self, parent):
        super().__init__()

        self.parent = parent

        self.punches_list = []
        self.ent1 = tk.StringVar()
        self.ent2 = tk.StringVar()
        self.ent3 = tk.StringVar()
        self.ent4 = tk.StringVar()

        self.init_ui()

    def init_ui(self):


        f = ttk.Frame()
#       ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW)
##        ttk.Label(f, text = "Entry1").pack(side=LEFT, padx=5, pady=5, anchor=NW)
##        self.txTest = ttk.Entry(f,textvariable=self.ent).pack(fill=X, padx=5, expand=True, anchor=NW)

#        ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW)
#        self.txTest1 = ttk.Entry(f, textvariable=self.ent2).pack(side=TOP, anchor=NW)

        ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW, fill=tk.BOTH, pady=5, padx=5, expand=0)
        self.txTest1 = ttk.Entry(f, textvariable=self.ent1).pack(side=TOP, anchor=NW, fill=tk.BOTH, pady=5, padx=5, expand=0)

        ttk.Label(f, text = "Entry2").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
        self.txTest2 = ttk.Entry(f, textvariable=self.ent2).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)

        ttk.Label(f, text = "Entry3").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
        self.txTest3 = ttk.Entry(f, textvariable=self.ent3).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)

        #tkinter.Label(window, text = "Username").grid(row = 0) #'username' is placed on position 00 (row - 0 and column - 0)
        #tkinter.Entry(window).grid(row = 0, column = 1) # first input-field is placed on position 01 (row - 0 and column - 1)

        ttk.Label(f, text = "Entry4").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
        self.txTest4 = ttk.Entry(f, textvariable=self.ent4).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
        

        self.lstItems = self.get_listbox(f, 140,140).pack(anchor=N)
        w = ttk.Frame()
        

        ttk.Button(w, text="Add",command=self.add_In).pack(side=TOP, anchor=NE)
        ttk.Button(w, text="Clear", command=self.clear_Out).pack(side=TOP, anchor=NE)
        ttk.Button(w, text="Close", command=self.on_close).pack(side=TOP, anchor=NE)

        #f.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
        #w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
        f.pack(side=tk.LEFT, fill=tk.BOTH, pady=5, padx=5, expand=1)
        w.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)


    def add_In(self,):
        #s = "IN {0:>30} {1}".format(str(datetime.now()), self.ent.get())
        s = self.ent1.get()
        self.set_list(s)
        s = self.ent2.get()
        self.set_list(s)
        s = self.ent3.get()
        self.set_list(s)
        s = self.ent4.get()
        self.set_list(s)
        self.ent1.set('')
        self.ent2.set('')
        self.ent3.set('')
        self.ent4.set('')

    def clear_Out(self):
        #s = "OUT {0:>29} {1}".format(str(datetime.now()), self.ent1.get())
        #field_name.set('')
        self.ent1.set('')
        self.ent2.set('')
        self.ent3.set('')
        self.ent4.set('')
        #self.set_list(s)

    def set_list(self,s):

        self.punches_list.append(s)

        self.lstItems.delete(0, tk.END)
        for i in self.punches_list:
            self.lstItems.insert(tk.END, i)

    def on_set(self):

        self.check.set(1)

    def on_close(self):
        #self.destroy()
        self.parent.on_exit()

    def get_listbox(self, container, height=750, width=600):


        sb = tk.Scrollbar(container,orient=tk.VERTICAL)

        w = tk.Listbox(container,
                    relief=tk.GROOVE,
                    selectmode=tk.BROWSE,
                    height=height,
                    width=width,
                    background = 'white',
                    font='TkFixedFont',
                    yscrollcommand=sb.set,)

        sb.config(command=w.yview)

        w.pack(side=tk.LEFT,fill=tk.BOTH, expand =1) 
        sb.pack(fill=tk.Y, expand=1)

        return w        

class App(tk.Tk):
    """Start here"""

    def __init__(self):
        super().__init__()

        self.protocol("WM_DELETE_WINDOW", self.on_exit)

        self.set_style()
        self.set_title() 
        Main(self,)     

    def set_style(self):
        self.style = ttk.Style()
        #('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
        self.style.theme_use("vista") #change to your liking :)

    def set_title(self):
        s = "{0}".format('Employee Time-Clock')
        self.title(s)
        self.destroy()

    def on_exit(self):
        window.destroy()
        #self.destroy()
        #sys.exit()
        #"""Close all"""
        #if messagebox.askokcancel( self.title(), "Do you want to quit?", parent=self):
        #    self.destroy()               

if __name__ == '__main__':
    app = App()
    app.mainloop()
1 Answers

Your code is a giant mess, brah ;D. What I gather from your question is that you need some kind of table. What I gather from your code is the table should have cells comprised of Label and Entry. You also want an interface to create entries. Below is an example of all of that. I don't really see anything to explain. It's just a bunch of Frame, Label, Entry and Button. The only real action is in Table. All that action is, is mathematically figuring out where to put the next Item. This is all really basic stuff.

import tkinter as tk
from tkinter import ttk


#the entire bottom row of the app.
#has a dependency on self.master.table ~ not good OOP
class EntryManager(tk.Frame):
    def __init__(self, master, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.grid_columnconfigure(5, weight=1)
        font='Helvetica 10 bold'

        tk.Label(self, text='Label', font=font, width=5).grid(row=0, column=0, padx=2)
        lbl = tk.Entry(self, width=10, font=font)
        lbl.grid(row=0, column=1, padx=2)

        tk.Label(self, text='Entry', font=font, width=5).grid(row=0, column=2, padx=2)
        ent = tk.Entry(self, width=25, font=font)
        ent.grid(row=0, column=3, padx=2)

        tk.Button(self, text='add', font=font, command=lambda: self.master.table.addItem(lbl.get(), ent.get())).grid(row=0, column=4, padx=2, sticky='w')

        tk.Label(self, text='rows', font=font, width=4).grid(row=0, column=5, padx=2, sticky='e')
        r = tk.Entry(self, width=4, font=font)
        r.insert('end', self.master.table.rows)
        r.grid(row=0, column=6, padx=2)

        tk.Label(self, text='cols', font=font, width=4).grid(row=0, column=7, padx=2)
        c = tk.Entry(self, width=4, font=font)
        c.insert('end', self.master.table.cols)
        c.grid(row=0, column=8, padx=2)

        tk.Button(self, text='set', font=font, command=lambda: self.master.table.setDims(r.get(), c.get())).grid(row=0, column=9, padx=2, sticky='e')


#generic scrollable frame
class ScrollFrame(tk.Frame):
    def __init__(self, master, row=0, column=0, scrollspeed=.02, **kwargs):        
        tk.Frame.__init__(self, master, **kwargs)
        self.grid(row=row, column=column, sticky='nswe')

        self.scrollspeed = scrollspeed

        self.canvas = tk.Canvas(self, highlightthickness=0)
        self.canvas.grid(column=0, row=0, sticky='nswe')

        self.v_scroll = tk.Scrollbar(self, orient='vertical', command=self.canvas.yview)
        self.v_scroll.grid(row=0, column=1, sticky='ns')

        self.canvas.configure(yscrollcommand=self.v_scroll.set)
        self.canvas.bind_all('<MouseWheel>', self.on_mousewheel)

        self.frame = tk.Frame(self.canvas, height=0)
        self.frame.grid_columnconfigure(0, weight=1)
        self.frame.bind('<Configure>', lambda e:self.canvas.configure(scrollregion=self.canvas.bbox("all")))
        self.canvas.create_window((0,0), window=self.frame, anchor="nw")

        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

    def on_mousewheel(self, event):
        self.canvas.yview_moveto(self.v_scroll.get()[0]+((-event.delta/abs(event.delta))*self.scrollspeed))


#a table cell        
class Item(tk.Frame):
    @property
    def value(self):
        return self.__value.get()

    @value.setter
    def value(self, text):
        self.__value.set(text)

    def __init__(self, master, text, value, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        tk.Label(self, text=text, width=10, font='none 8 bold').grid(row=0, column=0, pady=5, padx=5)
        self.__value = tk.StringVar(value=value)
        tk.Entry(self, textvariable=self.__value, width=25).grid(row=0, column=1, pady=5, padx=5)


#the table
class Table(ScrollFrame):
    def __init__(self, master, rows=15, cols=3, **kwargs):
        ScrollFrame.__init__(self, master, **kwargs)
        self.entries = []
        self.rows = rows
        self.cols = cols

    def addItem(self, text, value):
        if len(self.entries) < self.rows*self.cols:
            self.entries.append(Item(self.frame, text, value))
            self.entries[-1].grid(row=(len(self.entries)-1)%self.rows, column=(len(self.entries)-1)//self.rows)

    def getItem(self, row, column):
        return self.entries[self.rows*column+row].value

    def setDims(self, rows, cols):
        if rows.isnumeric():
            self.rows = int(rows)
        if cols.isnumeric():
            self.cols = int(cols)

        for ent in self.entries:
            ent.grid_forget()

        for i, ent in enumerate(self.entries):
            if i < self.rows*self.cols:
                ent.grid(row=i%self.rows, column=i//self.rows)


class App(tk.Tk):
    WIDTH, HEIGHT, TITLE = 770, 465, 'Application'

    def __init__(self):
        tk.Tk.__init__(self)
        ttk.Style().theme_use("vista")
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        self.table = Table(self, rows=20, cols=3)
        self.table.grid(row=0, column=0, sticky='nswe')

        EntryManager(self).grid(row=1, column=0, sticky='nswe', ipady=5)

        #junk for testing
        for i in range(12):
            self.table.addItem(f'entry_{i}', f'data {i}')


if __name__ == '__main__':
    app = App()
    app.config(background='black')
    app.title(App.TITLE)
    app.geometry(f'{App.WIDTH}x{App.HEIGHT}')
    #app.resizable(width=False, height=False)
    app.mainloop()

Might as well dump the table keys in the table and see what happens. The sizes and alignments of things could use some work.

enter image description here

Related