繁体   English   中英

扩展文本小部件而不扩展其他小部件 tkinter

[英]Expand Text Widget without expanding other widgets tkinter

我正在尝试使用可调整大小的 STD 框架来制作布局。 我尝试使用row_configurecolumn_configure ,但由于小部件在框架上,或者框架具有columnspan的事实,小部件似乎没有调整大小。 这是布局现在的样子。

示例布局

有什么建议吗?

代码需要'text.txt

R1:Saluda y pregunta al inicio los roles y nombres, y si desea cargar una partida.:Errores importantes son, por ejemplo, no preguntar directamente por los roles.
R2:Dialogo con el usuario durante el transcurso de un turno: durante cada turno pregunta la jugada del usuario y si desea guardar la partida, además explica de forma adecuada el formato del movimiento.:Muestra claramente cómo debe ser el input para el movimiento. Lo demás es meramente el acto de preguntar. Preguntar por guardar es un punto, mientras que "preguntar y explicar bien el movimiento" también es un punto.
R3:Al final de una partida avisa el ganador y pregunta si quiere seguir jugando. En caso de que no quieran seguir, entonces termina el juego. De lo contrario, se reinicia el juego de 0.:El programa debe manejar que el usuario no quiere seguir jugando, es decir, que si el jugador elige no seguir el juego termina de forma correcta sin caerse. Entiendase "reiniciar de cero" que es como si el programa corriese por primera vez. 
R4:Imprime el tablero 5x5 con las fichas representadas según formato.:Es importante que concuerde con el sistema de coordenadas descrito en el enunciado y el formato de este.
R5:Recibe y decodifica el input del movimiento de forma correcta:Pide el input en el formato pedido en el enunciado y lo guarda y/o utiliza.
R6:Efectúa el movimiento indicado de forma correcta (siempre que este sea válido).:Esta parte se debe corregir solamente con movimientos válidos. El movimiento de comer una gallina no cuenta aquí ya que este se evalúa en R8 y R9.
R7:Avisa cuando una jugada es inválida, además de evitar dicha jugada. (No es necesario controlar coordenadas fuera de rango):La mayoría de los errores posibles son importantes, por lo que se puede omitir el nivel Aceptable (2) de logro. En caso de jugadas inválidas el programa debe evitar hacerla, de lo contrario esto se considera como error importante.
R8:Lleva a cabo el movimiento de comer una gallina.:Solamente Completo o No logrado. 
R9:Lleva a cabo el movimiento de comer a más de una gallina en un solo turno.:El mayor caso es de 3 gallinas de una sola vez, lo cual pueden probar con el archivo de prueba correspondiente. También hay que tomar en cuenta que en este caso es obligación que el coyote coma una gallina, por lo tanto si el programa permite mover hacia otro lado cuenta como error importante.
R10:Detecta cuando ganan las gallinas.:Solamente es No logrado o Completo.
R11:Detecta cuando gana el coyote.:Solamente es No logrado o Completo.
R12:Guarda la partida en el formato correcto.:La mayoría de los errores posibles son importantes, por lo que se puede omitir el nivel Aceptable (2) de logro. 
R13:Carga correctamente la partida y muestra el historial de jugadas.:Con tal de que cada jugada se pueda ver claramente, la parte del historial esta correcto. Al momento de corregir  se debe utilizar un archivo que este en el formato correcto.
R14:Luego de cargar una partida se puede seguir jugando sobre esta.
R15:Formato de entrega:Archivo mal subido, archivo .py no corresponde a las instrucciones.

代码

import tkinter as tk
import tkinter.font as tkfont
from tkinter import ttk
import os
import subprocess
import glob

# GLOBALY USED

previous_value = []


def update_all(event):
    with open('saved_data.txt', 'r') as notas:
        for linea in notas:
            nro_alumno = linea.split(',')[0]
            if nro_alumno == nro_alumnos.get():
                stdin_filename.set(files[alumnos.index(nro_alumno)])
                obtained = linea.strip().split(',')[1:]
                for entrada, dato in zip(entradas.keys(), obtained):
                    entradas[entrada][0].delete(0, tk.END)
                    entradas[entrada][0].insert(0, int(dato))
                update_scores()


