展开文本小部件而不展开其他小部件 tkinter
Expand Text Widget without expanding other widgets tkinter
我正在尝试制作一个只有 STD'S Frames 可调整大小的布局。我尝试使用 row_configure
和 column_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" 和 "Filename"。第三个有 "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。我不确定你期望他们如何表现。你说你希望它们增长和收缩,但你没有说它们是否应该填满整个右侧或者在它们之间有填充或 space。
这是一种方法。由于您已经有了一个框架,因此您不一定需要额外的框架。只需将文本和滚动条直接放在右栏中即可。不过,您当然可以根据需要使用其他框架。我的建议是要么不使用额外的框架,并使用 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)
那样做,那样做,并确保在调整 window 大小时行为仍然正确。只有在您确定此部分的行为符合您的预期后,您才应该继续阅读另一栏。
我正在尝试制作一个只有 STD'S Frames 可调整大小的布局。我尝试使用 row_configure
和 column_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" 和 "Filename"。第三个有 "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。我不确定你期望他们如何表现。你说你希望它们增长和收缩,但你没有说它们是否应该填满整个右侧或者在它们之间有填充或 space。
这是一种方法。由于您已经有了一个框架,因此您不一定需要额外的框架。只需将文本和滚动条直接放在右栏中即可。不过,您当然可以根据需要使用其他框架。我的建议是要么不使用额外的框架,并使用 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)
那样做,那样做,并确保在调整 window 大小时行为仍然正确。只有在您确定此部分的行为符合您的预期后,您才应该继续阅读另一栏。