6

コンテンツに合わせて Tkinter テキスト ウィジェットのサイズを変更することは可能ですか?

つまり、テキストを 1 行入れると縮小しますが、5 行入れると大きくなります

4

4 に答える 4

7

これを達成する唯一の方法は、ユーザーが Text ウィジェットにテキストを入力するたびに幅と高さを計算し、ウィジェットのサイズをそれに設定することです。ただし、ここでの制限は、等幅フォントのみが正しく機能することですが、ここではとにかく:

import Tkinter

class TkExample(Tkinter.Frame):
   def __init__(self, parent):
      Tkinter.Frame.__init__(self, parent)
      self.init_ui()

   def init_ui(self):
      self.pack()
      text_box = Tkinter.Text(self)
      text_box.pack()
      text_box.bind("<Key>", self.update_size)

   def update_size(self, event):
      widget_width = 0
      widget_height = float(event.widget.index(Tkinter.END))
      for line in event.widget.get("1.0", Tkinter.END).split("\n"):
         if len(line) > widget_width:
            widget_width = len(line)+1
      event.widget.config(width=widget_width, height=widget_height)

if __name__ == '__main__':
    root = Tkinter.Tk()
    TkExample(root)
    root.mainloop()
于 2012-07-18T15:41:36.690 に答える
4

このスレッドは Google 検索の一番上にあったので、これを必要としている人が見つけてくれるかもしれません。何時間も検索しても答えが見つかりませんでした。そこで、私が思いついたHACKがこれです。

私は、ユーザー入力ではなく、Text ウィジェット内の未知の、しかし事前に定義されたテキストの周りに正しくフォーム フィットするポップアップ ウィンドウが必要でした。また、テキスト ウィジェットは、そのテキスト コンテンツの周りに正しくフォーム フィットする必要があります。

Aはうまく機能しますが、tkinter.Labelがなく、一部の HTML タグを tkinter のリッチ テキスト タグに置き換える必要がありました。  にはリッチ テキスト タグがありますが、適切に展開されません。一方、適切に展開されますが、リッチ テキスト タグはありません。さらに、本当に必要でない限り、スクロールバーとワードラップが嫌いです。これはまさに私が望んでいたことを行います。ただし、これはこのフォーラムの非常に単純な実用的な要約です。任意のフォントで動作します。Ubuntu 13.10 (Linux) の Python 3.3 でのみテストされています。tkinter.Text.tag_configuretkinter.Text.tag_bindtkinter.Texttkinter.Label

#!/usr/bin/env python3

import tkinter as tk

