tkinter的复选框在限定高度内通过滚动条查看

img


如上图所示

现有的源代码,请问如何修改成我需要的样子


import threading
import tkinter as tk
from datetime import datetime
from tkinter import ttk

from 根据系统单号打印单个标签v2 import print_label_v2

root = tk.Tk()
root.title('小助手 v0.0.2')
root.geometry('650x500+100+100')
"""左边布局"""
left_frame = tk.Frame(root)
left_frame.pack(side=tk.LEFT, anchor=tk.N, padx=5, pady=5)

"""左边布局 标签打印"""
net_frame = tk.LabelFrame(left_frame, text='标签打印', padx=5, pady=5)
net_frame.pack()

tk.Label(net_frame, text='(1)订单状态').pack(anchor=tk.W)
socket_type = ttk.Combobox(net_frame)
socket_type['values'] = ['打单配货', '批量称重']
socket_type.current(0)
socket_type.pack(anchor=tk.W)

tk.Label(net_frame, text='(2)查询范围').pack(anchor=tk.W)
socket_host = ttk.Combobox(net_frame)
socket_host['values'] = ['7日内', '30日内']
socket_host.current(0)
socket_host.pack(anchor=tk.W)

tk.Label(net_frame, text='(3)打印数量').pack(anchor=tk.W)
socket_host = ttk.Combobox(net_frame)
socket_host['values'] = ['1', '2', '3', '4', '5', '6']
socket_host.current(1)
socket_host.pack(anchor=tk.W)

tk.Label(net_frame, text='(4)系统单号').pack(anchor=tk.W)
entry_port = ttk.Entry(net_frame)
entry_port.pack(fill=tk.X)


# 获取文本框输入
def getTextInput():
    result = entry_port.get()  # 获取文本输入框的内容
    print(result)  # 输出结果


# 获取打印标签数量
def getPrintNum():
    print_num = socket_host.get()
    return print_num


def thread_it(func, *args, on_finished=None):
    """将函数打包进线程"""

    def wrapped_func():
        # 调用函数并获取返回值
        result = func(*args)
        # 如果提供了on_finished回调函数,则调用它并将返回值传递给它
        if on_finished:
            on_finished(result)

    # 创建线程
    t = threading.Thread(target=wrapped_func)
    # 设置守护线程
    t.daemon = True
    # 启动线程
    t.start()


# 当按钮被点击的时候执行click_button()函数
def click_button(print_num):
    result = entry_port.get().strip('\n').strip()  # 获取文本输入框的内容
    print(result, type(result))  # 输出结果

    # 限制按钮在程序运行中不能重复点击
    global print_button
    print_button.config(state=tk.DISABLED)
    close_button.config(state=tk.DISABLED)
    global send_area
    if result.find('XD') != -1:
        print_label_v2(trade_no=result, print_num=print_num)
        send_area.insert(tk.END,
                         f'>>>{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}\t系统单号:{result}已打印\n')
        entry_port.delete(0, 999)
    else:
        send_area.insert(tk.END, f'请输入正确的系统单号!\n')
    print_button.config(state=tk.NORMAL)
    close_button.config(state=tk.NORMAL)


# 按钮
button_frame = tk.Frame(net_frame)
button_frame.pack()

print_button = tk.Button(button_frame, text='打印', bg='#7CCD7C',
                         command=lambda: thread_it(click_button, getPrintNum()))
close_button = tk.Button(button_frame, text='忽略')
print_button.pack(side=tk.LEFT)
close_button.pack(side=tk.RIGHT)

"""左边布局 使用说明"""
recv_frame = tk.LabelFrame(left_frame, text='使用说明', padx=5, pady=5)
recv_frame.pack(side=tk.TOP, anchor=tk.N, fill=tk.X)
tk.Radiobutton(recv_frame, text='方式1:勾选待打单>打印').pack(anchor=tk.W)
tk.Radiobutton(recv_frame, text='方式2:输入单号>打印').pack(anchor=tk.W)

"""右边布局"""
right_frame = tk.Frame(root)
right_frame.pack(side=tk.TOP, padx=5, pady=5)

info_frame = tk.Frame(right_frame)
info_frame.pack()
tk.Label(info_frame, text='待打印订单').pack(anchor=tk.W)
#
# text_pad = tk.Text(info_frame, width=62)
# text_pad.pack(side=tk.LEFT, fill=tk.X)

# send_text_bar = tk.Scrollbar(info_frame)
# send_text_bar.pack(side=tk.RIGHT, fill=tk.Y)


