草庐IT

tkinter绘制组件(35)——列表视图

Smart-Space 2023-04-04 原文

tkinter绘制组件(35)——列表视图

引言

又是一个莫名其妙的元素组件——列表视图(listview)。

这个组件在原生tkinter中没有对应控件,这是一个拓展组件。但是,在tkinter中不存在,不代表在其它UI库或框架不存在,就比如WinUI的ListView。

listview的重要性在于将若干个重复排版而又包含不同信息的元素呈现出来,避免占用主界面过多的位置。相比于listbox,listview在提供可选的基础上,为使用者提供了更丰富的信息,并做到整齐划一;对编写者,能够做到批量生成信息元素模块。

对于listview,最大的技术难点不是布局,因为看看,这都到了TinUI在CSDN上的第35篇文章了,一般的布局不会是问题。难点是:在tkinter可滚动控件中,鼠标进入子控件,传递滚动信息的问题。这个会在稍后讲解。


布局

函数结构

    def add_listview(self,pos:tuple,width=300,height=300,linew=80,bg='#f3f3f3',activebg='#eaeaea',oncolor='#3041d8',scrobg='#f8f8f8',scroc='#999999',scrooc='#89898b',num=5,command=None):#绘制列表视图,function:add_list
    '''
    pos-位置
    width-宽度
    height-高度
    linew-列表元素高度
    bg-背景色
    activebg-响应色
    oncolor-选中标识色
    scrobg-滚动条背景色
    scroc-滚动条颜色
    scrooc-滚动条响应色
    num-列表元素数量
    command-响应函数,需要一个参数接受选中项位次
    '''

列表框架

为了方便样式调控,我们使用BasicTinUI作为列表视图框架。

        nowon=-1
        ui=BasicTinUI(self,bg=bg)
        view=self.create_window(pos,window=ui,height=height,width=width,anchor='nw')
        uid='listview'+str(view)
        self.addtag_withtag(uid,view)
        scro=self.add_scrollbar((pos[0]+width+2,pos[1]),ui,height=height,bg=scrobg,color=scroc,oncolor=scrooc)
        self.addtag_withtag(uid,scro[-1])

这里之所以选择BasicTinUI,还有一个重要原因是可以使用TinUI自己的滚动条,而不是使用tkinter的,这样可以有统一性。

列表元素

这个很简单,该怎么添加就怎么添加。

        for i in range(0,num):
            item=ui.add_ui((3,endy),width=width-3,height=linew,bg=bg)
            items.append(item)
            endy+=linew+2
            item[0].bind('<Enter>',lambda event,item=item:buttonin(item))
            item[0].bind('<Button-1>',lambda event,item=item:click(item))
            item[0].bind('<Leave>',lambda event,item=item:buttonout(item))

标识元素

这里的表示元素是模仿winui的。也就是在列表元素左侧有一个高度大概为元素高度三分之一的线条,以作为标识元素。

        lineheight=linew/3
        line=ui.create_line((1,linew/3,1,linew*2/3),fill=oncolor,width=3,capstyle='round')

滚动范围和背景

滚动范围就是ui内所有元素了,而背景就不用再自己绘制了,直接使用TinUI的back

        ui.config(scrollregion=ui.bbox('all'))
        ui.move(line,0,-linew-height)
        self.add_back((),(view,scro[-1]),fg=bg,bg=bg,linew=3)

滚动信息传递

这个部分是重点,虽然不难,但是是一个需要注意的地方。

如果只为BasicTinUI绑定滚动,那这个控件基本费了。当鼠标进入某一个列表元素时,是滚不动的。

因此,需要将每一个列表元素的滚动信息都往上传。

        def bindyview(event):
            ui.yview_scroll(int(-1*(event.delta/120)), "units")
        #...
        for i in range(0,num):
            #...
            item[0].bind('<MouseWheel>',bindyview)

选择功能

这个部分参考listbox。

        def buttonin(itui):
            itui[0]['background']=activebg
        def buttonout(itui):
            if items.index(itui)!=nowon:
                itui[0]['background']=bg
        def click(itui):
            nonlocal nowon
            index=items.index(itui)
            items[nowon][0]['background']=bg
            nowon=index
            items[nowon][0]['background']=activebg
            ui.coords(line,1,index*(linew+2)+lineheight,1,index*(linew+2)+lineheight*2)
            if command!=None:
                command(nowon)

