ปัญหา Tkinter Grid - เฟรมไม่ตรงกัน

Sep 25 2020

ฉันเพิ่งเริ่มทำงานกับ tkinter และฉันยังคงพยายามทำความคุ้นเคยกับวิธีการทำงาน ฉันกำลังพยายามเตรียมเมนูกริดที่มี 4 ส่วน

มีหนึ่งเฟรมที่ด้านบนพร้อมชื่อของแอพหนึ่งเฟรมทางด้านซ้ายมีปุ่มบางปุ่มเพื่อกำหนดค่าแอพจากนั้นเฟรมที่มีขนาดเท่ากัน 4 เฟรมในส่วนที่เหลือ

ปัญหาหลักของฉันที่นี่คือคอลัมน์ว่างระหว่างกรอบด้านซ้ายและอีกสี่คอลัมน์ฉันจะปรับสิ่งนี้เพื่อให้สี่เหลี่ยมทั้ง 4 เติมเต็มช่องว่างนั้นได้อย่างไร

ดูด้านล่างรหัส:

import datetime
import tkinter as tk
from time import strftime

window = tk.Tk()
window.geometry("1400x800")
window.configure(bg="white")
window.rowconfigure(20,weight=1)
window.columnconfigure(35,weight=1)
window.title("Hello World App")
entry_var_server = tk.StringVar(window,"")
entry_var_db = tk.StringVar(window,"")
entry_var_driver = tk.StringVar(window,"")


def window_widgets():
    db_ini_frame_top = tk.Frame(master=window,bg="#57b956",height=120,width=1400,highlightbackground="black",highlightthickness=2)
    db_ini_frame_top.grid(rowspan=3,columnspan=34,sticky="w")

    db_ini_label_top = tk.Label(master=window,text="Hello World",bg="#57b956")
    db_ini_label_top.configure(font=("Calibri",26))
    db_ini_label_top.grid(row=1,column=18,sticky="n")

    def cur_date(dic = {'01':'st','21':'st','31':'st',
                    '02':'nd','22':'nd',
                    '03':'rd','23':'rd'}):
        x = strftime('%A,  %B %d')
        return x + dic.get(x[-2:],'th')+strftime(" %G - %H:%M")

    date = cur_date()
    db_ini_date = tk.Label(master=window,text=date,bg="#57b956")
    db_ini_date.configure(font=("Calibri",12))
    db_ini_date.grid(row=0,column=0,sticky="w")

    db_ini_frame_left = tk.Frame(master=window,bg="light grey",height=800,width=120,colormap="new",highlightbackground="black",highlightthickness=2)
    db_ini_frame_left.grid(row=3,rowspan=16,columnspan=2,sticky="w")

    db_ini_frame_center_nw = tk.Frame(master=window,height=350,width=640,bg="blue")
    db_ini_frame_center_nw.grid(row=3,column=3,columnspan=16,rowspan=12,sticky="nw")

    db_ini_frame_center_sw = tk.Frame(master=window,height=450,width=640,bg="light blue")
    db_ini_frame_center_sw.grid(row=12,column=3,columnspan=16,rowspan=12,sticky="sw")

    db_ini_frame_center_ne = tk.Frame(master=window,height=350,width=640,bg="light blue")
    db_ini_frame_center_ne.grid(row=3,column=19,columnspan=16,rowspan=12,sticky="ne")

    db_ini_frame_center_se = tk.Frame(master=window,height=450,width=640,bg="blue")
    db_ini_frame_center_se.grid(row=12,column=19,columnspan=16,rowspan=12,sticky="se")

window_widgets()
window.tk.mainloop()

คำตอบ

1 BryanOakley Sep 25 2020 at 22:27

แม้ว่าเราจะแก้ไขโค้ดของคุณได้ด้วยการเปลี่ยนแปลงเล็ก ๆ น้อย ๆ เพียงไม่กี่นาที แต่การสร้างเค้าโครงที่ชาญฉลาดขึ้นจะช่วยให้แก้ไขโค้ดได้ง่ายขึ้นเมื่อแอปพลิเคชันเติบโตขึ้น

ฉันจะเสนอคำแนะนำเกี่ยวกับวิธีจัดระเบียบโค้ดของคุณใหม่ ในตอนท้ายของคำตอบคือตัวอย่างการทำงานขั้นสุดท้าย 90% เป็นรหัสดั้งเดิมของคุณ แต่ด้วยการปรับแต่งเล็กน้อยที่นี่และที่นั่นเพื่อให้การสร้าง UI ง่ายขึ้น

อย่าใช้gridสำหรับทุกสิ่ง