class MyFrame(tk.Frame):
    def __init__(self):
        tk.Frame.__init__(self)

        root = self.master
        root.title("My Window Title")

        # Pack Frame into root window and make it expand in "both" x and y
        self.pack(side="top", fill="both", expand=True, padx=10, pady=10)
        # Statistical weight of 1 = 100% for cell (0, 0) to expand 100%
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)

        # The string text
        text = """Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed
diam nonummy nibh euismod tincidunt ut laoreet dolore magna
aliquam erat volutpat. Ut wisi enim ad minim veniam, quis
nostrud exerci tation ullamcorper suscipit lobortis nisl ut
aliquip ex ea commodo consequat. Duis autem vel eum iriure
dolor in hendrerit in vulputate velit esse molestie consequat,
vel illum dolore eu feugiat nulla facilisis at vero eros et
accumsan et iusto odio dignissim qui blandit praesent luptatum
zzril delenit augue duis dolore te feugait nulla facilisi. Nam
liber tempor cum soluta nobis eleifend option congue nihil
imperdiet doming id quod mazim placerat facer possim assum.
Typi non habent claritatem insitam; est usus legentis in iis qui
facit eorum claritatem. Investigationes demonstraverunt lectores
legere me lius quod ii legunt saepius. Claritas est etiam
processus dynamicus, qui sequitur mutationem consuetudium
lectorum. Mirum est notare quam littera gothica, quam nunc
putamus parum claram, anteposuerit litterarum formas
humanitatis per seacula quarta decima et quinta decima. Eodem
modo typi, qui nunc nobis videntur parum clari, fiant sollemnes
in futurum."""

        # Add a tk.Text widget to Frame (self) and its configuration
        textwidget = tk.Text(self, wrap="none", font=("Comic Sans MS", 12),
                             padx=10, pady=10)
        textwidget.grid(row=0, column=0, sticky="nesw")
        # Add the text to textwidget and disable editing
        textwidget.insert(tk.END, text)
        textwidget.config(state=tk.DISABLED)

        # Here is where the HACK begins
        def is_scroll(wh, lower, upper):
            nonlocal size
            size[wh][0] = upper < '1.0' or lower > '0.0'
            size[wh][1] += 20 * size[wh][0] # += 1 for accuracy but slower
        # Call the is_scroll function when textwidget scrolls
        textwidget.config(xscrollcommand=lambda *args: is_scroll('w', *args),
                          yscrollcommand=lambda *args: is_scroll('h', *args))

        # Add a tk.Button to the Frame (self) and its configuration
        tk.Button(self, text="OK", command=self.quit).grid(row=1, column=0,
                                                           sticky="we")

        # For reasons of magic, hide root window NOW before updating
        root.withdraw()

        # Initially, make root window a minimum of 50 x 50 just for kicks
        root.geometry('50x50')
        size = {'w': [False, 50], 'h': [False, 50]}
        # Update to trigger the is_scroll function
        root.update()
        while size['w'][0] or size['h'][0]:
            # If here, we need to update the size of the root window
            root.geometry('{}x{}'.format(size['w'][1], size['h'][1]))
            root.update()

        # Center root window on mouse pointer
        x, y = root.winfo_pointerxy()
        root.geometry('+{}+{}'.format(x-size['w'][1]//2, y-size['h'][1]//2))

        # Now reveal the root window in all its glory
        root.deiconify()

        # Print textwidget dimensions to the console
        print(textwidget.winfo_width(), textwidget.winfo_height())

def main():
    """Show main window."""
    MyFrame().mainloop()

if __name__ == '__main__':
    main()

説明:  トリックは、Text ウィジェットを直接拡大または縮小しようとする無益さを気にしないことです。答えは少し直感に反するものです。なぜなら、最初に考えたのは、その Text ウィジェットに直接行って何かをすることだからです。代わりに、ルート (最も外側の) ウィンドウ (この場合はself.master) を展開し、Text ウィジェットはそのままにしておきます。簡単です。

"nesw"ルート ウィンドウで 100% 拡張用にパックされたフレームに Text ウィジェットをスティッキー ( ) します。ルート ウィンドウが拡大すると、その中の Frame と Text ウィジェットも拡大します。ただし、ルート ウィンドウを展開しているときは、Text ウィジェットの と の境界が消えているかどうかをテストします(lowerこれupper以上スクロールしません)。これらのコマンドは、スクロールバーに必要なコールバック関数 (通常は. ただし、スクロールバーやスクロールはまったく必要ないため、これらのコマンドを使用しています。私たちは完璧なフィット感を求めています。xscrollcommandyscrollcommandloweruppertkinter.Scrollbar.set

lowerおよび境界が消失した場合upper(下限 <= 0.0 および上限 >= 1.0)、テキスト ウィジェットの周囲に完全に適合したウィンドウがあり、テキスト コンテンツの周囲にも完全に適合していることを意味します。多田!

他のウィジェットを追加しても正しく動作することを示すボタンを追加しました。一部のテキストを削除して、フォームが完全に適合していることを確認します。

于 2014-03-14T11:25:58.880 に答える
1

編集:ショートメソッド:

text.pack(side="top", fill="both", expand=True, padx=0, pady=0)

sc0tt の回答と Bryan Oakley の回答 ここGet of number of lines of a Text tkinter widget を再利用することで、プロポーショナル フォントでも機能するこのすぐに使えるコード (将来の参照のためにここに投稿) を作成できます。

import Tkinter as Tk
import tkFont

class Texte(Tk.Text):
    def __init__(self, event=None, x=None, y=None, size=None, txt=None, *args, **kwargs):
        Tk.Text.__init__(self, master=root, *args, **kwargs)
        self.font = tkFont.Font(family="Helvetica Neue LT Com 55 Roman",size=35)
        self.place(x=10,y=10)
        self.insert(Tk.INSERT,' blah ')
        self.config(font=self.font)
        self.update_size(event=None)
        bindtags = list(self.bindtags())
        bindtags.insert(2, "custom")
        self.bindtags(tuple(bindtags))
        self.bind_class("custom", "<Key>", self.update_size)

    def update_size(self, event):
        width=0
        lines=0
        for line in self.get("1.0", "end-1c").split("\n"):
            width=max(width,self.font.measure(line))
            lines += 1
        self.config(height=lines)
        self.place(width=width+10)

root = Tk.Tk()
root.geometry("500x500")
Texte()
root.mainloop()
于 2013-12-13T13:08:55.777 に答える