python tkinter 自适配屏幕尺寸动态显示窗口滚动条,表格复选框全选功能的Demo

from tkinter import ttk, Tk, Frame, Canvas, Scrollbar, Label, Entry, Button, StringVar


def get_size(screen_width, screen_height, frame_width, frame_height, scrollbar_zise=15):
    # canvas_width: 画布宽度, canvas_height: 画布高度
    # scroll_area_width: 滚动区域宽度, scroll_area_height: 滚动区域高度
    if screen_width >= frame_width and screen_height >= frame_height:  # 没有滚动条
        canvas_width = frame_width
        canvas_height = frame_height
        scroll_area_width = frame_width
        scroll_area_height = frame_height
    elif screen_width >= frame_width and screen_height < frame_height:  # 只有垂直滚动条
        canvas_width = frame_width + scrollbar_zise
        canvas_height = screen_height
        scroll_area_width = frame_width + scrollbar_zise  # 增加垂直滚动条占用的高度
        scroll_area_height = frame_height
    elif screen_width < frame_width and screen_height >= frame_height:  # 只有水平滚动条
        canvas_width = screen_width
        canvas_height = frame_height + scrollbar_zise
        scroll_area_width = frame_width
        scroll_area_height = frame_height + scrollbar_zise  # 增加水平滚动条占用的高度
    elif screen_width < frame_width and screen_height < frame_height:  # 同时有水平和垂直滚动条
        canvas_width = screen_width
        canvas_height = screen_height
        scroll_area_width = frame_width + scrollbar_zise  # 增加垂直滚动条占用的高度
        scroll_area_height = frame_height + scrollbar_zise  # 增加水平滚动条占用的高度
    return canvas_width, canvas_height, scroll_area_width, scroll_area_height


def paint_canvas(root, frame_class, scrollbar_zise=15):
    # 生成画布,把frame绘制到画布上
    canvas = Canvas(root)
    frame = frame_class(canvas)
    root.frame = frame

    frame.update()  # 刷新后才能获取到组件加载后的总内容尺寸
    screen_width, screen_height = frame.winfo_screenwidth(), frame.winfo_screenheight()
    # 测试参数:
    # screen_width, screen_height = 1515, 920
    # screen_width, screen_height = 1000, 920
    # screen_width, screen_height = 1515, 600
    # screen_width, screen_height = 1000, 600
    # screen_width, screen_height = 1920, 600
    # screen_width, screen_height = 1000, 1080

    frame_width, frame_height = frame.winfo_reqwidth(), frame.winfo_reqheight()
    canvas_width, canvas_height, scroll_area_width, scroll_area_height = get_size(screen_width, screen_height, frame_width, frame_height, scrollbar_zise)

    # 垂直滚动条
    if scroll_area_height > canvas_height:
        vbar = Scrollbar(canvas, cursor='hand1', orient='vertical', command=canvas.yview)
        vbar.place(x=canvas_width - scrollbar_zise, width=scrollbar_zise, height=canvas_height)
        canvas.config(yscrollcommand=vbar.set)  # 绑定画布和滚动条的滚动

    # 水平滚动条
    if scroll_area_width > canvas_width:
        # 如果有垂直滚动条,水平滚动条宽度要减去垂直滚动条宽度
        hbar_width = canvas_width - (scroll_area_height > canvas_height and scrollbar_zise or 0)
        hbar = Scrollbar(canvas, cursor='hand1', orient='horizontal', command=canvas.xview)
        hbar.place(y=canvas_height - scrollbar_zise, width=hbar_width, height=scrollbar_zise)
        canvas.config(xscrollcommand=hbar.set)  # 绑定画布和滚动条的滚动

    # 刷新画布尺寸参数
    canvas.config(width=canvas_width, height=canvas_height, scrollregion=(0, 0, scroll_area_width, scroll_area_height))

    # 创建画布可见内容窗口,注意尺寸为frame尺寸的一半
    canvas.create_window((int(frame_width / 2), int(frame_height / 2)), window=frame)
    canvas.grid(row=0, column=0, padx=0, pady=0)

    # 返回窗口在屏幕中的位置
    return int((screen_width - canvas_width) / 2), int((screen_height - canvas_height - 100) / 2)