def clear(event):
    previous_value.append([event.widget, event.widget.get()])
    event.widget.delete(0, tk.END)


def move_down(event):
    for entrada in entradas:
        if entradas[entrada][0] == root.focus_get():
            index = int(entrada[1:])
            if index == 15:
                index = 1
            else:
                index += 1
            new_focus = f'R{index}'
            entradas[new_focus][0].focus_set()
            return


def move_up(event):
    for entrada in entradas:
        if entradas[entrada][0] == root.focus_get():
            index = int(entrada[1:])
            if index == 1:
                index = 15
            else:
                index -= 1
            new_focus = f'R{index}'
            entradas[new_focus][0].focus_set()
            return


def update_puntajes():
    alumno = nro_alumnos.get()
    with open('saved_data.txt', 'r') as archivo:
        datos = archivo.read().splitlines()
    puntajes = []
    for entrada in entradas.keys():
        puntajes.append(str(entradas[entrada][0].get()))
    for dato in datos:
        if dato.split(',')[0] == alumno:
            datos[datos.index(dato)] = ','.join([dato.split(',')[0]] + puntajes)
    with open('saved_data.txt', 'w') as archivo:
        for dato in datos:
            if dato == datos[-1]:
                archivo.write(dato)
            else:
                archivo.write(dato + '\n')
    with open('puntajes.csv', 'r') as archivo:
        datos = archivo.read().splitlines()
    puntajes = []
    for entrada in entradas.keys():
        puntajes.append(str(entradas[entrada][2].get()))
    for dato in datos:
        if dato.split(';')[0] == alumno:
            datos[datos.index(dato)] = ';'.join([dato.split(';')[0]] + puntajes)
    with open('puntajes.csv', 'w') as archivo:
        for dato in datos:
            if dato == datos[-1]:
                archivo.write(dato)
            else:
                archivo.write(dato + '\n')


def update_scores(event=None):
    try:
        previous_widget = previous_value.pop(0)
        if previous_widget[0].get() == '':
            previous_widget[0].insert(0, previous_widget[1])
    except IndexError:
        pass

    maximos = {
        'R1': 1,
        'R2': 2,
        'R3': 2,
        'R4': 4,
        'R5': 2,
        'R6': 4,
        'R7': 5,
        'R8': 4,
        'R9': 8,
        'R10': 6,
        'R11': 4,
        'R12': 5,
        'R13': 8,
        'R14': 5,
        'R15': 1
    }
    for entrada in entradas.keys():
        entradas[entrada][1].delete(0, tk.END)
        try:
            entradas[entrada][2].set((int(entradas[entrada][0].get()) * maximos[entrada]) / 3)
        except ValueError:
            pass


root = tk.Tk()


def bold(size=None):
    if not size:
        return tkfont.Font(weight='bold')
    else:
        return tkfont.Font(size=size, weight='bold')


def sized(size):
        return tkfont.Font(size=size)


def refresh_rubrica(event):
    current = rubrica_dropdown.get()
    for value in rubric_values:
        if value[0] == current:
            descripcion_var.set(value[1])
            comentarios_var.set(value[2])


def create_data_files():
    if os.path.isfile(os.getcwd()+os.sep+'saved_data.txt') and os.path.isfile(os.getcwd()+os.sep+'puntajes.csv'):
        return
    with open('saved_data.txt', 'w') as archivo:
        archivo.write('Nro,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15\n')
        for alumno in alumnos:
            if alumno != alumnos[-1]:
                archivo.write(alumno + ',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n')
            else:
                archivo.write(alumno + ',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')

    with open('puntajes.csv', 'w') as archivo:
        archivo.write('Nro;R1;R2;R3;R4;R5;R6;R7;R8;R9;R10;R11;R12;R13;R14;R15\n')
        for alumno in alumnos:
            if alumno != alumnos[-1]:
                archivo.write(alumno + ';0;0;0;0;0;0;0;0;0;0;0;0;0;0;0\n')
            else:
                archivo.write(alumno + ';0;0;0;0;0;0;0;0;0;0;0;0;0;0;0')