อันดับแรกขอแนะนำว่าอย่าใช้gridสำหรับทุกอย่าง เป็นการดีสำหรับการสร้างกริด แต่บางครั้งก็มีวิธีที่ดีกว่าในการจัดวางหน้าต่างทั้งหมด แบ่ง UI ของคุณออกเป็นกลุ่มเชิงตรรกะแล้วจัดวางโดยใช้การจัดกลุ่มเหล่านั้น

การจัดระเบียบ UI ของคุณเป็นส่วน ๆ ทำให้ง่ายต่อการปรับเปลี่ยนเพียงส่วนเดียว เมื่อคุณใช้gridสำหรับทุกสิ่งการเปลี่ยนแปลงเล็ก ๆ น้อย ๆ อาจทำให้คุณต้องเปลี่ยนโค้ดโหลซึ่งคุณต้องปรับหมายเลขแถวและคอลัมน์และช่วงของแถวและคอลัมน์สำหรับทุกสิ่งเพียงเพื่อให้รองรับวิดเจ็ตใหม่เพียงรายการเดียว

รหัสเค้าโครงกลุ่มเข้าด้วยกัน

ฉันขอแนะนำให้คุณจัดกลุ่มการโทรเข้าgridและpackเข้าด้วยกันแทนที่จะโปรยสายตลอดทั้งรหัส ฉันพบว่ามันช่วยให้เห็นภาพเค้าโครงได้ง่ายขึ้นและทำการเปลี่ยนแปลงได้ง่ายขึ้นเนื่องจากการเปลี่ยนแปลงที่เกี่ยวข้องทั้งหมดอยู่ใกล้กันแทนที่จะกระจายออกไป

แบ่ง UI ออกเป็นส่วนตรรกะ

คุณมีพื้นที่ที่แตกต่างกันสามส่วนอย่างชัดเจน ได้แก่ ชื่อเรื่องด้านบนปุ่มบางปุ่มทางด้านซ้ายและอื่น ๆ เริ่มต้นด้วยการสร้างสิ่งนั้น packเป็นทางเลือกที่ดีที่สุดเมื่อคุณจัดวางสิ่งของไว้ที่ด้านข้างของช่องว่าง

เริ่มต้นด้วยการสร้างเฟรมสำหรับทั้งสามพื้นที่ จากนั้นคุณสามารถใช้packเพื่อจัดแนวตามขอบตามคำอธิบายของคุณ

db_ini_frame_top = tk.Frame(master=window, ...)
db_ini_frame_left = tk.Frame(master=window, ...)
db_ini_main = tk.Frame(master=window, ...)

db_ini_frame_top.pack(side="top", fill="x")
db_ini_frame_left.pack(side="left", fill="y")
db_ini_main.pack(side="top", fill="both", expand=True)

วางวิดเจ็ตอื่น ๆ ในคอนเทนเนอร์เหล่านี้

แม้ว่าคุณจะสร้างเฟรมที่ด้านบนสุด แต่คุณได้ใส่ป้ายกำกับและวันที่ในหน้าต่างรูท คุณควรวางไว้ในกรอบ เมื่อคุณไปไหนมาไหนเพื่อเพิ่มปุ่มควรอยู่ในกรอบด้านซ้าย และสุดท้ายสำหรับหน้าต่างอีกสี่หน้าต่างก็ต้องไปในเฟรมที่สาม

db_ini_label_top = tk.Label(master=db_ini_frame_top, ...)
db_ini_date = tk.Label(master=db_ini_frame_top, ...)

db_ini_frame_center_nw = tk.Frame(master=db_ini_main, ...)
db_ini_frame_center_sw = tk.Frame(master=db_ini_main, ...)
db_ini_frame_center_ne = tk.Frame(master=db_ini_main, ...)
db_ini_frame_center_se = tk.Frame(master=db_ini_main, ...)

ใช้gridสำหรับสี่เฟรมที่อยู่ในตารางจริงๆ

เมื่อใช้gridกฎทั่วไปคือคุณควรให้น้ำหนักอย่างน้อยหนึ่งแถวและหนึ่งคอลัมน์เพื่อที่จะได้gridรู้ว่าจะทำอย่างไรกับพื้นที่เพิ่มเติมเมื่อหน้าต่างขยายหรือหดตัว ในกรณีของคุณคุณต้องการให้เซลล์ทั้งสี่เท่ากันดังนั้นคุณควรให้น้ำหนักทั้งหมดเท่ากัน

เนื่องจากตอนนี้คุณใช้กริดเฉพาะสำหรับหน้าต่างทั้งสี่นี้แทนที่จะพยายามบังคับทุกอย่างให้เป็นตารางเดียวคุณสามารถใช้หมายเลขแถวและคอลัมน์ที่เหมาะสม (เช่นแถว 0 และ 1 คอลัมน์ 0 และ 1 แทนแถวขนาดใหญ่เทียม และคอลัมน์และช่วง)