def paint_root(root, title, frame_class):
    # scrollbar_zise为滚动条的高度或者宽度
    root.title(title)
    root.resizable(False, False)  # 禁用窗口缩放
    root.update_idletasks()

    paint_x, paint_y = paint_canvas(root, frame_class)  # 在root上绘制画布

    # 调整窗口位置
    root.geometry('+%s+%s' % (paint_x, paint_y))
    root.deiconify()
    root.mainloop()


class TableFrame(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)

        incr_button = Button(self, text='增加表格', command=self.incr_table)
        incr_button.grid(row=0, column=1, pady=10)

        decr_button = Button(self, text='缩减表格', command=self.decr_table)
        decr_button.grid(row=0, column=3, pady=10)

        self.table = ttk.Treeview(self, height=45, show='headings')  # 显示45行
        self.table['columns'] = tuple(['□'] + [str(i + 1) for i in range(15)])
        for column in self.table['columns']:
            self.table.column(column, width=100)
            self.table.heading(column, text=column)
        self.table.heading('□', command=self.select_all)  # 表头选框绑定事件
        self.table.column('□', width=20)  # 调整列宽

        # 控制隐藏列
        displaycolumns = []
        for col in self.table['columns']:
            if col != '隐藏列名':
                displaycolumns.append(col)
        self.table['displaycolumns'] = displaycolumns

        self.table.bind('<Double-1>', self.double_select_one)  # 绑定双击行选中事件
        self.table.bind('<ButtonRelease-1>', self.select_one)  # 绑定单击选框选中事件
        self.refresh_table_data()

        self.table.grid(row=1, column=0, columnspan=5, padx=0, pady=0)

        # 为表格增加滚动条
        vbar = Scrollbar(self, cursor='hand1', orient='vertical', command=self.table.yview)
        self.table.configure(yscrollcommand=vbar.set)
        vbar.grid(row=1, column=5, padx=0, pady=0, sticky='NS')

    def get_table_data(self):  # 获取表格数据,自定义表格内容时修改这个方法
        table_data = []
        for index, data in enumerate([list(range(15))] * table_root.rows):
            table_data.append(['□'] + ['%s:%s' % (index + 1, i + 1) for i in data])
        return table_data

    def refresh_table_data(self):  # 刷新表格数据
        self.table.heading('□', text='□')
        self.table.all_selected = False
        self.table.selected_values = {}
        for row in self.table.get_children():
            self.table.delete(row)
        for table_data in self.get_table_data():
            self.table.insert('', 'end', values=table_data)

    def incr_table(self):  # 表格增加一行
        table_root.rows += 1
        self.refresh_table_data()

    def decr_table(self):  # 表格减少一行
        table_root.rows -= 1
        self.refresh_table_data()

    def double_select_one(self, event):  # 双击行
        selection_row = self.table.identify('row', event.x, event.y)
        selection_column = self.table.identify('column', event.x, event.y)
        if not selection_row or not selection_column:  # 排除点击表头的情况
            return
        values = self.table.item(selection_row, 'values')
        value = values[0] == '□' and '☑' or '□'
        self.table.set(selection_row, column='#1', value=value)
        if value == '□':
            self.table.selected_values.pop(selection_row, None)
        else:
            self.table.selected_values.update({selection_row: values})

    def select_one(self, event):  # 单击选框
        selection_column = self.table.identify('column', event.x, event.y)
        if selection_column == '#1':  # 点击的是第一列的选框
            self.double_select_one(event)

    def select_all(self):  # 单击全选
        value = self.table.all_selected and '□' or '☑'
        self.table.heading('□', text=value)
        self.table.selected_values = {}
        for row in self.table.get_children():
            self.table.set(row, column='#1', value=value)
            if value == '☑':
                self.table.selected_values.update({row: self.table.item(row, 'values')})
        self.table.all_selected = not self.table.all_selected