def process():
    if len(ID_entry.get())==0:
        ERROR_VAR.set('DEBES INGRESAR ALGO!')
        return
    try:
        os.chdir(os.getcwd() + os.sep + ID_entry.get())
        for file in os.listdir(os.getcwd()):
            if file not in ['puntajes.csv', 'saved_data.txt', 'input.txt', 'out.txt', 'err.txt']:
                alumnos.append(file.split('_')[0])
                files.append('_'.join(list(map(lambda x: x.lower(), file.split('_')[1:]))))
        create_data_files()
        nro_alumnos['values'] = alumnos
    except FileNotFoundError:
        ERROR_VAR.set('ESE ID NO EXISTE!')
        return
    else:
        ERROR_VAR.set('')
    create_data_files()
    config.destroy()
    root.deiconify()


def run():
    print(stdin_text.get(tk.END))
    inp_file = open('input.txt', 'w')
    inp_file.write(stdin_text.get('1.0', tk.END))
    inp_file.close()
    infile = open('input.txt', 'r')
    outfile = open('out.txt', 'w')
    errfile = open('err.txt', 'w')
    subprocess.run('python '+ glob.glob(nro_alumnos.get() + '*')[0], stdin=infile, stdout=outfile, stderr=errfile)
    infile.close()
    outfile.close()
    errfile.close()
    stdout_text.configure(state='normal')
    stdout_text.delete('1.0', tk.END)
    with open('out.txt', 'r') as file:
        stdout_text.insert('1.0', file.read())
    stdout_text.configure(state='disabled')
    stderr_text.configure(state='normal')
    stderr_text.delete('1.0', tk.END)
    with open('err.txt', 'r') as file:
        stderr_text.insert('1.0', file.read())
    stderr_text.configure(state='disabled')
    os.remove('input.txt')
    os.remove('out.txt')
    os.remove('err.txt')
# GLOBALS CONFIG

files = []
alumnos = []
entry_frame = tk.Frame(root)
entradas = {
    'R1': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R2': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R3': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R4': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R5': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R6': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R7': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R8': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R9': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R10': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R11': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R12': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R13': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R14': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)],
    'R15': [tk.Entry(entry_frame), tk.Entry(entry_frame), tk.DoubleVar(entry_frame, value=0.0)]
}
# ENTRY CONFIG
for entry in entradas.keys():
    entradas[entry][0].configure(width=5)
    entradas[entry][0].bind('<FocusOut>', update_scores)
    entradas[entry][0].bind('<FocusIn>', clear)
    entradas[entry][0].bind('<Down>', move_down)
    entradas[entry][0].bind('<Up>', move_up)
    entradas[entry][1].configure(width=5)
    entradas[entry][1].configure(width=5, state='readonly', textvariable=entradas[entry][2])

# ENTRY GRIDDING
for i, entry in enumerate(entradas.keys(), 3):
    label = tk.Label(entry_frame, text=entry, justify='center')
    label.grid(column=0, row=i, pady=2, padx=2)
    entradas[entry][0].grid(column=1, row=i, pady=2, padx=2, sticky=tk.W)
    entradas[entry][1].grid(column=2, row=i, pady=2, padx=2, sticky=tk.W)

# NRO ALUMNOS

nro_label = tk.Label(entry_frame, text='Puntaje', font=bold())  # TITLE
column_labelN = tk.Label(entry_frame, text='Nivel')
column_labelN.grid(column=1, row=2)
column_labelP = tk.Label(entry_frame, text='Puntaje')
column_labelP.grid(column=2, row=2)
nro_label.grid(column=0, row=0, sticky='nw')
nro_alumnos = ttk.Combobox(entry_frame, width=10, state='readonly')
nro_alumnos.bind('<<ComboboxSelected>>', update_all)
nro_alumnos['values'] = alumnos
nro_alumnos_label = tk.Label(entry_frame, text='N°de alumno')
nro_alumnos_label.grid(column=0, row=1, sticky='nw')
nro_alumnos.grid(column=1, row=1, columnspan=2, sticky='nw')
entry_frame.grid(column=0, row=0, columnspan=3, rowspan=15, sticky='n')
# RUBRICA
rubric_values = []
with open('text.txt', 'r') as a:
    rubric_data = a.read().splitlines()
for R in rubric_data:
    rubric_values.append(R.split(':'))
