我有一个顶层窗口小部件,它询问用户他想产生什么窗口小部件,然后询问cnf。什么和东西都不重要。
cnf将在Scrollframe-Table-something中被问到(我真的不知道如何描述它^^')。对于该Scrollframe及其滚动条,我制作了一个Frame,因此可以轻松地左右包装它。但是,以某种方式,Scrollframe会将Tk窗口(顶层的根目录)作为主窗口。
这是代码-我找不到我的错误:
from tkinter import _cnfmerge as cnfmerge
from tkinter import *
class Scrollframe(Frame):
def __init__(self,master=None,height=200,width=200,**kw):
if 'yscrollcommand' in kw:
self.ysc=kw['yscrollcommand']
del kw['yscrollcommand']
else: ysc=None
if 'pad' in kw:
self.pad=kw['pad']
del kw['pad']
else: self.pad=0
Frame.__init__(self,height=height,width=width)
self.scrollframe=Frame(self,**kw)
self.scrollframe.place(x=0,y=0,relwidth=1)
self.config(bg=self.scrollframe['bg'])
self.bind('<Configure>',self.adopt)
self.widgets,self.scrollable={},False
def adopt(self,event=None):
if self.scrollframe.winfo_height()>self.winfo_height():
self.scrollable=True
self.scrollframe.place(y=0)
self.ysc(0,0)
else:
self.scrollable=False
self.ysc(0,1)
def addItem(self,widget=None,cnf={},**kw):
if widget:
cnf=cnfmerge((cnf,kw))
if 'width' in cnf: del cnf['width']
obj=widget(self.scrollframe,cnf)
if len(self.widgets)==0 and self.pad!=0: obj.pack(fill=X)
else: obj.pack(fill=X,pady=(self.pad,0))
id_=str(id(obj))+widget.__name__
obj.bind('<Destroy>',lambda event: self.delItem(id_),'+')
self.widgets[id_]=obj
return id_
def getItem(self,id):
return self.widgets[id]
def delItem(self,id):
try: self.widgets[id].destroy()
except TclError: del self.widgets[id]
except KeyError: pass
def yview(self,*args):
try: delta=int(args[1])
except ValueError: delta=float(args[1])
maxnegscroll=self.winfo_height()-self.scrollframe.winfo_height()
if isinstance(delta,float):
if maxnegscroll<0: self.scrollframe.place(y=int(maxnegscroll*delta))
delta=abs(int(self.scrollframe.place_info()['y'])/maxnegscroll)
self.ysc(delta,delta)
else:
delta=-delta*3
if int(self.scrollframe.place_info()['y'])+delta<maxnegscroll: self.scrollframe.place(y=maxnegscroll)
elif int(self.scrollframe.place_info()['y'])+delta>0: self.scrollframe.place(y=0)
else: self.scrollframe.place(y=int(self.scrollframe.place_info()['y'])+delta)
delta=abs(int(self.scrollframe.place_info()['y'])/maxnegscroll)
self.ysc(delta,delta)
class CreateWindow(Toplevel):
def __init__(self,master=None):
Toplevel.__init__(self,master,height=458,width=400)
self.grab_set()
self.resizable(False,False)
self.title('Neues Item')
self.vars,self.cnf,self.cnfids={},{},{}
cnf=create_dict(bg='gainsboro',width=380)
Frame(self,cnf=cnf,height=39).place(x=10,y=10)
Frame(self,cnf=cnf,height=103).place(x=10,y=59)
Frame(self,cnf=cnf,height=220).place(x=10,y=172)
bottom=Frame(self,cnf=cnf,height=46)
bottom.pack_propagate(False)
bottom.place(x=10,y=402)
var,values,self.oldwidget=StringVar(value='Frame'),list(_tkinter_widgets.keys())[2:],'Frame'
for i in range(len(values)): values[i]=values[i].__name__
Spinbox(self,values=values,textvar=var,state=READONLY,cursor='arrow',command=self.refresh,buttonuprelief=FLAT,buttondownrelief=FLAT,wrap=True).place(x=20,y=20)
self.vars['widget']=var
Label(self,text='Höhe:',bg='gainsboro',anchor=W,bd=1).place(x=20,y=69)
var=StringVar()
Entry(self,textvar=var,justify=CENTER,width=40).place(x=136,y=69)
self.vars['height']=var
Label(self,text='Breite:',bg='gainsboro',anchor=W,bd=1).place(x=20,y=98)
var=StringVar()
Entry(self,textvar=var,justify=CENTER,width=40).place(x=136,y=98)
self.vars['width']=var
var=BooleanVar(value=True)
Checkbutton(self,onvalue=True,offvalue=False,text='Farbe übernehmen (falls vorhanden)',variable=var,cursor='hand2',bg='gainsboro',activebackground='gainsboro').place(x=20,y=127)
self.vars['takecolor']=var
cnfsframe=Frame(self,height=200,width=360)
cnfsframe.pack_propagate(0)
cnfsframe.place(x=20,y=182)
sb=Scrollbar(cnfsframe)
sb.pack(fill=Y,side=RIGHT)
self.cnfs=Scrollframe(master=cnfsframe,width=360-17,height=200,yscrollcommand=sb.set)
self.cnfs.pack(fill=Y,side=LEFT)
sb.config(command=self.cnfs.yview)
for arg in _tkinter_widgets[Frame]:
id=self.cnfs.addItem(Frame,height=19,width=360)
obj=self.cnfs.getItem(id)
var=StringVar()
Entry(obj,width=35,justify=CENTER,textvar=var).place(x=146,y=0)
Label(obj,text=arg,bd=1).place(x=0,y=0)
self.cnf[arg],self.cnfids[arg]=var,id
Button(bottom,text='Bestätigen',command=self.confirm,width=12,height=1).pack(side=LEFT,padx=10,pady=10)
Button(bottom,text='Abbrechen',command=self.destroy,width=12,height=1).pack(side=RIGHT,padx=(0,10),pady=10)
def refresh(self):
self.vars['height'].set(''),self.vars['width'].set(''),self.vars['takecolor'].set(True)
for arg in _tkinter_widgets[eval(self.oldwidget)]:
self.cnfs.delItem(self.cnfids[arg])
del self.cnfids[arg],self.cnf[arg]
for arg in _tkinter_widgets[eval(self.vars['widget'].get())]:
id=self.cnfs.addItem(Frame,height=19,width=360)
obj=self.cnfs.getItem(id)
obj.pack_propagate(False)
var=StringVar()
Entry(obj,width=35,justify=CENTER,textvar=var).pack(side=RIGHT)
Label(obj,text=arg,bd=1).pack(fill=X,side=LEFT)
self.cnf[arg],self.cnfids[arg]=var,id
self.oldwidget=self.vars['widget'].get()
self.focus()
def confirm(self):
raise NotImplementedError #first I'll have to fix that scrollframe issue xD
if __name__=='__main__':
t=Tk()
cw=CreateWindow(t)
在有人问Scrollframe中的self.scrollable是干什么的之前:我将在稍后实现的MouseWheel绑定。
答案 0 :(得分:4)
在这一行中,您没有将主服务器传递给超类'__init__
:
Frame.__init__(self,height=height,width=width)
只需将其更改为:
Frame.__init__(self,master=master, height=height,width=width)
也就是说,Python的一般建议是使用super()
而不是对超类名称进行硬编码:
super().__init__(master=master, height=height, width=width)