"""待打印订单列表"""


class Checklist(tk.Frame):
    def __init__(self, master, options):
        super().__init__(master)

        self.vars = []

        for option in options:
            var = tk.BooleanVar(value=False)
            item = tk.Checkbutton(self, text=option, variable=var)
            item.pack(side="top", anchor="w")
            self.vars.append(var)

    def state(self):
        return [var.get() for var in self.vars]


class App(tk.Frame):
    def __init__(self, master):
        super().__init__(master)

        self.options = ["option 1", "option 2", "option 3", "option 4", "option 5", "option 1", "option 2", "option 3",
                        "option 4", "option 5"]

        self.checklist = Checklist(self, self.options)
        self.checklist.pack(side="left", fill="x", expand=True)

        # self.button = tk.Button(self, text="Submit", command=self.submit)
        # self.button.pack(side="bottom")

    def submit(self):
        print(self.checklist.state())


app = App(info_frame)
app.pack(side="top", fill="both", expand=True)

tk.Label(right_frame, text='信息日志').pack(anchor=tk.W)
send_frame = tk.Frame(right_frame)
send_frame.pack()

send_area = tk.Text(send_frame, width=58, height=6)
send_area.pack(side=tk.LEFT)
send_button = tk.Button(send_frame, text='清除', width=5)
send_button.pack(side=tk.RIGHT, fill=tk.Y)
root.mainloop()

根据要求,提供以下程序:

from tkinter import *
from tkinter import ttk


