tkinter.ttk中的可编辑树视图

时间:2018-03-03 11:13:16

标签: python-3.x tkinter

我发现的有关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中进行奇特的可编辑树视图?思想,我不太关心外表。

添加:这还不够。我应该能够:

  1. 评估树以将更改返回到文件。需要知道如何 迭代树。
  2. 将项目添加到root或目录。
  3. 删除项目和目录
  4. 添加:似乎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()
    

0 个答案:

没有答案