frame_rubrica = tk.Frame(root, width=100, height=100)
label_descRub = tk.Label(frame_rubrica, text='Descripcion: ', font=bold(7))
label_comRub = tk.Label(frame_rubrica, text='Comentarios: ', font=bold(7))
descripcion_var = tk.StringVar(frame_rubrica, value='None')
descripcion_rubrica = tk.Label(frame_rubrica, textvariable=descripcion_var, wraplength=200,
                               justify='left', font=sized(7))
comentarios_var = tk.StringVar(frame_rubrica, value='None')
comentarios_rubrica = tk.Label(frame_rubrica, textvariable=comentarios_var, wraplength=200,
                               justify='left', font=sized(7))
r_label = tk.Label(frame_rubrica, text='Rubrica', font=bold())
r_label.grid(column=0, row=0, columnspan=1, sticky='w')
rubrica_dropdown = ttk.Combobox(frame_rubrica, width=5, state='readonly', values=[R[0] for R in rubric_values])
rubrica_dropdown.grid(column=1, row=0, sticky='w')
label_descRub.grid(column=0, row=1)
label_comRub.grid(column=0, row=2)
descripcion_rubrica.grid(column=1, row=1, sticky='w', columnspan=3)
comentarios_rubrica.grid(column=1, row=2, sticky='w', columnspan=3)
frame_rubrica.grid(column=3, row=0, columnspan=3, rowspan=6, sticky='nw', padx= 10)
rubrica_dropdown.bind('<<ComboboxSelected>>', refresh_rubrica)
# BOTONES

update = tk.Button(entry_frame, text='Actualizar', command=update_puntajes)
update.grid(column=0, row=18, columnspan=3, pady=10, padx=20, sticky='nsew')

# STDIN
stdin_frame = tk.Frame(root)
filename_frame = tk.Frame(stdin_frame)
stdin_labelN = tk.Label(filename_frame, text='Filename: ', font=bold())
stdin_filename = tk.StringVar(filename_frame, 'NONE')
stdin_file = tk.Label(filename_frame, textvariable=stdin_filename)
stdin_label = tk.Label(stdin_frame, text='STD-IN', font=bold(10))
stdin_text = tk.Text(stdin_frame, width=40, height=16)
stdin_scroll = tk.Scrollbar(stdin_frame, command=stdin_text.yview)
runbutton = tk.Button(stdin_frame, text='Run', height=2, command=run)
stdin_text.configure(yscrollcommand=stdin_scroll.set)
stdin_labelN.grid(column=0, row=0, sticky='w')
stdin_file.grid(column=1, row=0, sticky='w')
filename_frame.grid(column=0,row=0, columnspan=2, sticky='w')
stdin_label.grid(column=0, row=3, sticky='w', padx=10)
stdin_text.grid(column=0, row=4, pady=4)
stdin_scroll.grid(column=1, row=4, sticky='nsew')
runbutton.grid(column=0, row=5, sticky='nsew', padx=20, pady=1)
stdin_frame.grid(column=4, row=9, rowspan=16, columnspan=3, padx=10)


#STDOUT
stdout_frame = tk.Frame(root)
stdout_label = tk.Label(stdout_frame, text='STD-OUT', font=bold(10))
stdout_label.grid(column=0, row=0, sticky='w', padx=10)
stdout_var = tk.StringVar(stdout_frame, 'NONE')
stdout_text = tk.Text(stdout_frame, width=40, height=12, state=tk.DISABLED)
stdout_scroll = tk.Scrollbar(stdout_frame, command=stdout_text.yview)
stdout_text.configure(yscrollcommand=stdout_scroll.set)
stdout_text.grid(column=0, row=1)
stdout_scroll.grid(column=1, row=1, sticky='nsew')
stdout_frame.grid(column=9, row=0, rowspan=10, columnspan=3, padx=10)