class MainFrame(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)

        self.rows_text = Label(self, width=8, text='行数:')
        self.rows_text.grid(row=0, column=0, padx=0, pady=10)
        self.rows_str = StringVar()
        self.rows = Entry(self, width=10, textvariable=self.rows_str)
        self.rows_str.set('100')
        self.rows.grid(row=0, column=1, padx=0, pady=10)

        refresh_button = Button(self, text='显示表格', command=self.refresh_table)
        refresh_button.grid(row=0, column=2, padx=4, pady=10)

    def refresh_table(self):
        global table_root
        if table_root is None or not table_root.children:  # 如果首次打开窗口或窗口被关闭
            table_root = Tk()
            table_root.rows = int(self.rows.get() or 100)  # 输入的行数
            paint_root(table_root, '表格界面', TableFrame)
        else:
            table_root.rows = int(self.rows.get() or 100)  # 输入的行数
            table_root.frame.refresh_table_data()

            # 窗口升起
            table_root.lift()
            table_root.focus_force()

if __name__ == '__main__':
    main_root, table_root = Tk(), None
    paint_root(main_root, '主界面', MainFrame)

 

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Tkinter复选框(Checkbutton)是一种常见的GUI元素,用于让用户选择一个或多个选项。在Python中,可以使用Tkinter模块来创建复选框。以下是创建Tkinter复选框的基本步骤: 步骤1:导入Tkinter模块 ```python import tkinter as tk ``` 步骤2:创建Tkinter窗口 ```python root = tk.Tk() root.title("Checkbutton Example") ``` 步骤3:创建复选框(Checkbutton) ```python var1 = tk.IntVar() checkbutton1 = tk.Checkbutton(root, text="Option 1", variable=var1) checkbutton1.pack() var2 = tk.IntVar() checkbutton2 = tk.Checkbutton(root, text="Option 2", variable=var2) checkbutton2.pack() ``` 步骤4:获取复选框的值 ```python value1 = var1.get() value2 = var2.get() ``` 步骤5:将复选框添加到窗口 ```python root.mainloop() ``` 完整示例代码: ```python import tkinter as tk root = tk.Tk() root.title("Checkbutton Example") var1 = tk.IntVar() checkbutton1 = tk.Checkbutton(root, text="Option 1", variable=var1) checkbutton1.pack() var2 = tk.IntVar() checkbutton2 = tk.Checkbutton(root, text="Option 2", variable=var2) checkbutton2.pack() def show_values(): print("Option 1: ", var1.get()) print("Option 2: ", var2.get()) button = tk.Button(root, text="Show Values", command=show_values) button.pack() root.mainloop() ``` 代码解释: 首先,我们导入了Tkinter模块。然后,我们创建了一个Tkinter窗口,并设置了窗口的标题。接下来,我们创建了两个复选框,并将它们添加到窗口中。每个复选框都有一个关联的整数变量(IntVar),用于存储复选框的值。我们还创建了一个按钮,当用户单击该按钮时,将调用show_values函数来显示复选框的值。最后,我们使用mainloop()方法来启动Tkinter事件循环。 自定义复选框的属性: 可以使用Checkbutton的各种选项来自定义复选框的外观和行为。例如,可以使用text选项来设置复选框的标签,使用variable选项来设置与复选框关联的变量,使用command选项来设置单击复选框时要调用的函数,等等。 结论: Tkinter复选框是一种非常有用的GUI元素,可以让用户选择一个或多个选项。在Python中,可以使用Tkinter模块来创建复选框,并使用各种选项来自定义复选框的外观和行为。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值