Python Tkinter umschließt Widgets im Frame, wenn sie das Ende des Bildschirms erreichen


Answers

Im Allgemeinen stimme ich der Antwort von I_do_python zu, aber ich würde eine kleine Änderung vornehmen. Ich würde alle Widgets in einen neuen Frame einfügen, und ich würde die Breite des Frames als Lackmustest verwenden, um zu verpacken. Und Sie können einen Event-Handler für das Ereignis "<Configure>" binden, das dann prüft, ob der Inhalt des Frames umbrochen werden muss, wenn das Fenster der Anwendung (und damit der Frame) in der Größe geändert wird.

Ich hatte die folgende Funktion geschrieben, die die Grid-Methode verwendet, um Widgets intelligent in einen Rahmen einzufügen. Es kann sicherlich verbessert werden, aber es funktioniert für mich. Gewöhnlich, wenn Sie .grid() , um einen Elternteil zu füllen, können Sie .grid() Leerraum bekommen, wenn die füllenden Widgets in der Breite variieren. Die folgende Funktion behebt dies, indem das übergeordnete Element in logische Spalten ( divisions im Code) aufgespalten wird und die Widgets sich über mehrere Spalten erstrecken. Das Ergebnis ist ein Rasterlayout mit viel reduziertem verschwendeten Leerraum. Je höher Sie die divisions , desto besser ist das Ergebnis, aber der Standardwert sollte für die meisten Situationen funktionieren.

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

Schließlich werde ich ein paar Minuten w.winfo_reqwidth() , um es mit w.winfo_reqwidth() umzuschreiben und werde meinen Beitrag aktualisieren.

Question

Gibt es für den Tk Geometry Manager etwas wie eine neue Zeile? Ich benutze Pack, um Widgets in einen Frame zu setzen. Auf einem hochauflösenden Bildschirm passen die Widgets nebeneinander. Wenn Sie es jedoch auf einen kleineren Bildschirm stellen, wird den Widgets im Bildrahmen kein Platz mehr zur Verfügung stehen.

Grundsätzlich gehen wir von:

zu:

Sie können sehen, wie es von meinem Processors-Eingabefeld abgeschnitten wird. Der relevante Code:

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)

Ein Großteil der Eventbindung und Einstellung der Optionen mag nicht relevant sein, aber ich dachte, ich sollte immer noch ... nur für den Fall einschließen. Wäre die beste Option, zu einem Grid Manager zu wechseln? Das Problem wäre, dass dieser Rahmen in einen anderen gepackt ist ... und so weiter. Ist es nicht so, dass Sie, wenn Sie den Grid-Manager verwenden, ihn für alles verwenden müssen, weil Sie den Packed- und Grid-Manager nicht im selben Frame mischen können?