展开Text Widget而不展开其他小部件tkinter

时间:2017-10-27 15:01:09

标签: python tkinter widget

我正在尝试制作一个只有STD'S Frames可调整大小的布局。我尝试使用row_configurecolumn_configure,但由于小部件在帧上,或者帧有columnspan这一事实,小部件似乎没有调整大小。 现在是布局的样子。

Sample Layout

有什么建议吗?

'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.

CODE

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()

1 个答案:

答案 0 :(得分:0)

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

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

例如:

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)

执行此操作,并确保在调整窗口大小时行为仍然正确。只有在您确定此部分的行为符合您的预期后,才能转到另一列。