class ListView():
    char_ct = '☑'  # 复选框选中标识符
    chat_cf = '□'  # 复选框未选中标识符

    def __init__(self, tk, x=0, y=0, height=400, width=600):
        self.tk = tk
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.rows_count = 0
        self.cols_count = 0
        self.head_tags = ['index']
        self.head_widths = [50]
        self.head_texts = ['']
        self.tree = None
        self.__created = False  # 控制表格创建后,停用部分方法
        self.__check_boxes = True  # 标识是否有复选框功能
        self.__show_index = True  # 标识是否显示行号

    def create_listview(self):
        """
        设置好列后,执行这个函数显示出控件
        """
        if self.__created:
            print('不能再次创建!')
        else:
            self.__created = True
            self.cols_count = len(self.head_tags) - 1  # 第一列用作索引了

            frame1 = Frame(self.tk, relief=RAISED)
            frame1.place(height=self.height, width=self.width, x=self.x, y=self.y)
            frame1.propagate(0)  # 使组件大小不变,此时width才起作用

            # 定义listview
            self.tree = ttk.Treeview(frame1, columns=self.head_tags, show='headings')
            self.tree.column(self.head_tags[0], width=self.head_widths[0], anchor='center')  # stretch=YES怎么用
            for i in range(1, len(self.head_tags)):
                self.tree.column(self.head_tags[i], width=self.head_widths[i], anchor='center')
                self.tree.heading(self.head_tags[i], text=self.head_texts[i])

            # 设置垂直滚动条
            vbar = ttk.Scrollbar(frame1, orient=VERTICAL, command=self.tree.yview)
            self.tree.configure(yscrollcommand=vbar.set)
            # self.tree.grid(row=0, column=0, sticky=NSEW)
            self.tree.grid(row=0, column=0)
            vbar.grid(row=0, column=1, sticky=NS)

            # 设置水平滚动条
            hbar = ttk.Scrollbar(frame1, orient=HORIZONTAL, command=self.tree.xview)
            self.tree.configure(xscrollcommand=hbar.set)
            hbar.grid(row=1, column=0, sticky=EW)

            # 绑定事件
            self.tree.bind('<ButtonRelease-1>', self.on_click)  # 绑定行单击事件
            self.tree.bind("<Double-1>", self.on_db_click)  # 绑定双击事件

    def add_column(self, text='', width=100):
        """
        增加一列,应该在show()前面设定,后面就无效了
        :param text: 表头文字
        :param width: 列宽度
        """
        if self.__created:
            print('表格已经创建,在增加的列无效!')
        else:
            self.head_tags.append(len(self.head_tags))
            self.head_widths.append(width)
            self.head_texts.append(text)

    def add_row_char(self, check_char=char_ct, vals=''):
        """
        在最后增加一行
        """
        if self.__check_boxes:
            if check_char != ListView.char_ct:
                check_char = ListView.chat_cf
            index = '%s%d' % (check_char, self.rows_count + 1)
        else:
            index = self.rows_count + 1

        values = [index]
        for v in vals:
            values.append(v)
        self.tree.insert('', 'end', values=values)
        self.rows_count += 1

    def add_row(self, check_bl=True, vals=''):
        """
        在最后增加一行
        """
        check_char = self.check_bl2char(check_bl)
        self.add_row_char(check_char, vals)

    def set_check(self, state=True):
        """
        设置是否有复选功能
        """
        if self.__created:
            print('表格创建后,不能设置复选状态!')
        else:
            self.__check_boxes = state

    def set_width(self, col_num, width):
        """
        设置列宽
        :param col_num: 列号
        :param width: 宽度
        """
        self.tree.column("#%d" % col_num, width=width)  # 可以动态改变列宽

    def get_row(self, row_num):
        """
        获取一行的对象,供tree.item调用
        :param row_num:行号
        :return: 行对象
        """
        if row_num in range(1, self.rows_count + 1):
            items = self.tree.get_children()
            for it in items:
                index = self.get_index_by_item(it)
                if int(index) == int(row_num):
                    return it

    def get_row_values_by_item(self, item):
        """
        获取一行的值内容,包含行头部信息
        :param row_num: 行号
        :return: 元组,1为头部信息,1以后为表格信息
        """
        values = self.tree.item(item, 'values')
        return values

    def get_row_vals_head(self, row_num):
        """
        获取一行的值内容,包含行头部信息
        :param row_num: 行号
        :return: 元组,1为头部信息,1以后为表格信息
        """
        item = self.get_row(row_num)
        return self.get_row_values_by_item(item)

    def get_row_vals_by_item(self, item):
        """
        获取一行的表格内容
        :param item: 对象
        :return: 列表,索引从0开始
        """
        values = self.tree.item(item, 'values')
        vals = []
        for i in range(1, len(values)):
            vals.append(values[i])
        return vals

    def get_row_vals(self, row_num):
        """
        获取一行的表格内容
        :param row_num: 行号
        :return: 列表,索引从0开始
        """
        item = self.get_row(row_num)
        return self.get_row_vals_by_item(item)

    def get_row_head(self, row_num):
        """
        获取一行的表头内容,包含复选框和索引
        :param row_num: 行号
        :return: 字符串
        """
        row_vals = self.get_row_vals_head(row_num)
        return row_vals[1]

    def get_index_by_values(self, values):
        """
        获取一行的索引
        :param values: 行数据(包含行头部信息)
        :return: 索引(整数)
        """
        if self.__check_boxes:
            index = values[0][1:]
        else:
            index = values[0]
        return index

    def get_index_by_item(self, item):
        """
        获取一行的索引
        :param by_item: 行对象
        :return: 索引(整数)
        """
        values = self.tree.item(item, 'values')
        return self.get_index_by_values(values)

    def get_index(self, row_num):
        """
        获取一行的索引
        :param row_num: 行号
        :return: 索引(整数)
        """
        item = self.get_row(row_num)
        return self.get_index_by_item(item)

    def get_index_select(self):
        """
        获取选中行的行号
        :return: 行号
        """
        try:
            item = self.tree.selection()[0]  # 获取行对象
        except Exception:
            return 1
        return self.get_index_by_item(item)

    def get_checkbl_by_values(self, values):
        """
        获取某一行的勾选状况
        :param values: 行数据(包含行头部信息)
        """
        if self.__check_boxes:
            check_str = values[0][0:1]
            if check_str == ListView.char_ct:
                return True
            else:
                return False

    def get_checkbl_by_item(self, item):
        """
        获取某一行的勾选状况
        :param item: 行对象
        """
        values = self.get_row_values_by_item(item)
        return self.get_checkbl_by_values(values)

    def get_check_bl(self, row_num):
        """
        获取某一行的勾选状况
        :param row_num: 行号
        """
        item = self.get_row(row_num)
        return self.get_checkbl_by_item(item)

    def get_check_char(self, row_num):
        """
        获取某一行的勾选符号
        :param item: 行对象
        """
        item = self.get_row(row_num)
        return self.get_checkchar_by_item(item)

    def change_check_by_item(self, item, check_bl=True):
        """
        修改一行的复选状态
        :param item: 行对象
        :param check_bl:复选状态
        """
        if self.__check_boxes:
            check_char = self.check_bl2char(check_bl)
            index = self.get_index_by_item(item)
            value = '%s%s' % (check_char, index)
            col_str = '#%d' % 1
            self.tree.set(item, column=col_str, value=value)

    def change_check_by_item_char(self, item, check_char=char_ct):
        """
        修改一行的复选状态
        :param item: 行对象
        :param check_char:复选字符
        """
        if self.__check_boxes:
            index = self.get_index_by_item(item)
            value = '%s%s' % (check_char, index)
            col_str = '#%d' % 1
            self.tree.set(item, column=col_str, value=value)

    #
    def exchange_check_by_item(self, item):
        """
        变换一行的复选状态
        """
        if self.__check_boxes:
            vals = self.get_row_values_by_item(item)
            check_str = vals[0][0:1]
            index = vals[0][1:]
            if check_str == ListView.char_ct:
                value = ListView.chat_cf + index
            else:
                value = ListView.char_ct + index
            col_str = '#%d' % 1
            self.tree.set(item, column=col_str, value=value)  # 修改单元格的值

    def change_check_on_select(self):
        """
        改变选中行的勾选状态
        """
        try:
            item = self.tree.selection()[0]  # 获取行对象
        except Exception:
            pass
        else:
            self.exchange_check_by_item(item)

    def check_bl2char(self, bl=True):
        """
        返回复选框符号
        :param bl: True代表已选,False未选中
        :return: 复选框
        """
        if bl:
            return ListView.char_ct
        else:
            return ListView.chat_cf

    def check_char2bl(self, char=char_ct):
        """
        返回复选框符号
        :param char: ☑代表已选
        :return: 复选框
        """
        if char == ListView.char_ct:
            return True
        else:
            return False

    def on_click(self, event):
        """
        行单击事件
        """
        self.change_check_on_select()

    def on_db_click(self, event):
        item = self.tree.selection()  # 获取行对象
        print(self.tree.item(item, 'values'))