完整函数代码

    def add_listview(self,pos:tuple,width=300,height=300,linew=80,bg='#f3f3f3',activebg='#eaeaea',oncolor='#3041d8',scrobg='#f8f8f8',scroc='#999999',scrooc='#89898b',num=5,command=None):#绘制列表视图,function:add_list
        def buttonin(itui):
            itui[0]['background']=activebg
        def buttonout(itui):
            if items.index(itui)!=nowon:
                itui[0]['background']=bg
        def click(itui):
            nonlocal nowon
            index=items.index(itui)
            items[nowon][0]['background']=bg
            nowon=index
            items[nowon][0]['background']=activebg
            ui.coords(line,1,index*(linew+2)+lineheight,1,index*(linew+2)+lineheight*2)
            if command!=None:
                command(nowon)
        def bindyview(event):
            ui.yview_scroll(int(-1*(event.delta/120)), "units")
        nowon=-1
        ui=BasicTinUI(self,bg=bg)
        view=self.create_window(pos,window=ui,height=height,width=width,anchor='nw')
        uid='listview'+str(view)
        self.addtag_withtag(uid,view)
        scro=self.add_scrollbar((pos[0]+width+2,pos[1]),ui,height=height,bg=scrobg,color=scroc,oncolor=scrooc)
        self.addtag_withtag(uid,scro[-1])
        items=[]#使用列表作为存储类型,以后可能动态修改列表视图元素
        endy=0
        for i in range(0,num):
            item=ui.add_ui((3,endy),width=width-3,height=linew,bg=bg)
            items.append(item)
            endy+=linew+2
            item[0].bind('<Enter>',lambda event,item=item:buttonin(item))
            item[0].bind('<Button-1>',lambda event,item=item:click(item))
            item[0].bind('<Leave>',lambda event,item=item:buttonout(item))
            item[0].bind('<MouseWheel>',bindyview)
        lineheight=linew/3
        line=ui.create_line((1,linew/3,1,linew*2/3),fill=oncolor,width=3,capstyle='round')
        ui.config(scrollregion=ui.bbox('all'))
        ui.move(line,0,-linew-height)
        self.add_back((),(view,scro[-1]),fg=bg,bg=bg,linew=3)
        ui.bind('<MouseWheel>',bindyview)
        return ui,scro,items,uid

效果

测试代码

    lvitems=b.add_listview((1220,980))[2]
    lvcontent=(
    ('BasicTinUI','TinUI框架渲染核心','https://tinui.smart-space.com.cn'),
    ('TinUI','基于tkinter的现代元素控件框架','https://smart-space.com.cn/project/TinUI/index.html'),
    ('CSDN','中文IT技术交流平台','https://www.csdn.net/'),
    ('百度','全球领先的中文搜索引擎','https://www.baidu.com/'),
    ('Smart-Space','一个平凡的中国人','https://smart-space.com.cn')
    )
    for i in range(0,5):
        lvitems[i][2].loadxml(f'''<tinui>
        <line>
        <line>
        <title text='{lvcontent[i][0]}'></title>
        <link text='相关链接' url='{lvcontent[i][2]}'></link>
        </line>
        <line>
        <label text='{lvcontent[i][1]}'></label>
        </line>
        </line>
        </tinui>''')

最终效果


github项目

TinUI的github项目地址

pip下载

pip install tinui

结语

最近TinUI的pypi使用率上来了,但是维护频率下降了🥹。

🔆tkinter创新🔆

