我发现的有关tkinter的所有文档都已过时或未提供示例。但它比Qt文档更好 - 它们对我来说似乎有太奇怪的术语。 "建立索引",例如。那个有什么用?这完全是关于C ++的。我已经用Python编写了WML格式。
这是我的程序目前的样子: https://i.imgur.com/EZ8rMQ5l.png
我从:
开始import sys
from tkinter import Tk
from tkinter.ttk import *
此代码构建树视图的结构。
tree = Treeview(root,height=32)
tree["columns"]=("name","type","key","value","comment")
tree.column("#0", width=160)
tree.column("name", width=40)
tree.column("type", width=80)
tree.column("key", width=80)
tree.column("value", width=400)
tree.column("comment", width=400)
tree.heading("name", text="Name")
tree.heading("type", text="Type")
tree.heading("key", text="Key")
tree.heading("value", text="Value")
tree.heading("comment", text="Comment")
这里有一些伪代码:
selectors=dict()
if name=='dir':
return (0,3,0,0,0)
elif name=='mcr':
return (0,0,0,1,1)
elif name=='nwl':
if comment:
type='comment'
else:
type='separator'
return (0,0,0,0,1)
elif name=='str':
if key=='name':
return (0,2,2,3,1)
elif key in selectors:
type='string'
return (0,0,2,2,1)
type='speech'
return (0,0,2,1,1)
mcr名称应该具有确切的类型 - 宏。 dir有一个变量类型,str为key == name。否则,str类型取决于键。 nwl的类型取决于评论的价值。
返回值表示列#1-#5的标志总和。
1表示可手动编辑。 2表示可以从下拉菜单中选择。
标记的提取很简单:flag& 1,flag& 2。
此外,对于目录名称,#0列等于#2,但不可编辑。
我发现如果我想编辑单元格值,我应该看鼠标光标。
如果光标下的单元格是可选择的,则应在单元格的右角绘制下拉箭头。如果鼠标熄灭,则应删除箭头,如果 - 重复读取该行。
点击该箭头应绘制菜单。单击“外部”关闭菜单,单击“内部”更改单元格的值,然后关闭菜单。
如果双击单元格,如果可以编辑,则应在其上绘制编辑框。然后应该设置文本,并在编辑后 - 写回。然后应该销毁这个盒子。
如果name == dir和column == 2,那么也写入#0列。
在伪代码中,列是变量。但实际上我应该得到当前行的值。
选择器是元组的词典。 它可以包含以下值:
selectors={'name':('prestart','start','time over','last breath','die')}
如果键==名称,选择器[' name']是下拉菜单的值。
在其他键之前检查名称键,也可以手动编辑。
我说的是目前不存在的算法。我可能忘记了一些事情。
问题 - 如何在tkinter.ttk中的Microsoft Office中进行奇特的可编辑树视图?思想,我不太关心外表。
添加:这还不够。我应该能够:
添加:似乎gtk要好得多。草稿:
import sys,re
def weslen(line):
indent=0
ln=0
for char in line:
if char==" ":
ln+=1
elif char=="\t":
ln+=4
else:
break
indent+=1
return indent,ln
class WesItem(object):
keys=tuple()
def settype(self):
self.type=property(self.getType,self.setType)
def setcomment(self,comment):
self.comment=comment
#comment=stub.find('#')+1
#if comment:
# self.comment=stub[comment:-1]
# if not self.comment:
# self.comment=" "
#else:
# self.comment=""
def getvalue(self, column):
return getattr(self,self.keys[column])
def setvalue(self, column, value):
if column < 0 or column >= len(self.keys):
return False
setattr(self,self.keys[column],value)
return True
def getType(self):
return ""
def setType(self,type):
pass
def delchildren(self, position, count):
return False
class fakelist(object):
#def __repr__(self):
# if self.comment:
# return self.__repr_unc__(self)+"<#"+self.comment+">"
# return self.__repr_unc__()
def __len__(self):
return 0
def append(self,child):
pass
def extend(self,children):
pass
def insert(self,pos,child):
pass
class WesDir(WesItem,list):
keys=('type','indent','section',)
def __init__(self,indent,section):
list.__init__(self)
self.indent, self.section=indent,section
self.settype()
def __repr__(self):
return "<{0} {1}>".format(self.section, list.__repr__(self))
def getType(self):
return "dir:"+self.section
def delchildren(self, position, count):
if position < 0 or position + count > len(self):
return False
for row in range(count):
self.pop(position)
return True
def getValues(self):
return self.section,"dir",""
class WesConcat(WesItem,list):
keys=('type','indent','key','comment')
def __init__(self,indent,key,comment=''):
list.__init__(self)
self.indent, self.key, self.comment=indent, key, comment
self.settype()
def __repr__(self):
cmt=''
if self.comment:
cmt='#'+self.comment
if self.key:
return "<{0}={1}{2}>".format(self.key, list.__repr__(self),cmt)
return "<statement {0}{1}>".format(list.__repr__(self),cmt)
def getType(self):
return "cat"
def delchildren(self, position, count):
if position < 0 or position + count > len(self):
return False
for row in range(count):
self.pop(position)
return True
def getValues(self):
return self.key,self.getType(),self.comment
class WesNewline(WesItem,fakelist):
keys=('type','indent','comment',)
types=("sep","cmt")
def __init__(self,ln,comment):
self.indent=ln
self.setcomment(comment)
self.settype()
def __repr__(self):
if self.comment:
return "<#"+self.comment+">"
return "<newline>"
def getType(self):
return self.types[bool(self.comment)]
def getValues(self):
return "",self.getType(),self.comment
class WesMap(WesItem,fakelist):
keys=('type','map')
def __init__(self,map):
self.map=map
self.settype()
def getType(self):
return 'map'
def getValues(self):
return "",self.getType(),', '.join(self.compile())
def __repr__(self):
return '<map "{0}">'.format(self.compile())
def compile(self):
return ', '.join(self.map)
class WesString(WesItem,fakelist):
keys=('type','value','isspeech')
locale=("str","spk")
def __init__(self,value,speech=False):
self.value,self.isspeech=value,speech
self.settype()
def getType(self):
return self.locale[self.isspeech]
def __repr__(self):
return '<{0} "{1}">'.format(self.getType(),self.value)
def compile(self):
if self.isspeech:
return '_"{0}"'.format(self.value)
return '"{0}"'.format(self.value)
def getValues(self):
return "",self.getType(),self.value
class WesLua(WesItem,fakelist):
keys=('type','code')
def __init__(self,code):
self.code=code
self.settype()
def getType(self):
return 'lua'
def __repr__(self):
return '<<{0}>>'.format(self.code)
def compile(self):
return '<<{0}>>'.format(self.code)
def getValues(self):
return "",self.getType(),self.code
class WesOperator(WesItem,fakelist):
keys=('type','op')
def __init__(self,op):
self.op=op
self.settype()
def getType(self):
return 'ops'
def getValues(self):
return self.op,self.getType(),""
def __repr__(self):
return self.op
def compile(self):
return self.op
class WesInt(WesItem,fakelist):
keys=('type','num')
def __init__(self,num):
self.num=int(num)
self.settype()
def getType(self):
return 'int'
def getValues(self):
return "",self.getType(),str(self.num)
def __repr__(self):
return str(self.num)
def compile(self):
return str(self.num)
class WesMacro(WesItem,fakelist):
keys=('type','macro')
def __init__(self,macro):
self.macro=macro
self.settype()
def __repr__(self):
return "{"+self.macro+"}"
def compile(self):
return "{"+self.macro+"}"
def getType(self):
return "mcr"
def getValues(self):
return "",self.getType(),self.macro
class WesCfg(WesDir):
params={}#debug
extractor=re.compile('([a-z_]*)[ \t]*=[ \t]*([^\n]*)')
def __init__(self,fname):
super(WesCfg, self).__init__(0, 'root')
if isinstance(fname,list):
self.extend(fname)
else:
pointer=[]
with open(fname,'r') as f:
for line in f:
indent,ln=weslen(line)
line=line[indent:]
#print(line)
while True:
obj=self
for i in pointer:
obj=obj[i]
keyparam=self.extractor.match(line)
if keyparam:
wc=WesConcat(ln,keyparam.group(1))
g2=keyparam.group(2)
else:
wc=WesConcat(ln,'')
g2=line.rstrip('\n')
while g2:
if g2[0]=='[':
break
elif g2[0] in '_ABCDEFGHIJKLMNOPQRSTUVWXYZ' and g2[1] in '\\|/abcdefghigklmnopqrstuvwxyz':
wc.append(WesMap([tl.strip(' \t') for tl in g2.split(',')]))
g2=''
elif g2[0]=='_':#speech
g2=g2[g2.index('"')+1:]
while '"' not in g2:
g2+='\n'+next(f).rstrip('\n')
end=g2.find('"')
wc.append(WesString(g2[:end],speech=True))
g2=g2[end+1:]
elif g2[:2]=='<<':#Lua
g2=g2[2:]
while '>>' not in g2:
g2+='\n'+next(f).rstrip('\n')
end=g2.index('>>')
wc.append(WesLua(g2[:end]))
g2=g2[end+2:]
elif g2[0]=='{':#macro
while True:
oc=0
cc=0
for i,ch in enumerate(g2):
if ch in '({':
oc+=1
elif ch in ')}':
cc+=1
if oc==cc:
if '}' in g2.split(')')[-1]:
break
if oc==cc:
if '}' in g2.split(')')[-1]:
break
g2+='\n'+next(f).rstrip('\n')
wc.append(WesMacro(g2[1:i]))
g2=g2[i+1:]
elif g2[0]=='"':#string
g2=g2[1:]
while '"' not in g2:
g2+='\n'+next(f).rstrip('\n')
end=g2.find('"')
wc.append(WesString(g2[:end]))
g2=g2[end+1:]
elif g2[0] in '0123456789' or (g2[0]=='-' and g2[1] in '0123456789'):#maths
num=g2[0]
end=1
if end!=len(g2):
while g2[end] in '0123456789':
num+=g2[end]
end+=1
if end==len(g2):
break
if end==len(g2):
wc.append(WesInt(g2))
g2=''
elif g2[end] not in ' \t+-*/[#':#plain text
end=g2.find('#')
if not end:
pass
elif end==-1:
wc.append(WesString(g2))
g2=''
else:
wc.append(WesString(g2[:end]))
g2=g2[end:]
else:
wc.append(WesInt(g2[:end]))
g2=g2[end:]
else:#plain text
end=g2.find('#')
if not end:
pass
elif end==-1:
wc.append(WesString(g2))
g2=''
else:
wc.append(WesString(g2[:end]))
g2=g2[end:]
g2.lstrip(' \t')
if not g2:
break
elif g2[0]=='[':
break
elif g2[0] in '+-*/':
wc.append(WesOperator(g2[0]))
g2=g2[1:]
g2.lstrip(' \t')
elif g2[0]=='#':
wc.setcomment(g2[1:])
g2=''
else:
print('unhandled',g2)
if wc or wc.key:#is not empty
obj.append(wc)
elif g2:
pass
else:
obj.append(WesNewline(ln,wc.comment))
if g2:
assert(g2[0]=='[')
g2=g2[1:]
end=g2.index(']')
if g2[0]=='/':
assert(obj.section==g2[1:end] or (obj.section[1:]==g2[1:end] and obj.section[0]=='+'))
del pointer[-1]
else:
obj.append(WesDir(ln,g2[:end]))
pointer.append(len(obj)-1)
line=g2[end+1:]
else:
break
def add_value(self,value,obj):
if value is not None:
if value.key in ('attack_depth', 'bonus', 'canrecruit', 'carryover_percentage', 'condition', 'controller', 'fog', 'grouping', 'id', 'image', 'income', 'map_data', 'next_scenario', 'profile', 'race', 'recruit', 'result', 'shroud', 'side', 'speaker', 'team_name', 'turns', 'type', 'x', 'y', 'x,y', 'x, y', 'facing', 'background', 'music'):
assert(not value.isLocalized)
elif value.key in ('description', 'message', 'story', 'user_team_name', 'note'):
if not value.isLocalized:
pass
#print("WARNING: that should be localized: {0}={1}".format(value.key,value.value))
elif value.key=="name":
if not value.isLocalized:
if value.value[:5]!="turn ":
if value.value not in ('prestart','start','time over','last breath','die'):
pass
#print("WARNING: that should be localized: {0}={1}".format(value.key,value.value))
#else:
#print('WARNING: unrecognized key:',value)
obj.append(value)
self.params[(value.key,value.isLocalized)]=self.params.get((value.key,value.isLocalized),None)#debug
def __repr__(self):
represented=''
pointer=[0]
while pointer:
obj=self
try:
for i in pointer:
obj=obj[i]
except IndexError:
del pointer[-1]
obj=self
if not pointer:
break
for i in pointer:
obj=obj[i]
if obj.section[0]=="+":
represented+=' '*obj.indent+"[/"+obj.section[1:]+"]"
else:
represented+=' '*obj.indent+"[/"+obj.section+"]"
pointer[-1]+=1
continue
if isinstance(obj,WesDir):
represented+=' '*obj.indent+"["+obj.section+"]"
pointer.append(0)
continue
# elif isinstance(obj,WesMacro):
# represented+=' '*obj.indent+"{"+obj.macro+"}\n"
elif isinstance(obj,WesNewline):
represented+=' '*obj.indent+"\n"
elif isinstance(obj,WesConcat):
represented+=' '*obj.indent
if obj.key:
represented+=obj.key+"="
for item in obj:
represented+=item.compile()
represented+='\n'
else:
print('unhandled',type(obj),obj)
# elif isinstance(obj,WesParam):
# represented+=' '*obj.indent+obj.key+"="
# if obj.isLocalized:
# represented+=" _ "
# isSentence=(" " in obj.value and obj.key!='name') or obj.isLocalized
# if isSentence:
# represented+='"'
# represented+=obj.value
# if isSentence:
# represented+='"'
# represented+='\n'
# elif isinstance(obj,WesLua):
# represented+=' '*obj.indent
# if obj.key:
# represented+=obj.key+"="
# represented+="<<{0}>>\n".format(obj.code)
if hasattr(obj,'comment'):
if obj.comment:
represented="{0}#{1}\n".format(represented[:-1],obj.comment)
pointer[-1]+=1
return represented
def autoindent(self):#not tested
pointer=[0]
while pointer:
obj=self
try:
for i in pointer:
obj=obj[i]
except IndexError:
del pointer[-1]
obj=self
if not pointer:
break
pointer[-1]+=1
continue
if hasattr(obj,'indent'):
newindent=(len(pointer)-1)*4
if obj.indent!=newindent:
print(obj,"had indent",obj.indent,"but now have",newindent)
obj.indent=newindent
if isinstance(obj,WesDir):
pointer.append(0)
continue
pointer[-1]+=1
if __name__ == '__main__':
# wescfg=WesCfg(sys.argv[1])
# #wescfg.autoindent()
# print(wescfg)
#elif 0:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
empst=Gtk.ListStore(str)
sssst=Gtk.ListStore(str)
sssst.append(["str"])
sssst.append(["spk"])
stattp=("cmt","sep","lua","mcr","int","str","spk","")
try:
from chc import canhavechild
except:
canhavechild=dict()
chcmodels=dict()
for parentid in canhavechild:
chcmodels[parentid]=Gtk.ListStore(str)
for childid in canhavechild[parentid]:
if childid not in stattp:
chcmodels[parentid].append([childid])
wescfg=WesCfg(sys.argv[1])
#wescfg.autoindent()
print(wescfg)
win=Gtk.Window(title="WesTreeView")
store=Gtk.TreeStore(str,str,str,Gtk.ListStore)
pointer=[0]
stack=[None]
while pointer:
obj=wescfg
try:
for i in pointer:
prev=obj
obj=obj[i]
except IndexError:
del pointer[-1]
del stack[-1]
if not pointer:
break
pointer[-1]+=1
continue
if obj.getValues()[1] in ("str","spk"):
handle=store.append(stack[-1],obj.getValues()+(sssst,))
elif obj.getValues()[1] in stattp:
handle=store.append(stack[-1],obj.getValues()+(empst,))
else:
handle=store.append(stack[-1],obj.getValues()+(chcmodels.get(prev.getValues()[0],empst),))
canhavechild[prev.getValues()[0]]=canhavechild.get(prev.getValues()[0],set())|{obj.getValues()[0]}
if isinstance(obj,WesDir) or isinstance(obj,WesConcat):
pointer.append(0)
stack.append(handle)
continue
pointer[-1]+=1
#print(canhavechild)
with open("chc.py",'w') as f:
f.write("canhavechild="+repr(canhavechild))
tree = Gtk.TreeView(store)
renderer_combo = Gtk.CellRendererCombo()
renderer_combo.set_property("editable", True)
renderer_combo.set_property("has-entry", True)
renderer_combo.set_property("text-column", 0)
renderer = Gtk.CellRendererText()
renderer2 = Gtk.CellRendererText()
renderer2.set_property("editable", True)
tree.append_column(Gtk.TreeViewColumn("Name", renderer_combo, text=0, model=3))
tree.append_column(Gtk.TreeViewColumn("Type", renderer, text=1))
tree.append_column(Gtk.TreeViewColumn("Entry", renderer2, text=2))
sw=Gtk.ScrolledWindow(None,None)
sw.set_vexpand(True)
sw.set_hexpand(True)
sw.add(tree)
win.add(sw)
win.connect("destroy", Gtk.main_quit)
win.set_default_size(800,550)
#win.show_all()
#Gtk.main()