if __name__ == '__main__':
    # 定义窗口---------------------------------------
    win = Tk()
    win.title('测试窗口')
    win.geometry("%dx%d+%d+%d" % (1024, 800, 0, 0))

    # 定义listview---------------------------------------
    lv = ListView(win, x=100, y=100, width=800, height=500)
    lv.add_column('第一列', 100)
    lv.add_column('第二列', 100)
    lv.add_column('第三列', 100)
    lv.add_column('第四列', 100)
    lv.create_listview()
    # 添加数据
    for i in range(0, 4):
        row = ['a%d' % (i + 1), 'b%d' % (i + 1), 'c%d' % (i + 1), 'e%d' % (i + 1)]
        lv.add_row(False, row)

    # # 执行按钮---------------------------------------
    def do_task():
        list1 = []
        for j in range(lv.rows_count):
            if lv.get_check_bl(j + 1) is True:
                list1.append(j + 1)
        for k in list1:
            print(lv.get_row_vals(k))


    do_button = Button(win, text='测试', command=do_task)
    do_button.place(height=22, width=160, x=100, y=600)

    win.mainloop()


结果为:

img

img

img


如果问题得到解决的话请点 采纳~~

一般我们在开发时可能会用到下拉列表、全选功能以及勾选几个特别的选项,这个时候需要进行滚动操作,让选项显现。下面就用Tkinter实现这个功能。

先上代码和结果:

from tkinter import *
root = Tk()
root.title('my window')
root.geometry('500x500')
root.config(bg='red')
f1 = Frame(root,bg='blue')
f1.pack(fill=X)
yscro = Scrollbar(f1,orient=VERTICAL)
yscro.pack(side=RIGHT,fill=Y)
canv =Canvas(f1,bg='green')
canv.pack(side=LEFT)
f2 = Frame(canv,bg='yellow')
canv.create_window((0, 0), window=f2, anchor='nw')
for i in range(0,30):
    btu = Checkbutton(f2,text=str(i))
    btu.pack()
canv.update() #要先更新画布,bbox才能知道滚动的区域有多大。否者滚动不了
canv.config(yscrollcommand=yscro.set,scrollregion=canv.bbox('all'))
yscro.config(command=canv.yview)
root.mainloop()

小魔女参考了bing和GPT部分内容调写:
使用python实现复选框的动态更新列表信息,并获取多选框的信息,以及点击按钮进行相关后续操作,可以使用tkinter库来实现。

首先,需要导入tkinter库:

import tkinter as tk

然后,创建一个tkinter窗口:

root = tk.Tk()

接着,创建一个复选框列表:

checkbox_list = []

接下来,创建一个函数,用于更新复选框列表:

