Pergunta

Existe algo como pack to new line para o gerenciador de geometria Tk?Estou usando o pack para colocar widgets dentro de um quadro.Em uma tela de alta resolução, os widgets cabem lado a lado.No entanto, se você colocá-lo em uma tela menor, os widgets ficarão sem espaço no quadro.

Basicamente, partimos de:

Before

para:

after

Você pode ver como ele corta meu campo de entrada Processadores.O código relevante:

options_frame = ttk.LabelFrame(
        parent_frame, text="Blast Options")
options_frame.pack(side=TOP, fill=X, expand=1, padx=5, pady=5)
        self._set_up_blast_options(options_frame)

def _set_up_blast_options(self, options_frame):
    self.evalue = Tkinter.DoubleVar()
    self.evalue.set(1)
    self.word_size = Tkinter.IntVar()
    self.word_size.set(4)
    self.penalty_mismatch = Tkinter.DoubleVar()
    self.penalty_mismatch.set(-4)
    self.min_d_match = Tkinter.IntVar()
    self.min_d_match.set(5)
    self.proc_count = Tkinter.IntVar()
    self.proc_count.set(cpu_count())

    # evalue
    e_value_label = ttk.LabelFrame(
        options_frame, text="e-Value Threshold")
    e_value_entry = ttk.Entry(e_value_label)
    e_value_entry.insert(0, self.evalue.get())
    e_value_entry.bind('<Return>', self._validate_e_value)
    e_value_entry.bind('<FocusOut>', self._validate_e_value)
    e_value_label.pack(side=LEFT, expand=1, pady=5, padx=5, fill=X)
    e_value_entry.pack(side=TOP, expand=1, pady=5, padx=5, fill=X)

    # word size
    word_size_label = ttk.LabelFrame(
        options_frame, text="Word Size")
    word_size_entry = ttk.Entry(word_size_label)
    word_size_entry.insert(0, self.word_size.get())
    word_size_entry.bind('<Return>', self._validate_word_value)
    word_size_entry.bind('<FocusOut>', self._validate_word_value)
    word_size_label.pack(side=LEFT, expand=1, pady=5, padx=5, fill=X)
    word_size_entry.pack(side=TOP, expand=1, pady=5, padx=5, fill=X)

    penalty_mismatch_label = ttk.LabelFrame(
        options_frame, text="Penalty Mismatch")
    penalty_mismatch_entry = ttk.Entry(penalty_mismatch_label)
    penalty_mismatch_entry.insert(0, self.penalty_mismatch.get())
    penalty_mismatch_entry.bind(
        '<Return>', self._validate_penalty_mismatch_value)
    penalty_mismatch_entry.bind(
        '<FocusOut>', self._validate_penalty_mismatch_value)
    penalty_mismatch_label.pack(side=LEFT, expand=1, pady=5,
                                padx=5, fill=X)
    penalty_mismatch_entry.pack(side=TOP, expand=1, pady=5,
                                padx=5, fill=X)
    # Min D Nucleotides
    min_d_match_label = ttk.LabelFrame(
        options_frame, text="Minimal Number of D Nucleotides")
    min_d_match_entry = ttk.Entry(min_d_match_label)
    min_d_match_entry.insert(0, self.min_d_match.get())
    min_d_match_entry.bind(
        '<Return>', self._validate_min_match_value)
    min_d_match_entry.bind(
        '<FocusOut>', self._validate_min_match_value)
    min_d_match_label.pack(side=LEFT, expand=1, pady=5, padx=5, fill=X)
    min_d_match_entry.pack(side=TOP, expand=1, pady=5, padx=5, fill=X)

    # how many cpus to use
    proc_count_label = ttk.LabelFrame(
        options_frame, text="Processors")
    proc_count_entry = ttk.Entry(proc_count_label)
    proc_count_entry.insert(0, self.proc_count.get())
    proc_count_entry.bind(
        '<Return>', self._validate_proc_count_value)
    proc_count_entry.bind(
        '<FocusOut>', self._validate_proc_count_value)
    proc_count_label.pack(side=LEFT, expand=1, pady=5, padx=5, fill=X)
    proc_count_entry.pack(side=TOP, expand=1, pady=5, padx=5, fill=X)

Muitas ligações de eventos e configurações de opções podem não ser relevantes, mas achei que ainda deveria incluir... só para garantir.A melhor opção seria mudar para um gerenciador de grade?O problema seria que esse quadro estivesse dentro de outro... e assim por diante.Não é que se você começar a usar o gerenciador de grade, terá que usá-lo para tudo porque não pode misturar o gerenciador de grade e compactado no mesmo quadro?

Foi útil?

Solução

AFAIK, não existe uma maneira integrada de criar interfaces dinâmicas no tkinter.Sua melhor aposta é obter a resolução da tela e, em seguida, grade/empacotar adequadamente.

user32 = ctypes.windll.user32
get_screensize = (user32.GetSystemMetrics(0), user32.GetSystemMetrics(1))

Então, por exemplo....

widget1 = tkinter.Entry(root,width=20,etc)
widget2 = tkinter.Label(root,text='Hello',etc)
## Now perform update_idletasks() which will force
## Tkinter to calculate their size.
widget1.update_idletasks()
widget2.update_idletasks()
## Now calculate whether they'll fit.
if widget1.winfo_width() + widget2.winfo_width() > screensize[0]:## Not enough space
    widget1.grid(row=0)
    widget2.grid(row=1)
else:## Both will fit on one line.
    widget1.grid(row=0,column=0)
    widget2.grid(row=0,column=1)

Outras dicas

Em geral, concordo com a resposta de I_do_python, mas faria uma pequena modificação.Eu colocaria todos os widgets em um novo quadro e usaria a largura do quadro como o teste decisivo para saber se deveria ser agrupado.E você pode vincular um manipulador de eventos para o "<Configure>" evento que verifica se o conteúdo do quadro precisa ser quebrado quando a janela do aplicativo (e, portanto, o quadro) é redimensionada.

Eu escrevi a função abaixo que usa o método de grade para inserir widgets de forma inteligente em um quadro.Certamente pode ser melhorado, mas funciona para mim.Geralmente se você usa .grid() para preencher um pai, você pode desperdiçar espaço em branco quando os widgets de preenchimento variam em largura.A função abaixo resolve isso dividindo o pai em colunas lógicas (divisions no código) e permitindo que os widgets ocupem várias colunas.O resultado é um layout de grade com espaço em branco desperdiçado muito reduzido.Quanto mais alto você definir divisions, melhor será o resultado, mas o valor padrão deverá funcionar na maioria das situações.

def smart_grid(parent, *args, **kwargs): # *args are the widgets!
    divisions   = kwargs.pop('divisions', 100)
    force_f     = kwargs.pop('force', False)
    if 'sticky' not in kwargs:
        kwargs.update(sticky='w')
    try:
        parent.win_width
    except:
        parent.win_width = -1
    winfo_width = parent.winfo_width()
    if 1 < winfo_width != parent.win_width or force_f:
        parent.win_width = winfo_width
        row = col = width = 0
        argc = len(args)
        for i in range(argc):
            widget_width = args[i].winfo_width()
            columns = max(1, int(widget_width * float(divisions) / winfo_width))
            width += widget_width
            if width > winfo_width:
                width = widget_width
                row += 1
                col = 0
            args[i].grid(row=row, column=col, columnspan=columns, **kwargs)
            col += columns
        parent.update_idletasks() # update() # 
        return row + 1

Eventualmente, levarei alguns minutos para reescrevê-lo com w.winfo_reqwidth() e atualizarei minha postagem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top