• tkinter-TinUI-xml实战(6)问卷


    引言

    电子问卷可以方便地获取大量受访者态度信息,具有高效性和环保性。那么在普通的应用中,问卷可以用来做意见反馈、未来决策参考等重要的信息收集行为。

    在tkinter,并没有现成的问卷系统拓展库。那我们不妨使用TinUI来写一个简单的问卷控件,为大家作参考使用。

    该问卷控件实际上是对TinUI的操作类,不是一个完全的控件实例。本次问卷控件仅实现填写、收集等简单功能。


    声明

    本项目属于作者原创。借鉴了GitHub/TinUI上的tuxml.py,翻版必究,但可以自行添加功能代码。

    本项目使用的TinUI为我开源并维护在GitHub上的主文件——TinUI.py。当然,使用PYPI中下载安装的tinui也可以。


    文件结构

    在这里插入图片描述

    • tinui.py - TinUI核心支持

    • 问卷.py - 本次的源码文件


    核心代码

    因为本次属于动态UI元素添加,而且布局简单,所以暂时不想写TinUIXaml。

    操作类ATW是随便起的名称。

    class ATW():
    
        def __init__(self,tinui,command=None,content=[['radio','select radio',('a','b','c')],['check','select some',('1','2','3','4','5')],['input','input something','input>>'],['text','write something in textbox','text it>>'],['rating','do you like it',5]]):
            '''
            要操作的TinUI类
            点击提交按钮后执行的函数
            问卷内容
            '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    问卷内容参数设计

    问卷内容参数content采用列表式标签型文本设计。

    content=[(tag,text,val),...]
    
    • 1
    • tag 标签

      • radio 单选

      • check 多选

      • input 单行输入

      • text 文本框输入

      • rating 评星

    • text 问题文本

    • val 相应类型的选值

    获取TinUI最下方位置

    也就是取得最下方左侧点的坐标。

    def end(pady=2):
        bbox=self.ui.bbox('all')
        if bbox==None:
            return (5,5)
        else:
            return (5,bbox[3]+pady)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    初始化属性

    以下是初始化代码:

        def __init__(self,tinui,command=None,content=[['radio','select radio',('a','b','c')],['check','select some',('1','2','3','4','5')],['input','input something','input>>'],['text','write something in textbox','text it>>'],['rating','do you like it',5]]):
            self.answer=list()#结果
            self.over=False#是否结束
            self.content=content#问卷内容
            self.command=command#结束函数
            self.ui=tinui
            for i in content:#提前初始化总数据
                self.answer.append('')#初始化结果个数
            self.inputbar=list()#[(entry|text,num),...],用于最终获取内容
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    值得注意的是,输入框类无法直接获取选值,因此将它们储存到self.inputbar中,当点击提交按钮后再获取。

    元素布局

        def show(self):
            def end(pady=2):
                bbox=self.ui.bbox('all')
                if bbox==None:
                    return (5,5)
                else:
                    return (5,bbox[3]+pady)
            count=0
            for ask in self.content:
                ask[1]=str(count+1)+'. '+ask[1]
                if ask[0]=='radio':
                    self.ui.add_paragraph(end(8),text=ask[1])
                    self.ui.add_radiobox(end(),content=ask[2],command=lambda text,c=count:self.get_radio(c,text))
                elif ask[0]=='check':
                    self.answer[count]=list()
                    self.ui.add_paragraph(end(8),text=ask[1])
                    for i in ask[2]:
                        self.ui.add_checkbutton(end(),text=i,command=lambda event,text=i,c=count:self.get_check(c,text))
                elif ask[0]=='input':
                    self.ui.add_paragraph(end(8),text=ask[1])
                    entry=self.ui.add_entry(end(),width=400,text=ask[2])[0]
                    self.inputbar.append((entry,count,'entry'))
                elif ask[0]=='text':
                    self.ui.add_paragraph(end(8),text=ask[1])
                    text=self.ui.add_textbox(end(),width=400,text=ask[2],scrollbar=True)[0]
                    self.inputbar.append((text,count,'text'))
                elif ask[0]=='rating':
                    self.ui.add_paragraph(end(8),text=ask[1])
                    self.ui.add_ratingbar(end(),linew=10,num=ask[2],command=lambda rate,c=count:self.get_rating(c,rate))
                count+=1
            self.ui.add_button(end(10),text='提交答案',command=self.over_it)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    注意到checkbutton的按钮响应存在默认值event

    获取按钮值

        def get_radio(self,num,text):
            self.answer[num]=text
        def get_check(self,num,text):
            if text not in self.answer[num]:
                self.answer[num].append(text)
            else:
                self.answer[num].remove(text)
        def get_rating(self,num,rate):
            self.answer[num]=rate
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    提交响应

    这个操作需要有以下步骤:

    1. 获取文本框内容

    2. 设置self.over为True,问卷已经结束

    3. 响应给定的self.command

        def over_it(self,*e):
            for bar in self.inputbar:
                if bar[2]=='entry':
                    content=bar[0].get()
                elif bar[2]=='text':
                    content=bar[0].get(1.0,'end')
                self.answer[bar[1]]=content
            self.over=True
            if self.command!=None:
                self.command()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    编写者获取答案

    这个方法天经地义,但是,要是使用者没有提交呢?这可能又有编写者想强行获取当前答案。那么,我们再加上一个有判断的获取函数吧。

        def get(self,must=False):
            if self.over:
                return self.answer
            else:
                if must:#必须返回
                    return self.answer
                else:
                    return None
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    完整类函数

    class ATW():
    
        def __init__(self,tinui,command=None,content=[['radio','select radio',('a','b','c')],['check','select some',('1','2','3','4','5')],['input','input something','input>>'],['text','write something in textbox','text it>>'],['rating','do you like it',5]]):
            self.answer=list()
            self.over=False#是否结束
            self.content=content
            self.command=command
            self.ui=tinui
            for i in content:#提前初始化总数据
                self.answer.append('')
            self.inputbar=list()#[(entry|text,num),...]
    
        def get_radio(self,num,text):
            self.answer[num]=text
        def get_check(self,num,text):
            if text not in self.answer[num]:
                self.answer[num].append(text)
            else:
                self.answer[num].remove(text)
        def get_rating(self,num,rate):
            self.answer[num]=rate
        def over_it(self,*e):
            for bar in self.inputbar:
                if bar[2]=='entry':
                    content=bar[0].get()
                elif bar[2]=='text':
                    content=bar[0].get(1.0,'end')
                self.answer[bar[1]]=content
            self.over=True
            if self.command!=None:
                self.command()
    
        def show(self):
            def end(pady=2):
                bbox=self.ui.bbox('all')
                if bbox==None:
                    return (5,5)
                else:
                    return (5,bbox[3]+pady)
            count=0
            for ask in self.content:
                ask[1]=str(count+1)+'. '+ask[1]
                if ask[0]=='radio':
                    self.ui.add_paragraph(end(8),text=ask[1])
                    self.ui.add_radiobox(end(),content=ask[2],command=lambda text,c=count:self.get_radio(c,text))
                elif ask[0]=='check':
                    self.answer[count]=list()
                    self.ui.add_paragraph(end(8),text=ask[1])
                    for i in ask[2]:
                        self.ui.add_checkbutton(end(),text=i,command=lambda event,text=i,c=count:self.get_check(c,text))
                elif ask[0]=='input':
                    self.ui.add_paragraph(end(8),text=ask[1])
                    entry=self.ui.add_entry(end(),width=400,text=ask[2])[0]
                    self.inputbar.append((entry,count,'entry'))
                elif ask[0]=='text':
                    self.ui.add_paragraph(end(8),text=ask[1])
                    text=self.ui.add_textbox(end(),width=400,text=ask[2],scrollbar=True)[0]
                    self.inputbar.append((text,count,'text'))
                elif ask[0]=='rating':
                    self.ui.add_paragraph(end(8),text=ask[1])
                    self.ui.add_ratingbar(end(),linew=10,num=ask[2],command=lambda rate,c=count:self.get_rating(c,rate))
                count+=1
            self.ui.add_button(end(10),text='提交答案',command=self.over_it)
    
        def get(self,must=False):
            if self.over:
                return self.answer
            else:
                if must:#必须返回
                    return self.answer
                else:
                    return None
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    测试

    测试代码

    r=Tk()
    r.title('问卷系统')
    r.geometry('500x400+50+50')
    
    ui=TinUI(r)
    ui.pack(fill='both',expand=True)
    
    atw=ATW(ui,command=print_over)
    atw.show()
    
    r.mainloop()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    效果

    在这里插入图片描述


    使用测试

    问卷内容

    简单一点的设计:

    real_list=[
        ['radio','你喜欢用tkinter吗',('yes','no')],
        ['radio','你更喜欢哪个tkinter控件库',('tkinter','customtkinter','tinui')],
        ['check','你学习tkinter的途径',('课程','辅导书','网络','自己摸索')],
        ['input','你对使用tkinter的想法',''],
        ['rating','你对当前tkinter的拓展库开发情况满意程度',5]
        ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    效果

    在这里插入图片描述


    结语

    至此,我们完成了一个简单的问卷操作类,感兴趣的朋友可以在此基础上开发出一个问卷系统。关于问卷数据处理,就是仁者见仁智者见智了。

    TinUI现在有了33个正规元素控件了。

    🔆tkinter创新🔆

  • 相关阅读:
    VisualStudio[WPF/.NET]基于CommunityToolkit.Mvvm架构开发
    【JS 原型对象和构造函数有何关系】
    Java基础单元测试
    c++ || 智能指针
    PCB入门介绍与电阻电容电感类元件的创建
    Codeforces暑期训练周报(7.28~8.3)
    Springboot整合shiro安全框架+swagger
    《Head First HTML5 javascript》第7章 表单
    嵌入式Linux和stm32区别? 之间有什么关系吗?
    vue的diff算法
  • 原文地址:https://blog.csdn.net/tinga_kilin/article/details/125829428