Ttk notebook too many frames causes glitch - python

I am creating a simple SQLite database viewer in Tkinter/Ttk. It consists of a ttk notebook with a table in each tab. For smaller tables, it loads fine but for tables with 1000+ rows it glitches.
How it should look:How it looks on large tables:(The white part at the top overlays other windows which is a bit weird) Is there a better way to load the tables such that this does not occur?
Code:
import tkinter as tk
import tkinter.filedialog
from tkinter import ttk
import random
class dbTable(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
def populateTable(self, data):
for n1, line in enumerate(data):
if n1 == 0: #Header
bg = "lightgray"
else:
bg = "white"
for n2, item in enumerate(line):
f = tk.Frame(self, highlightthickness = 1, highlightbackground = "black", bg = bg)
f.grid(row = n1, column = n2, sticky = "nesw")
l = tk.Label(f, bg = bg, text = item)
l.pack(padx = 3, pady = 3, fill = "both", expand = True)
if len(data) == 1:
f = tk.Label(self, text = "No data")
f.grid(row = 2, column = 0, columnspan = len(data[0]))
class DatabaseViewer(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("Database viewer")
self.loadData()
self.openViewer()
def loadData(self):
self.tables = ["example"]
self.tableHeaders = {"example":("header1","header2","header3","header4")}
randData = [(n, random.randint(10,20000000), random.randint(10,20000000), random.randint(10,20000000), random.randint(10,20000000)) for n in range(1000)]
self.tableData = {"example":randData}
def openViewer(self):
self.viewerFrm = tk.Frame(self)
self.viewerFrm.pack()
self.viewerNotebook = ttk.Notebook(self.viewerFrm)
self.viewerNotebook.pack()
for table in self.tables:
f = tkinter.Frame(self.viewerNotebook)
self.viewerNotebook.add(f, text = table)
t = dbTable(f)
t.pack(fill = "both", expand = True)
t.populateTable([self.tableHeaders[table]] + self.tableData[table])
app = DatabaseViewer()
app.mainloop()

Related

Linked data from database to a button tkinter

I am working on a project on tkinter python.
This is how my graphic interface looks like:
And I have this database.txt:
ChickenCurry,Rice,Curry,Chicken,0.ppm
ChocolateCake,Chocolate,Flour,Sugar,Eggs,1.ppm
BolognesePasta,Pasta,Beef,TomatoeSauce,Cheese,2.ppm
Really simple. 0.ppm, 1.ppm and 2.ppm are the name of 3 images, the first one is the image of chicken curry the second one of chocolate and the last one of bolognese pasta.
My project: I would like to display the image of the chicken dish when I am clicking on the button ChickenCurry, the image of the chocolate cake when I am clicking on the chocolate cake, etc...
Here is my code:
import sys
from tkinter import *
import tkinter as tk
from PIL import Image
class Application(tk.Frame):
x = 2
def __init__(self, param = None, i = None, master=None):
super().__init__(master)
self.master = master
self.pack()
self.create_widgets()
def create_widgets(self):
if (self.x == 2):
param = "coucou"
self.hi_there = tk.Label(self)
self.hi_there["text"] = param
#self.hi_there["command"] = self.say_hi
self.hi_there.pack(side="top")
self.quit = tk.Button(self, text="QUIT", fg="red",
command=self.master.destroy)
self.quit.pack(side="bottom")
# Opening file in read format
File = open('data.txt',"r")
if(File == None):
print("File Not Found..")
else:
while(True):
# extracting data from records
record = File.readline()
if (record == ''): break
data = record.split(',')
print('Name of the dish:', data[0])
self.hi_there = tk.Button(self)
self.hi_there["text"] = data[0]
self.hi_there["command"] = self.photoOfTheDish
self.hi_there.pack(side="top")
# printing each record's data in organised form
for i in range(1, len(data)-1):
print('Ingredients:',data[i])
self.hi_there = tk.Label(self)
self.hi_there["text"] = data[i]
self.hi_there.pack(side="top")
File.close()
def photoOfTheDish(self):
novi = Toplevel()
self.canvas = Canvas(novi, width = 1500, height = 1000)
self.canvas.pack(expand = YES, fill = BOTH)
File = open('data.txt',"r")
with open('data.txt') as f:
record = File.readline()
data = record.split(',')
gif1 = PhotoImage(file = data[-1].rstrip('\n'))
#image not visual
self.canvas.create_image(50, 10, image = gif1, anchor = NW)
#assigned the gif1 to the canvas object
self.canvas.gif1 = gif1
root = tk.Tk()
root.geometry("5000x2000")
app = Application(master=root)
app.mainloop()
My issue is whatever the button I am clicking on, it's always the image corresponding to "0.ppm" which is displaying. I don't know how to link the button to his set of value from the database.
Inside photoOfTheDish(), you open data.txt and read only the first line to get the image filename. Therefore you always get the 0.ppm.
You can use lambda to pass the image filename to photoOfTheDish() when creating the buttons:
def create_widgets(self):
...
else:
while True:
...
# extracting data from records
record = File.readline().rstrip() # strip out the trailing newline
...
# pass image filename to callback
self.hi_there["command"] = lambda image=data[-1]: self.photoOfTheDish(image)
...
...
def photoOfTheDish(self, image):
novi = Toplevel()
self.canvas = Canvas(novi, width = 1500, height = 1000)
self.canvas.pack(expand = YES, fill = BOTH)
self.canvas.gif1 = PhotoImage(file=image)
self.canvas.create_image(50, 10, image=self.canvas.gif1, anchor=NW)

Sqlite3 Accessing a specific record from a database from a different class and putting it into a tkinter entrybox

The function of this code is that it displays the list of records in a database with one of the fields being a button. When this button is clicked it brings the user to a new frame which displays the account information for that record.
The record information is displayed in the Record class as dat[0] and dat[1] and I have had problems with initializing this in the second class, I do not know how I would get this information to appear on the second screen.
Thanks for any help.
from tkinter import *
import sqlite3
import AddAccount
import RemoveAccount
import LogOnLib
import LoginMenu
import TrainerAccounts
class Records(object):
def __init__(self, window):
self.window = window
window.state("zoomed")
self.window.title('Trainer Accounts')
window.update_idletasks()
h = self.window.winfo_height()
w = self.window.winfo_width()
Center_h = h/2
Center_w = w/2
self.FrameRecords = Frame(window, bg = "PaleTurquoise1")
self.FrameRecords.place(x = Center_w , y = Center_h, anchor = "center", width = 1024, height = 300)
self.btn_Back = Button(self.FrameRecords, text = "Back", bg = "PaleTurquoise1", font =("Arial", "16"), command = self.Back, width = 20)
self.btn_Back.grid(row = 1, column = 4, columnspan = 5)
self.connection = sqlite3.connect(r"E:\Program\Accounts.db")
self.cur = self.connection.cursor()
self.btn_TrainerID = Label(self.FrameRecords, text = "Trainer ID", bg = "PaleTurquoise1", font =("Arial", "16"), width = 20)
self.btn_TrainerID.grid(row = 0, column = 1, columnspan = 1)
self.NameLabel = Label(self.FrameRecords, text = "Name", bg = "PaleTurquoise1", font =("Arial", "16"), width = 20)
self.NameLabel.grid(row=0, column=0)
self.showallrecords()
def showallrecords(self):
Data = self.readfromdatabase()
for index, dat in enumerate(Data):
self.row1 = Button(self.FrameRecords, text=dat[0],font =("Arial", "16"), command = self.account).grid(row=index+1, column=0)
self.row2 = Label(self.FrameRecords, text=dat[1],font =("Arial", "16")).grid(row=index+1, column=1)
def readfromdatabase(self):
self.cur.execute("SELECT * FROM Trainers")
return self.cur.fetchall()
self.btn_TrainerID = self.row1
self.NameLabel = self.row2
def Back(self):
self.FrameRecords.place_forget()
GUI = LoginMenu.Logged(self.window)
def account(self):
self.FrameRecords.place_forget()
GUI = TrainerAccounts.TrainerInfo(self.window, Records)
##########################################################################################################################################################################################
class TrainerInfo(Records):
def __init__(self, window, Records):
self.window = window
window.state("zoomed")
self.window.title('CHANGEEEE')
window.update_idletasks()
h = self.window.winfo_height()
w = self.window.winfo_width()
Center_h = h/2
Center_w = w/2
self.FrameTrainerInfo = Frame(window, bg = "PaleTurquoise1")
self.FrameTrainerInfo.place(x = Center_w , y = Center_h, anchor = "center", width = 1024, height = 300)
self.connection = sqlite3.connect(r"E:\Program\Accounts.db")
self.cur = self.connection.cursor()
self.showrecord()
def showrecord(self):
Data = self.Information()
for index, dat in enumerate(Data):
Label(self.FrameTrainerInfo, text=self.row1,font =("Arial", "16")).grid(row=index+1, column=0)
Label(self.FrameTrainerInfo, text=self.row2,font =("Arial", "16")).grid(row=index+1, column=1)
def Information(self):
self.cur.execute("SELECT * FROM Trainers WHERE row1 = '" + row1 + "'" + "AND row2 = '" + row2 + "'")
return self.cur.self.all()
Have you tried merging the two classes together ?
if you can push values from database you only need make a .insert on Entrybox
maybe like this
tkEntry = Entry( master)
tkEntry.pack() # .grid or .place, don't make this in obj create
tkEntry.insert( 0, dat[0] ) # 0 is the index and dat[0] is your value

Duplicating values in text file

I am using a text file to store values for a tkinter combobox. If the user enters a value not in the file, I want it added. Everything works fine, but if the user selects an existing value, it also is added again to the list. I believe it is because I am returning stripped values and comparing against values with '\n'. Any help on how to correct this is greatly appreciated.
from tkinter import *
from tkinter import ttk
regionList = open('regions1.txt','r')
root = Tk()
root.configure()
varRegions = StringVar(root, value='')
class MainWindow(Frame):
def __init__(self,master = None):
Frame.__init__(self,master)
self.master = master
self.grid()
self.create_widgets()
def create_widgets(self):
"""Create Window Layout"""
Boxfont = ('Arial', 12, 'bold')
self.blank = Label(self,text='').grid(row=2,column=0)
self.label = Label(self, font=Boxfont, text="Regions").grid(row=3,column=1)
self.regcombo = ttk.Combobox(self, font = Boxfont, width = 16, textvariable = varRegions)
self.regcombo.bind("<Return>", self.regcombo_onEnter)
self.regcombo.bind('<<ComboboxSelected>>',self.regcombo_onEnter)
self.regcombo['values'] = regionList.readlines()
self.regcombo.grid(row=3, column=2,sticky = W)
self.blank = Label(self,text='').grid(row=4,column=0)
def regcombo_onEnter(self,event):
varRegions.set(varRegions.get().lower().strip())
mytext = varRegions.get().strip()
vals = self.regcombo.cget('values')
self.regcombo.select_range(0,END)
print(mytext)
if not vals:
self.regcombo.configure(values = (mytext,))
elif mytext not in vals:
with open('regions1.txt','a') as f:
f.write('\n'+ mytext)
self.regcombo.configure(values = vals + (mytext,))
f.close
return 'break'
app = MainWindow(root)
root.mainloop()

Updating a Tkinter canvas with a list created inside a function

I'm developing a GUI with Tkinter and have been successful up until now. I want to update a canvas with a list created in a function (inside a class). I have the following:
class GC_data_tk(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
self.grid()
def initialize(self):
self.canvas = Tkinter.Canvas(self, width = 600, height = 400, bg = 'white').grid(column = 5, row = 1)
I want to use the self.Result list created in the following:
def result(self):
self.Result = []
filepath = self.folder
filepath1 = self.folder +"\*.csv"
print filepath
comps = float(self.no_comps.get())
no_comps = comps +2
files = glob.glob(filepath1)
dataframes = [pd.DataFrame.from_csv(f, index_col=None, header=None) for f in files]
new_dfb = pd.DataFrame()
for i, df in enumerate(dataframes):
colname = 'Run {}'.format(i+1)
selected_data = df[3].ix[0:no_comps]
new_dfb[colname] = selected_data
self.Result.append(new_dfb)
folder = filepath + "\summary.csv"
new_dfb.to_csv(folder)
print self.Result
to print to the canvas. Is it possible to do this even though the result is stored inside a function?
The function "result(self)" is called with the following:
self.button2 = Tkinter.Button(self, text = "Run", font = ("Helvetica, 12"), command = self.combine_funcs(self.tx0_to_csv,self.csv_to_csv,self.result)).grid(column = 0, row = 7, columnspan = 1, rowspan =1, padx = 5, pady=5)
The current Result outputs to cmd as:

Issue with crash in TKinter Application

I have a program running that is having issues when the timer runs. Every time "start" is hit, the application crashes. Any thoughts?
##-- Imports --##
import time
import openpyxl as xl
from Tkinter import *
##-- Classes --##
class App(Frame):
def startTimer(self):
self.check = True
self.now = time.strftime("%H:%M:%S")
while self.check == True:
self.timer.configure(text = self.now)
time.sleep(1)
def initUI(self):
self.parent.title("Emma's Time Manager")
self.pack(fill = BOTH, expand = 1)
def initWidget(self):
##Create button definitions##
self.buttonwidth = 12
self.quit = Button(self, text = "Quit", comman = self.quit, width = self.buttonwidth)
self.newClient = Button(self, text = "Add Client", command = lambda:self.newClientFunc(), width = self.buttonwidth)
self.timeStart = Button(self, text = "Start", command = lambda:self.startTimer(), width = self.buttonwidth)
self.timeEnd = Button(self, text = "End", command = lambda:self.endTimer(), width = self.buttonwidth)
self.saveBut = Button(self, text = "Save", command = lambda:self.saveFunc(), width = self.buttonwidth)
self.viewClient = Button(self, text = "View Client", command = lambda:self.viewCliFunc(), width = self.buttonwidth)
##Create lable definitions##
self.timer = Label(self, text = "00:00:00") ##self.timer used as display for timer##
##Create the listbox for Client Selection##
self.wb = xl.load_workbook("clients.xlsx")
self.clientNames = self.wb.get_sheet_names()
self.clivar = StringVar(self)
self.clivar.set(self.clientNames[0])
self.clilist = apply(OptionMenu, (self, self.clivar) + tuple(self.clientNames))
##Create Entry Box to describe work information##
self.info = Entry(self, width = 50)
##Create GUI for widgets##
self.clilist.grid(row = 0, column = 0)
self.timer.grid(row = 0, column = 1)
self.timeStart.grid(row = 0, column = 2)
self.timeEnd.grid(row = 0, column = 3)
self.info.grid(row = 1, column = 0, columnspan = 4)
self.newClient.grid(row = 2, column = 0)
self.viewClient.grid(row = 2, column = 1)
self.saveBut.grid(row = 2, column = 2)
self.quit.grid(row = 2, column = 3)
def __init__(self, parent):
Frame.__init__(self, parent, background = "light blue")
self.parent = parent
self.initUI()
self.initWidget()
def main():
try:
xl.load_workbook("clients.xlsx")
except:
temp = xl.Workbook()
temp.save("clients.xlsx")
temp.remove_sheet(temp.get_sheet_by_name("Sheet"))
root = Tk()
bob = App(root)
root.mainloop()
main()
Please note that most of the program is not yet finished. I just cannot seem to get this timer to run properly.
Looks like you have no way out of your while loop. You'll either need to set self.check to False, or break out of the loop.
while self.check == True:
self.timer.configure(text = self.now)
time.sleep(1)

Categories