有关tkinter绘制组件(35)——列表视图的更多相关文章

  1. ruby - RVM 使用列表[0] - 2

    是否有类似“RVMuse1”或“RVMuselist[0]”之类的内容而不是键入整个版本号。在任何时候,我们都会看到一个可能包含5个或更多ruby的列表,我们可以轻松地键入一个数字而不是X.X.X。这也有助于rvmgemset。 最佳答案 这在RVM2.0中是可能的=>https://docs.google.com/document/d/1xW9GeEpLOWPcddDg_hOPvK4oeLxJmU3Q5FiCNT7nTAc/edit?usp=sharing-知道链接的任何人都可以发表评论

  2. Ruby on Rails regexp equals-tilde 与 array include 用于检查选项列表 - 2

    我正在使用Rails3.2.3和Ruby1.9.3p0。我发现我经常需要确定某个字符串是否出现在选项列表中。看来我可以使用Ruby数组.includemethod:或正则表达式equals-tildematchshorthand用竖线分隔选项:就性能而言,一个比另一个好吗?还有更好的方法吗? 最佳答案 总结:Array#include?包含String元素,在接受和拒绝输入时均胜出,对于您的示例只有三个可接受的值。对于要检查的更大的集合,看起来Set#include?和String元素可能会获胜。如何测试我们应该根据经验对此进行测试

  3. Ruby:如何将数组拼接成 Lisp 风格的列表? - 2

    这是我发现自己偶尔想做的事情。假设我有一个参数列表。在Lisp中,我可以像这样`(imaginary-function,@args)为了调用将数组从一个元素转换为正确数量的参数的函数。Ruby中是否有类似的功能?或者我只是在这里使用了一个完全错误的成语? 最佳答案 是的!它被称为splat运算符。a=[1,44]p(*a) 关于Ruby:如何将数组拼接成Lisp风格的列表?,我们在StackOverflow上找到一个类似的问题: https://stackov

  4. ruby-on-rails - Ruby on Rails 将列表拆分或切片为列 - 2

    @locations=Location.all#currentlistingall@locations=Location.slice(5)orLocation.split(5)使用Ruby,我试图将我的列表分成4列,每列限制为5个;然而,切片或拆分似乎都不起作用。知道我可能做错了什么吗?任何帮助是极大的赞赏。 最佳答案 您可能想使用in_groups_of:http://railscasts.com/episodes/28-in-groups-of这是RyanBates在railscast中的示例用法:

  5. Ruby 删除可枚举列表中的重复项 - 2

    ruby中有没有一个很好的方法来删除可枚举列表中的重复项(即拒绝等) 最佳答案 对于数组你可以使用uniq()方法a=["a","a","b","b","c"]a.uniq#=>["a","b","c"]所以如果你只是(1..10).to_a.uniq或%w{antbatcatant}.to_a.uniq因为无论如何,几乎所有您实现的方法都将作为Array类返回。 关于Ruby删除可枚举列表中的重复项,我们在StackOverflow上找到一个类似的问题: h

  6. ruby-on-rails - Scaffold Rails 3 View 中的外键下拉列表 - 2

    我使用脚手架和Rails3创建了2个模型。模型是位置和作业,每个作业都有一个位置。我在脚手架生成代码中创建了所需的引用调用,但是当我查看创建新作业的View时,我看到的只是一个文本框,我应该在其中添加location_id。我怎样才能让它变成下拉菜单以获得更好的用户体验? 最佳答案 想象一下,您有每个位置的titleAPI:http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/collection_select 关于r

  7. ruby - 如何在 Ruby 中创建数字列表并将其反向附加到它 - 2

    给定一个最小整数和最大整数,我想创建一个数组,它从最小值到最大值以二为单位计数,然后倒退(再次以二为单位,重复最大数)。例如,如果最小数是1,最大数是9,我想要[1,3,5,7,9,9,7,5,3,1].我试图尽可能简洁,这就是我使用单行代码的原因。在Python中,我会这样做:range(1,10,2)+range(9,0,-2)在我刚刚开始学习的Ruby中,到目前为止我所想到的是:(1..9).inject([]){|r,num|num%2==1?r这行得通,但我知道必须有更好的方法。这是什么? 最佳答案 (1..9).step

  8. ruby - Ruby 参数列表中的单个拼音/星号是什么意思? - 2

    这个问题在这里已经有了答案:nakedasteriskasparameterinmethoddefinition:deff(*)(1个回答)关闭9年前。我今天浏览了Rails3ActiveRecord源代码,发现amethodwheretheentireparameterlistwasasingleasterisk.defsave(*)我找不到很好的描述来说明它的作用(尽管我有一些基于我对splat参数的了解的想法)。它有什么作用,为什么要使用它?

  9. ruby - 在 ruby​​ 中合并两个排序列表的内置方法 - 2

    我有两个Foo对象列表。每个Foo对象都有一个时间戳,Foo.timestamp。两个列表最初都按时间戳降序排列。我想以最终列表也按时间戳降序排序的方式合并Foo对象的两个列表。实现这个并不难,但我想知道是否有任何内置的Ruby方法可以做到这一点,因为我认为内置方法会产生最佳性能。谢谢。 最佳答案 这会起作用,但不会提供很好的性能,因为它不会利用事先已经排序的列表:list=(list1+list2).sort_by(&:timestamp)我不知道有任何内置函数可以满足您的需求。 关于

  10. ruby - 从列表中生成从 n 到 m 的数字 - 2

    我将从一个例子开始;给定n=1和m=100以及一个列表[1,2,3]生成所有包含一位数和两位数的数字等等,但在这种情况下它们需要小于100。输出:-1,2,3,11,12,13,21,22,23,31,32,33然后我们停止,因为下一个数字将超过100,例如:-111,112,113,121,122,123,131,132,133,21..,.22...,23...,31,32,33正如您所注意到的,我将1,2,3,4附加到之前创建的数字,为此我使用了一个递归函数,该函数在for循环中为我的列表,它们会一直运行,直到生成的数字大于我的限制。defx(str,finish,d,c)ret

随机推荐