db_ini_frame_center_nw = tk.Frame(master=db_ini_main,height=350,width=640,bg="blue")
db_ini_frame_center_sw = tk.Frame(master=db_ini_main,height=450,width=640,bg="light blue")
db_ini_frame_center_ne = tk.Frame(master=db_ini_main,height=350,width=640,bg="light blue")
db_ini_frame_center_se = tk.Frame(master=db_ini_main,height=450,width=640,bg="blue")

db_ini_main.grid_rowconfigure((0,1), weight=1)
db_ini_main.grid_columnconfigure((0,1), weight=1)

db_ini_frame_center_nw.grid(row=0,column=0, sticky="nsew")
db_ini_frame_center_sw.grid(row=0,column=1, sticky="nsew")
db_ini_frame_center_ne.grid(row=1,column=0, sticky="nsew")
db_ini_frame_center_se.grid(row=1,column=1, sticky="nsew")

นี่คือลักษณะของโค้ดทั้งหมดของคุณ ฉันไม่ได้ปรับตำแหน่งของข้อความในพื้นที่ชื่อเรื่อง แต่มันง่ายที่จะเปลี่ยนโดยไม่ส่งผลกระทบต่อส่วนอื่น ๆ ของ GUI

นอกจากนี้โปรดสังเกตว่าคุณสามารถปรับขนาดหน้าต่างได้ด้วยตนเองและทุกอย่างจะขยายหรือลดขนาดอย่างเหมาะสมแทนที่จะปล่อยให้เป็นจุดว่างเปล่า

import datetime
import tkinter as tk
from time import strftime

window = tk.Tk()
window.geometry("1400x800")
window.configure(bg="white")
window.rowconfigure(20,weight=1)
window.columnconfigure(35,weight=1)
window.title("Hello World App")
entry_var_server = tk.StringVar(window,"")
entry_var_db = tk.StringVar(window,"")
entry_var_driver = tk.StringVar(window,"")


def window_widgets():
    db_ini_frame_top = tk.Frame(master=window,bg="#57b956",height=120,width=1400,highlightbackground="black",highlightthickness=2)
    db_ini_frame_left = tk.Frame(master=window,bg="light grey",height=800,width=120,colormap="new",highlightbackground="black",highlightthickness=2)
    db_ini_main = tk.Frame(master=window,bg="light grey",height=800,width=120,colormap="new",highlightbackground="black",highlightthickness=2)

    db_ini_frame_top.pack(side="top", fill="x")
    db_ini_frame_left.pack(side="left", fill="y")
    db_ini_main.pack(side="top", fill="both", expand=True)

    db_ini_label_top = tk.Label(master=db_ini_frame_top,text="Hello World",bg="#57b956")
    db_ini_label_top.configure(font=("Calibri",26))
    db_ini_label_top.grid(row=1,column=18,sticky="n")

    def cur_date(dic = {'01':'st','21':'st','31':'st',
                    '02':'nd','22':'nd',
                    '03':'rd','23':'rd'}):
        x = strftime('%A,  %B %d')
        return x + dic.get(x[-2:],'th')+strftime(" %G - %H:%M")

    date = cur_date()
    db_ini_date = tk.Label(master=db_ini_frame_top,text=date,bg="#57b956")
    db_ini_date.configure(font=("Calibri",12))
    db_ini_date.grid(row=0,column=0,sticky="w")

    db_ini_frame_center_nw = tk.Frame(master=db_ini_main,height=350,width=640,bg="blue")
    db_ini_frame_center_sw = tk.Frame(master=db_ini_main,height=450,width=640,bg="light blue")
    db_ini_frame_center_ne = tk.Frame(master=db_ini_main,height=350,width=640,bg="light blue")
    db_ini_frame_center_se = tk.Frame(master=db_ini_main,height=450,width=640,bg="blue")

    db_ini_main.grid_rowconfigure((0,1), weight=1)
    db_ini_main.grid_columnconfigure((0,1), weight=1)

    db_ini_frame_center_nw.grid(row=0,column=0, sticky="nsew")
    db_ini_frame_center_sw.grid(row=0,column=1, sticky="nsew")
    db_ini_frame_center_ne.grid(row=1,column=0, sticky="nsew")
    db_ini_frame_center_se.grid(row=1,column=1, sticky="nsew")


window_widgets()
window.tk.mainloop()

Mike67 Sep 25 2020 at 22:16

ฟิลด์วันที่อยู่ในคอลัมน์เดียวดังนั้นมันจึงผลักคอลัมน์ถัดไปไปทางขวา

อัปเดตบล็อกวันที่ของคุณและเพิ่ม columnspan=4

date = cur_date()
db_ini_date = tk.Label(master=window,text=date,bg="#57b956")
db_ini_date.configure(font=("Calibri",12))
db_ini_date.grid(row=0,column=0,columnspan=4,sticky="w")   # Allow 4 columns for date 

เอาต์พุต