有一个函数,我每次调用时都会添加一行,其中包含一个Entry,Combobox和一个Button。当我第一次调用该函数时,直到将鼠标光标移至该按钮的假定位置后该按钮才可见。 Before cursor hover After cursor hover
如果我一次调用该函数,则除第一行外,其他所有行均明显包含该按钮。我在框架内使用网格布局。
namevar = StringVar()
cbvar = StringVar()
entry = Entry(self.createTableFrame, textvariable = namevar)
cb = ttk.Combobox(self.createTableFrame, textvariable = cbvar, values= self.sqlDatatypes,
state='readonly'
)
cb.bind("<<ComboboxSelected>>", self.datatypeSelect)
cb.bind("<Return>", self.datatypeSelect)
#this segment contains the error
btn = Button(self.createTableFrame, text='Remove')
btn.bind('<Button-1>', self.deleteRowNT)
entry.grid(row=self.rowcountNT, column = 0)
cb.grid(row=self.rowcountNT, column = 1)
btn.grid(row = self.rowcountNT, column = 2)
以下是完整的代码供参考:
(该错误发生在def nextEntryTable(self)
中的函数class Tables(Scan)
中)
from tkinter import *
import tkinter as tk
from tkinter import ttk
import mysql.connector
class Scrollable(ttk.Frame):
# Make a frame scrollable with scrollbar on the right.
# After adding or removing widgets to the scrollable frame,
# call the update() method to refresh the scrollable area.
def __init__(self, frame, width=16):
scrollbar = tk.Scrollbar(frame, width=width)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y, expand=False)
self.canvas = tk.Canvas(frame, yscrollcommand=scrollbar.set)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.config(command=self.canvas.yview)
self.canvas.bind('<Configure>', self.__fill_canvas)
# base class initialization
tk.Frame.__init__(self, frame)
# assign this obj (the inner frame) to the windows item of the canvas
self.windows_item = self.canvas.create_window(0,0, window=self, anchor=tk.NW)
def __fill_canvas(self, event):
"Enlarge the windows item to the canvas width"
canvas_width = event.width
self.canvas.itemconfig(self.windows_item, width = canvas_width)
def update(self):
"Update the canvas and the scrollregion"
self.update_idletasks()
self.canvas.config(scrollregion=self.canvas.bbox(self.windows_item))
class Scan(Frame):
def __init__(self, master):
self.flag = 0 # to stop multiple instances opening
self.master = master
self.master.geometry('300x200+500+300')
self.master.title('Scan Page')
self.frame = Frame(self.master)
lablist = ['Host','User name','Password', 'Database']
self.lables, self.entries, self.svars = self.addlables(self.frame, lablist)
self.b1=Button(self.frame,text='SCAN',command=self.tableselect)
self.b1.grid(row= len(lablist))
self.master.bind('<Return>',self.tableselect)
self.message = Message(self.frame, text='Connection status',
bg ='Grey', width= 100)
self.message.grid(row = 5, column = 1)
self.frame.pack(fill='x',expand= True)
self.tables = None
def tableselect(self, event=None):
try:
self.tables.destroy()
except:
print('Nothing to destroy')
conn = self.databaseconnect()
# print( self.entries[0]["textvariable"] )
if conn != -1:
self.tables = Toplevel(self.master)
self.app = Tables(self.tables, conn)
def addlables(self, lableroot, lablelist):
lables = []
entries = []
svars = []
for labs, i in zip(lablelist, range(len(lablelist))):
l = Label(lableroot, text = labs)
l.grid(row=i)
e = Entry(lableroot)
e.grid(row=i, column = 1, columnspan = 5)
s = StringVar()
e['textvariable'] = s
lables.append(l)
entries.append(e)
svars.append(s)
svars[0].set('localhost')
svars[1].set('myproject')
svars[2].set('myproject')
return [lables, entries, svars]
def printvals(self, event):
for s in self.svars:
print(s.get())
def databaseconnect(self):
s = self.svars
try:
if s[3].get()=='':
conn = mysql.connector.connect(host=s[0].get(), user = s[1].get(),
passwd = s[2].get())
else:
conn = mysql.connector.connect(host=s[0].get(), user = s[1].get(),
passwd = s[2].get(),
database = s[3].get())
self.message.config(text='Connected', bg ='Lightgreen')
return conn
except Exception as e:
for x in e.args:
print(x)
self.message.config(text="Error Connecting", bg='Red')
# self.message.grid(row = 5)
return -1
class Tables(Scan):
def __init__(self, master, connector):
self.conn = connector
self.cursor = self.conn.cursor()
self.master = master
self.master.geometry('600x400+150+20')
self.master.title('Table Selection')
if self.conn.database == None:
print('Connected without a database')
self.dbRadiobuttonState = 'normal'
else:
print('Conneccted using ',self.conn.database,' database')
self.dbRadiobuttonState = 'disabled'
self.master.title('Database: ' + self.conn.database)
self.f1 = Frame(self.master, padx=5) ## Main frame
self.entry = Entry(self.f1)
self.data = StringVar() ##Variable to get value from the Entry bar
self.entry['textvariable'] = self.data
self.entry.pack(fill = X, pady = 10)
##Button creations segment
self.f2root = Frame(self.f1) ##Main left frame, fixed size
self.f2 = Frame(self.f2root) ##top bar for 'Open tables'
self.b1 = Button(self.f2, text = ' Open Table', command= self.openTableClick)
self.b1.pack(side = 'left')
self.b1.bind('<Return>', self.openTableClick)
self.b2 = Button(self.f2, text = ' Select Databse ', command = self.selectDatabaseClick)
self.b2.bind('<Return>', self.selectDatabaseClick)
self.b2.pack(side = 'left', expand=True)
self.f2.pack(side = 'top')
self.f22 = Frame(self.f2root) ##Bar frame below self.f2
self.b12 = Button(self.f22, text = 'Create Table ', command = self.createTableClick)
self.b12.pack(side = 'left')
self.b22 = Button(self.f22, text = 'Create Database')
self.b22.pack(side = 'left')
self.f22.pack(side = 'top')
self.f2root.pack(fill='y', side='left')
##Button creation ended
self.nb = ttk.Notebook(self.f1)
self.dbPage = ttk.Frame(self.nb)
self.setDBList()
self.tablesPage = ttk.Frame(self.nb)
self.tableList= [] #Contains a list of all the tables
self.tableFrameBuffer = [] #Contains a list of all the Frames
self.currentFrameSelected = -1
self.tableLayoutSet()
if self.dbRadiobuttonState == 'disabled':
self.createTableBuffer()
self.dbval.set( self.dbList.index( self.conn.database))
self.nb.add(self.dbPage, text = 'Databse')
self.nb.add(self.tablesPage, text = 'Tables')
self.nb.pack(expand=1, fill='both')
self.f1.pack(fill='both', expand= True)
def selectDatabaseClick(self, event=None):
print('Database: ',self.data.get())
try:
index = self.dbList.index(self.data.get())
print('Index: ', index)
self.dbval.set(index)
self.connectDB()
except:
print('Error in clicking DB Select button')
def openTableClick(self, event=None): ##Called whenever we click 'Open table'
print(self.data.get())
try:
index = self.tableList.index(self.data.get())
print('Table index: ',index)
self.tabVar.set(index+1)
self.tableSelect()
except:
print('Could not find entered table')
def createTableClick(self):
##Uses button self.b12
print('Create Table clicked')
if self.nb.winfo_ismapped():
print('Notebook state: ', self.nb.winfo_ismapped())
self.nb.pack_forget()
self.b12.config(text = 'Cancel')
self.b22.config(state='disabled')
self.createNewTableLayout()
self.newTableMF.pack(fill='both', expand=True, anchor = 'n')
else:
self.newTableMF.pack_forget()
print('Notebook state: ', self.nb.winfo_ismapped())
self.nb.pack(expand=1, fill='both')
self.b12.config(text='Create Table ')
self.b22.config(state='normal')
def setDBList(self):
self.dbList = []
self.cursor.execute("SHOW DATABASES")
self.dbval = IntVar()
self.dbval.set(-1)
i=0
for (x,) in self.cursor:
self.dbList.append(x)
rb = tk.Radiobutton(self.dbPage,
text=x,
padx = 20,
variable=self.dbval,
command=self.connectDB,
state = self.dbRadiobuttonState,
value=i)
rb.pack(anchor="nw")
i=i+1
def connectDB(self):
self.cursor.execute("USE " + self.dbList[self.dbval.get()])
print("Databse selected: " + self.conn.database)
self.master.title('Database: ' + self.conn.database)
self.createTableBuffer()
def createTableBuffer(self):
self.cursor.execute("show tables")
self.tabVar = IntVar()
##CLeanup code
for destroyableFrame in self.tableFrameBuffer:
destroyableFrame.destroy()
self.currentFrameSelected = -1
self.tableFrameBuffer = [] ##Contains the list of Frames
self.tableList = []
for (x,) in self.cursor:
if (self.cursor.rowcount -1) % 10 == 0:
# print(self.cursor.rowcount,'Frame buffer ',' added ')
tempFrame = Frame(self.tablesTopFrame)
self.tableFrameBuffer.append(tempFrame)
self.currentFrameSelected = len(self.tableFrameBuffer)-1
rb = Radiobutton(self.tableFrameBuffer[-1],
text = x,
padx=20,
pady=2,
variable = self.tabVar,
command = self.tableSelect,
value = self.cursor.rowcount)
rb.pack(anchor='w')
self.tableList.append(x) ## List of all the names of tables
if len(self.tableFrameBuffer) >0:
self.tableFrameBuffer[0].pack()
self.currentFrameSelected = 0
def tableLayoutSet(self):
self.tablesTopFrame = Frame(self.tablesPage)
self.tablesBottomFrame = Frame(self.tablesPage)
self.nextTableButton = Button(self.tablesBottomFrame, text = 'Next',
command = self.nextTableFrame, padx=10)
self.prevTableButton = Button(self.tablesBottomFrame, text = 'Previous',
command = self.prevTableFrame, padx=10)
self.prevTableButton.pack(side = 'left')
self.nextTableButton.pack( side = 'left')
self.tablesBottomFrame.pack(side = 'bottom', fill='x')
self.tablesTopFrame.pack(side = 'top', anchor = 'w')
def nextTableFrame(self):
if self.currentFrameSelected < len(self.tableFrameBuffer) -1:
self.tableFrameBuffer[self.currentFrameSelected].pack_forget()
self.tableFrameBuffer[self.currentFrameSelected + 1].pack()
self.currentFrameSelected += 1
def prevTableFrame(self):
if self.currentFrameSelected > 0:
self.tableFrameBuffer[self.currentFrameSelected].pack_forget()
self.tableFrameBuffer[self.currentFrameSelected - 1].pack()
self.currentFrameSelected -= 1
def tableSelect(self):
val = self.tabVar.get()
print(self.tableList[val - 1])
try:
self.newTableWindow.destroy()
except:
pass
self.newTableWindow = Toplevel(self.master)
self.app = TablesData(self.newTableWindow, self.cursor,
self.tableList[val - 1])
def createNewTableLayout(self):
self.sqlDatatypes = ['int', 'tinyint', 'smallint', 'mediumint', 'bigint',
'float', 'double', 'decimal',
'date','datetime','timestamp','time','year',
'char','varchar','text', 'tinytext','mediumtext','longtext','enum']
self.ntRowList = []
self.ntVarList = [] ##New Table var list
self.newTableMF = Frame(self.f1) ## New table main frame
##Top frame containing the sql command
self.topFrameNT = Frame(self.newTableMF)
lable = Label(self.topFrameNT, text='SQL Command')
self.newtableSQLcommand = StringVar()
entry = Entry(self.topFrameNT, textvariable = self.newtableSQLcommand)
lable.pack(side='left')
entry.pack(side='left', fill='x', expand=True)
self.topFrameNT.pack(side='top', fill='x')
##Bottom frame containing table names and dattatypes
self.createTableFrame = Frame(self.newTableMF, bg='red') ##Bottom frame
lable = Label(self.createTableFrame, text = 'Table name')
lable.grid(column=0, row=0, sticky='w')
self.newTableName = StringVar()
entryNewTable = Entry(self.createTableFrame, textvariable = self.newTableName)
entryNewTable.grid(row=0, column=1, sticky='w')
plusButton = Button(self.createTableFrame, text = '+', command = self.nextEntryTable)
plusButton.grid(row=0, column=2)
lable = Label(self.createTableFrame, text = 'Column Name')
lable.grid(column=0, row=1, sticky= 'w')
lable = Label(self.createTableFrame, text = 'Datatype')
lable.grid(column=1, row=1, sticky= 'w')
self.rowcountNT = 1
self.nextEntryTable()
self.createTableFrame.pack(side='bottom', fill='both', expand=True)
def nextEntryTable(self):
self.rowcountNT += 1
namevar = StringVar()
cbvar = StringVar()
entry = Entry(self.createTableFrame, textvariable = namevar)
cb = ttk.Combobox(self.createTableFrame, textvariable = cbvar, values= self.sqlDatatypes,
state='readonly'
)
cb.bind("<<ComboboxSelected>>", self.datatypeSelect)
cb.bind("<Return>", self.datatypeSelect)
btn = Button(self.createTableFrame, text='Remove')
btn.bind('<Button-1>', self.deleteRowNT)
entry.grid(row=self.rowcountNT, column = 0)
cb.grid(row=self.rowcountNT, column = 1)
btn.grid(row = self.rowcountNT, column = 2)
l = [btn.winfo_id(), entry, cb, btn]
self.ntRowList.append(l)
l = [namevar, cbvar]
self.ntVarList.append(l)
def datatypeSelect(self, event):
state = list (map(lambda var: [var[0].get(), var[1].get()], self.ntVarList))
print(state)
def deleteRowNT(self, event):
bid = event.widget.winfo_id()
for rows in self.ntRowList:
if rows[0] == bid:
index = self.ntRowList.index(rows)
break
print('Row number: ', index+1)
row = self.ntRowList[index]
row[3].destroy()
row[2].destroy()
row[1].destroy()
del(self.ntRowList[index])
print('Row deleted')
class TablesData(Tables):
def __init__(self, master, cursor, table):
self.master = master
self.cursor = cursor
self.tablename = table
self.master.geometry('500x500+50+30')
self.master.title(str(table))
self.buttonFrame = Frame(self.master)
self.buttonLayoutSet()
self.buttonFrame.pack(side='bottom', fill='x')
self.topFrame = Frame(self.master)
self.scrollableFrame = Scrollable(self.topFrame)
self.entriesframe = Frame(self.scrollableFrame)
self.entriesframe.grid()
self.displayTables()
self.topFrame.pack(fill='both', side='top', anchor='w', expand=True)
def buttonLayoutSet(self):
self.delete = Button(self.buttonFrame, text='Delete', command=self.deleteClick)
self.delete.pack(side='left')
self.edit = Button(self.buttonFrame, text='Edit', command=self.editClick)
self.edit.pack(side='left')
self.insert = Button(self.buttonFrame, text='Insert', command=self.insertClick)
self.insert.pack(side='left', padx=20)
self.delete.config(state='disabled')
self.edit.config(state='disabled')
def insertClick(self):
print('Insert')
def deleteClick(self):
print('Delete')
def editClick(self):
print('Edit')
def allSelect(self):
allVal = self.allCheck.get()
for var in self.entryVarList:
var.set(allVal)
if allVal == 1:
self.delete.config(state='normal')
else:
self.delete.config(state='disabled')
self.edit.config(state='disabled')
def displayTables(self):
self.cursor.execute('DESC '+ str(self.tablename))
self.allCheck = IntVar()
cb = Checkbutton(self.entriesframe,
onvalue=1, offvalue=0,
variable = self.allCheck,
command = self.allSelect)
cb.grid(row=0, column=0)
for heading in self.cursor:
L = Label(self.entriesframe, text=heading[0])
L.grid(row=0, column = self.cursor.rowcount)
self.cursor.execute('select * from ' + str(self.tablename))
self.entryVarList = []
for tableEntries in self.cursor:
entryVar = IntVar()
cb = Checkbutton(self.entriesframe,
onvalue=1, offvalue= 0,
variable = entryVar,
command= self.selectEntry)
cb.grid(row=self.cursor.rowcount, column=0)
self.entryVarList.append(entryVar)
for val, col in zip(tableEntries, range(1,len(tableEntries) + 1)):
L = Label(self.entriesframe, text = val)
L.grid(row=self.cursor.rowcount, column = col)
self.scrollableFrame.update()
def selectEntry(self):
state = list (map(lambda var: var.get(), self.entryVarList))
if sum(state) == 0:
self.delete.config(state='disabled')
self.edit.config(state='disabled')
elif sum(state) == 1:
self.delete.config(state='normal')
self.edit.config(state='normal')
else:
self.delete.config(state='normal')
self.edit.config(state='disabled')
if len(state) == sum(state):
self.allCheck.set(1)
else:
self.allCheck.set(0)
def main():
root = Tk()
app = Scan(root)
root.mainloop()
if __name__ == '__main__':
main()