def update_checkbox_list():
    # 更新复选框列表
    for i in range(len(checkbox_list)):
        checkbox_list[i].destroy()
    # 动态更新复选框列表
    for i in range(len(data)):
        checkbox_list.append(tk.Checkbutton(root, text=data[i]))
        checkbox_list[i].pack()

最后,创建一个按钮,用于获取复选框的信息,并进行后续操作:

def get_checkbox_info():
    # 获取复选框的信息
    for i in range(len(checkbox_list)):
        if checkbox_list[i].get() == 1:
            print(data[i])
    # 进行后续操作
    # ...

# 创建一个按钮
button = tk.Button(root, text="获取复选框信息", command=get_checkbox_info)
button.pack()

最后,调用update_checkbox_list()函数,更新复选框列表,完成整个程序:

update_checkbox_list()
root.mainloop()

回答不易,记得采纳呀。

参考gpt和自己的思路,以下是一个简单的示例代码,演示如何使用Tkinter在列表中嵌套复选框。其中,使用了一个字典来保存每个复选框的状态,并通过点击按钮获取选中的复选框。


import tkinter as tk

root = tk.Tk()
root.geometry('400x400')

# 列表中的数据
data = {
    '发日': ['13', 'XD230301000087'],
    '31': ['XD230301000112'],
    '32': ['0230301000137'],
    '33': ['666', 'XD230301000138'],
    '34': ['25', 'XD230301000151'],
    '35': ['XD230301000206'],
    '36': ['107', 'XD230301606206'],
    '办': [],
    '32': ['XD230301000299']
}

# 保存复选框状态的字典
checkbox_state = {}

# 创建列表框
listbox = tk.Listbox(root)
listbox.pack(expand=True, fill='both')

# 往列表框中添加数据及复选框
for key in data:
    listbox.insert('end', key)
    if len(data[key]) > 0:
        sub_frame = tk.Frame(listbox)
        sub_frame.pack(side='left', anchor='w')
        for item in data[key]:
            checkbox_state[item] = tk.BooleanVar()
            checkbox_state[item].set(False)
            checkbox = tk.Checkbutton(sub_frame, text=item, variable=checkbox_state[item])
            checkbox.pack(side='left', anchor='w')


# 点击按钮获取选中的复选框
def get_checked_boxes():
    for key in checkbox_state:
        if checkbox_state[key].get():
            print(key)

button = tk.Button(root, text='获取选中项', command=get_checked_boxes)
button.pack()

root.mainloop()


需要注意的是,该示例代码中使用了tk.Frame来创建子框架,并在子框架中添加复选框,以便于在列表框中嵌套复选框。同时,使用了一个字典来保存每个复选框的状态,以便于在点击按钮时获取选中的复选框。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
下面是基于Tkinter实现的一个列表中嵌套复选框的代码示例,可以实现动态更新列表信息,并能够获取勾选的信息。

import tkinter as tk

class Checklist(tk.Frame):
    def __init__(self, master, options):
        super().__init__(master)
        
        self.vars = []
        
        for option in options:
            var = tk.BooleanVar(value=False)
            item = tk.Checkbutton(self, text=option, variable=var)
            item.pack(side="top", anchor="w")
            self.vars.append(var)
    
    def state(self):
        return [var.get() for var in self.vars]

class App(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        
        self.options = ["option 1", "option 2", "option 3", "option 4", "option 5"]
        
        self.checklist = Checklist(self, self.options)
        self.checklist.pack(side="left", fill="both", expand=True)
        
        self.button = tk.Button(self, text="Submit", command=self.submit)
        self.button.pack(side="bottom")
    
    def submit(self):
        print(self.checklist.state())

if __name__ == "__main__":
    root = tk.Tk()
    app = App(root)
    app.pack(side="top", fill="both", expand=True)
    root.mainloop()

这个示例程序中,Checklist类继承自Tkinter的Frame类,表示一个复选框列表。在Checklist的构造函数中,通过循环创建复选框,并使用BooleanVar来存储复选框的选中状态。Checklist类还提供了一个state()方法,用于获取当前选中的复选框状态。

App类继承自Tkinter的Frame类,表示整个应用程序的界面。在App的构造函数中,创建了一个Checklist对象和一个提交按钮。当用户点击提交按钮时,会调用submit()方法获取当前选中的复选框状态,并将其打印到控制台中。在这个示例程序中,使用了五个选项作为复选框列表的内容,可以根据实际需求动态更新列表信息。
如果我的回答解决了您的问题,请采纳!