#STDERR
stderr_frame = tk.Frame(root)
stderr_label = tk.Label(stderr_frame, text='STD-ERR', font=bold(10))
stderr_label.grid(column=0, row=0, sticky='w', padx=10)
stderr_var = tk.StringVar(stderr_frame, 'NONE')
stderr_text = tk.Text(stderr_frame, width=40, height=12, state=tk.DISABLED)
stderr_scroll = tk.Scrollbar(stderr_frame, command=stderr_text.yview)
stderr_text.configure(yscrollcommand=stderr_scroll.set)
stderr_text.grid(column=0, row=1)
stderr_scroll.grid(column=1, row=1, sticky='nsew')
stdin_frame.grid_rowconfigure(1, weight=1)
stdin_frame.grid_columnconfigure(0, weight=1)
stderr_frame.grid(column=9, row=10, rowspan=10, columnspan=3, padx=10)
root.grid_rowconfigure(10, weight=1)
root.grid_columnconfigure(9, weight=1)
root.attributes('-topmost', 'true')
root.geometry('900x600')

#SETUP

config = tk.Tk()
ID_label = tk.Label(config, text='ID Ayudante')
ERROR_VAR = tk.StringVar(config)
ERROR = tk.Label(config, textvariable=ERROR_VAR, fg='red', justify=tk.CENTER)
ID_entry = tk.Entry(config)
ID_button = tk.Button(config, text='Correr', command=process)
ID_label.grid(column=0, row=0, padx=10, pady=10)
ID_entry.grid(column=1, row=0, padx=10, pady=10)
ERROR.grid(column=0, row=2,columnspan=2, sticky='nsew')
ID_button.grid(column=0, row=3, padx=35, columnspan=2, sticky='nsew')
config.grid_rowconfigure(3, weight=1)
config.grid_columnconfigure(0, weight=1)


root.withdraw()
config.geometry('100x100')
config.mainloop()
root.mainloop()

对于这样一个概念上简单的布局,您的布局非常复杂。 我强烈建议您重新组织您的代码。 当您的布局简单时,Tkinter 效果最佳。

在您的情况下,您的 UI 似乎具有三个不同的列。 第一个有标题为“Puntaje”的部分。 第二列有标题“Rubrica”和“文件名”。 第三个有“STD-OUT”和“STD-ERR”。 因此,我的建议是首先创建三个框架,每个部分一个。

例如:

left = tk.Frame(root)
middle = tk.Frame(root)
right = tk.Frame(root)

你说你只希望右边的文本小部件增长,所以你可以这样布置这三列:

left.pack(side="left", fill="both", expand=False)
middle.pack(side="left", fill="both", expand=False)
right.pack(side="right", fill="both", expand=True)

这样做,就那样。 给每列一个不同的颜色和一个临时的宽度和高度,这样你就可以验证它们的行为是否正常。

完成后,您可以分别关注每一列。 例如,让我们添加 stdout 和 stderr。 我不确定您期望他们的行为方式。 你说你想让它们增长和缩小,但你没有说他们是否应该填满整个右侧,或者在它们之间有填充或空间。

这是一种方法。 由于您已经有一个框架,因此您不一定需要额外的框架。 只需将文本和滚动条直接放在右栏中即可。 不过,如果需要,您当然可以使用其他框架。 我的建议是要么不使用额外的框架,而是使用grid在右栏中布置小部件,或者使用额外的框架然后使用pack将两个小部件和标签简单地堆叠在一起。

# right column, using grid
stdin_label = tk.Label(right, text="STD-IN", anchor="w")
stdin_text = tk.Text(right, width=40, height=16)
stdin_scroll = tk.Scrollbar(right, command=stdin_text.yview, orient="vertical")

stdout_label = tk.Label(right, text="STD-OUT", anchor="w")
stdout_text = tk.Text(right, width=40, height=16)
stdout_scroll = tk.Scrollbar(right, command=stdout_text.yview, orient="vertical")

stdin_label.grid(row=0, column=0, columnspan=2, sticky="nsew")
stdin_text.grid(row=1, column=0, sticky="nsew")
stdin_scroll.grid(row=1, column=1, sticky="ns")

stdout_label.grid(row=2, column=0, columnspan=2, sticky="nsew")
stdout_text.grid(row=3, column=0, sticky="nsew")
stdout_scroll.grid(row=3, column=1, sticky="ns")

right.grid_rowconfigure(1, weight=1)
right.grid_rowconfigure(3, weight=1)
right.grid_columnconfigure(0, weight=1)

这样做,仅此而已,并确保在调整窗口大小时行为仍然正确。 只有在您确定此部分的行为方式符合您的预期后,您才能转到另一列。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM