简体   繁体   English

如何从 Tkinter Text Widget 获取输入?

[英]How to get the input from the Tkinter Text Widget?

How to get Tkinter input from the Text widget?如何从Text小部件获取 Tkinter 输入?

EDIT编辑

I asked this question to help others with the same problem - that is the reason why there is no example code.我问这个问题是为了帮助遇到同样问题的其他人 -就是没有示例代码的原因。 This issue had been troubling me for hours and I used this question to teach others.这个问题困扰了我好几个小时,我用这个问题来教别人。 Please do not rate it as if it was a real question - the answer is the thing that matters.不要把它当作一个真正的问题来评价——答案才是最重要的。

To get Tkinter input from the text box, you must add a few more attributes to the normal .get() function.要从文本框中获取 Tkinter 输入,您必须向普通的.get()函数添加更多属性。 If we have a text box myText_Box , then this is the method for retrieving its input.如果我们有一个文本框myText_Box ,那么这是检索其输入的方法。

def retrieve_input():
    input = self.myText_Box.get("1.0",END)

The first part, "1.0" means that the input should be read from line one, character zero (ie: the very first character).第一部分, "1.0"意味着输入应该从第一行,字符零(即:第一个字符)读取。 END is an imported constant which is set to the string "end" . END是一个导入的常量,它被设置为字符串"end" The END part means to read until the end of the text box is reached. END部分表示一直读到文本框的末尾。 The only issue with this is that it actually adds a newline to our input.唯一的问题是它实际上为我们的输入添加了一个换行符。 So, in order to fix it we should change END to end-1c (Thanks Bryan Oakley ) The -1c deletes 1 character, while -2c would mean delete two characters, and so on.因此,为了修复它,我们应该将END更改为end-1c (感谢Bryan Oakley-1c删除 1 个字符,而-2c表示删除两个字符,依此类推。

def retrieve_input():
    input = self.myText_Box.get("1.0",'end-1c')

Here is how I did it with python 3.5.2:这是我用 python 3.5.2 做的:

from tkinter import *
root=Tk()
def retrieve_input():
    inputValue=textBox.get("1.0","end-1c")
    print(inputValue)

textBox=Text(root, height=2, width=10)
textBox.pack()
buttonCommit=Button(root, height=1, width=10, text="Commit", 
                    command=lambda: retrieve_input())
#command=lambda: retrieve_input() >>> just means do this when i press the button
buttonCommit.pack()

mainloop()

with that, when i typed "blah blah" in the text widget and pressed the button, whatever i typed got printed out.有了这个,当我在文本小部件中输入“blah blah”并按下按钮时,我输入的任何内容都会被打印出来。 So i think that is the answer for storing user input from Text widget to variable.所以我认为这是将用户输入从 Text 小部件存储到变量的答案。

To get Tkinter input from the text box in python 3 the complete student level program used by me is as under:要从 python 3 的文本框中获取 Tkinter 输入,我使用的完整学生级程序如下:

#Imports all (*) classes,
#atributes, and methods of tkinter into the
#current workspace

from tkinter import *

#***********************************
#Creates an instance of the class tkinter.Tk.
#This creates what is called the "root" window. By conventon,
#the root window in Tkinter is usually called "root",
#but you are free to call it by any other name.

root = Tk()
root.title('how to get text from textbox')


#**********************************
mystring = StringVar()

####define the function that the signup button will do
def getvalue():
##    print(mystring.get())
#*************************************

Label(root, text="Text to get").grid(row=0, sticky=W)  #label
Entry(root, textvariable = mystring).grid(row=0, column=1, sticky=E) #entry textbox

WSignUp = Button(root, text="print text", command=getvalue).grid(row=3, column=0, sticky=W) #button


############################################
# executes the mainloop (that is, the event loop) method of the root
# object. The mainloop method is what keeps the root window visible.
# If you remove the line, the window created will disappear
# immediately as the script stops running. This will happen so fast
# that you will not even see the window appearing on your screen.
# Keeping the mainloop running also lets you keep the
# program running until you press the close buton
root.mainloop()

In order to obtain the string in a Text widget one can simply use get method defined for Text which accepts 1 to 2 arguments as start and end positions of characters, text_widget_object.get(start, end=None) .为了获取Text小部件中的字符串,可以简单地使用为Text定义的get方法,该方法接受 1 到 2 个参数作为字符的startend位置text_widget_object.get(start, end=None) If only start is passed and end isn't passed it returns only the single character positioned at start , if end is passed as well, it returns all characters in between positions start and end as string.如果只传递了start而没有传递end它只返回位于start处的单个字符,如果传递了end ,它会将startend位置之间的所有字符作为字符串返回。

There are also special strings, that are variables to the underlying Tk.还有一些特殊的字符串,它们是底层 Tk 的变量 One of them would be "end" or tk.END which represents the variable position of the very last char in the Text widget.其中之一是"end"tk.END ,它表示Text小部件中最后一个字符的可变位置。 An example would be to returning all text in the widget, with text_widget_object.get('1.0', 'end') or text_widget_object.get('1.0', 'end-1c') if you don't want the last newline character.一个例子是返回小部件中的所有文本,如果您不想要最后一个换行符,则使用text_widget_object.get('1.0', 'end')text_widget_object.get('1.0', 'end-1c') .

Demo演示

See below demonstration that selects the characters in between the given positions with sliders:请参阅以下演示,使用滑块选择给定位置之间的字符:

try:
    import tkinter as tk
except:
    import Tkinter as tk


class Demo(tk.LabelFrame):
    """
    A LabeFrame that in order to demonstrate the string returned by the
    get method of Text widget, selects the characters in between the
    given arguments that are set with Scales.
    """

    def __init__(self, master, *args, **kwargs):
        tk.LabelFrame.__init__(self, master, *args, **kwargs)
        self.start_arg = ''
        self.end_arg = None
        self.position_frames = dict()
        self._create_widgets()
        self._layout()
        self.update()


    def _create_widgets(self):
        self._is_two_args = tk.Checkbutton(self,
                                    text="Use 2 positional arguments...")
        self.position_frames['start'] = PositionFrame(self,
                                    text="start='{}.{}'.format(line, column)")
        self.position_frames['end'] = PositionFrame(   self,
                                    text="end='{}.{}'.format(line, column)")
        self.text = TextWithStats(self, wrap='none')
        self._widget_configs()


    def _widget_configs(self):
        self.text.update_callback = self.update
        self._is_two_args.var = tk.BooleanVar(self, value=False)
        self._is_two_args.config(variable=self._is_two_args.var,
                                    onvalue=True, offvalue=False)
        self._is_two_args['command'] = self._is_two_args_handle
        for _key in self.position_frames:
            self.position_frames[_key].line.slider['command'] = self.update
            self.position_frames[_key].column.slider['command'] = self.update


    def _layout(self):
        self._is_two_args.grid(sticky='nsw', row=0, column=1)
        self.position_frames['start'].grid(sticky='nsew', row=1, column=0)
        #self.position_frames['end'].grid(sticky='nsew', row=1, column=1)
        self.text.grid(sticky='nsew', row=2, column=0,
                                                    rowspan=2, columnspan=2)
        _grid_size = self.grid_size()
        for _col in range(_grid_size[0]):
            self.grid_columnconfigure(_col, weight=1)
        for _row in range(_grid_size[1] - 1):
            self.grid_rowconfigure(_row + 1, weight=1)


    def _is_two_args_handle(self):
        self.update_arguments()
        if self._is_two_args.var.get():
            self.position_frames['end'].grid(sticky='nsew', row=1, column=1)
        else:
            self.position_frames['end'].grid_remove()


    def update(self, event=None):
        """
        Updates slider limits, argument values, labels representing the
        get method call.
        """

        self.update_sliders()
        self.update_arguments()


    def update_sliders(self):
        """
        Updates slider limits based on what's written in the text and
        which line is selected.
        """

        self._update_line_sliders()
        self._update_column_sliders()


    def _update_line_sliders(self):
        if self.text.lines_length:
            for _key in self.position_frames:
                self.position_frames[_key].line.slider['state'] = 'normal'
                self.position_frames[_key].line.slider['from_'] = 1
                _no_of_lines = self.text.line_count
                self.position_frames[_key].line.slider['to'] = _no_of_lines
        else:
            for _key in self.position_frames:
                self.position_frames[_key].line.slider['state'] = 'disabled'


    def _update_column_sliders(self):
        if self.text.lines_length:
            for _key in self.position_frames:
                self.position_frames[_key].column.slider['state'] = 'normal'
                self.position_frames[_key].column.slider['from_'] = 0
                _line_no = int(self.position_frames[_key].line.slider.get())-1
                _max_line_len = self.text.lines_length[_line_no]
                self.position_frames[_key].column.slider['to'] = _max_line_len
        else:
            for _key in self.position_frames:
                self.position_frames[_key].column.slider['state'] = 'disabled'


    def update_arguments(self):
        """
        Updates the values representing the arguments passed to the get
        method, based on whether or not the 2nd positional argument is
        active and the slider positions.
        """

        _start_line_no = self.position_frames['start'].line.slider.get()
        _start_col_no = self.position_frames['start'].column.slider.get()
        self.start_arg = "{}.{}".format(_start_line_no, _start_col_no)
        if self._is_two_args.var.get():
            _end_line_no = self.position_frames['end'].line.slider.get()
            _end_col_no = self.position_frames['end'].column.slider.get()
            self.end_arg = "{}.{}".format(_end_line_no, _end_col_no)
        else:
            self.end_arg = None
        self._update_method_labels()
        self._select()


    def _update_method_labels(self):
        if self.end_arg:
            for _key in self.position_frames:
                _string = "text.get('{}', '{}')".format(
                                                self.start_arg, self.end_arg)
                self.position_frames[_key].label['text'] = _string
        else:
            _string = "text.get('{}')".format(self.start_arg)
            self.position_frames['start'].label['text'] = _string


    def _select(self):
        self.text.focus_set()
        self.text.tag_remove('sel', '1.0', 'end')
        self.text.tag_add('sel', self.start_arg, self.end_arg)
        if self.end_arg:
            self.text.mark_set('insert', self.end_arg)
        else:
            self.text.mark_set('insert', self.start_arg)


class TextWithStats(tk.Text):
    """
    Text widget that stores stats of its content:
    self.line_count:        the total number of lines
    self.lines_length:      the total number of characters per line
    self.update_callback:   can be set as the reference to the callback
                            to be called with each update
    """

    def __init__(self, master, update_callback=None, *args, **kwargs):
        tk.Text.__init__(self, master, *args, **kwargs)
        self._events = ('<KeyPress>',
                        '<KeyRelease>',
                        '<ButtonRelease-1>',
                        '<ButtonRelease-2>',
                        '<ButtonRelease-3>',
                        '<Delete>',
                        '<<Cut>>',
                        '<<Paste>>',
                        '<<Undo>>',
                        '<<Redo>>')
        self.line_count = None
        self.lines_length = list()
        self.update_callback = update_callback
        self.update_stats()
        self.bind_events_on_widget_to_callback( self._events,
                                                self,
                                                self.update_stats)


    @staticmethod
    def bind_events_on_widget_to_callback(events, widget, callback):
        """
        Bind events on widget to callback.
        """

        for _event in events:
            widget.bind(_event, callback)


    def update_stats(self, event=None):
        """
        Update self.line_count, self.lines_length stats and call
        self.update_callback.
        """

        _string = self.get('1.0', 'end-1c')
        _string_lines = _string.splitlines()
        self.line_count = len(_string_lines)
        del self.lines_length[:]
        for _line in _string_lines:
            self.lines_length.append(len(_line))
        if self.update_callback:
            self.update_callback()


class PositionFrame(tk.LabelFrame):
    """
    A LabelFrame that has two LabelFrames which has Scales.
    """

    def __init__(self, master, *args, **kwargs):
        tk.LabelFrame.__init__(self, master, *args, **kwargs)
        self._create_widgets()
        self._layout()


    def _create_widgets(self):
        self.line = SliderFrame(self, orient='vertical', text="line=")
        self.column = SliderFrame(self, orient='horizontal', text="column=")
        self.label = tk.Label(self, text="Label")


    def _layout(self):
        self.line.grid(sticky='ns', row=0, column=0, rowspan=2)
        self.column.grid(sticky='ew', row=0, column=1, columnspan=2)
        self.label.grid(sticky='nsew', row=1, column=1)
        self.grid_rowconfigure(1, weight=1)
        self.grid_columnconfigure(1, weight=1)


class SliderFrame(tk.LabelFrame):
    """
    A LabelFrame that encapsulates a Scale.
    """

    def __init__(self, master, orient, *args, **kwargs):
        tk.LabelFrame.__init__(self, master, *args, **kwargs)

        self.slider = tk.Scale(self, orient=orient)
        self.slider.pack(fill='both', expand=True)


if __name__ == '__main__':
    root = tk.Tk()
    demo = Demo(root, text="text.get(start, end=None)")

    with open(__file__) as f:
        demo.text.insert('1.0', f.read())
    demo.text.update_stats()
    demo.pack(fill='both', expand=True)
    root.mainloop()

I think this is a better way-我认为这是一个更好的方法-

variable1=StringVar() # Value saved here

def search():
  print(variable1.get())
  return ''

ttk.Entry(mainframe, width=7, textvariable=variable1).grid(column=2, row=1)

ttk.Label(mainframe, text="label").grid(column=1, row=1)

ttk.Button(mainframe, text="Search", command=search).grid(column=2, row=13)

On pressing the button, the value in the text field would get printed.按下按钮时,将打印文本字段中的值。 But make sure You import the ttk separately.但请确保您单独导入 ttk。

The full code for a basic application is-基本应用程序完整代码是-

from tkinter import *
from tkinter import ttk

root=Tk()
mainframe = ttk.Frame(root, padding="10 10 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)


variable1=StringVar() # Value saved here

def search():
  print(variable1.get())
  return ''

ttk.Entry(mainframe, width=7, textvariable=variable1).grid(column=2, row=1)

ttk.Label(mainframe, text="label").grid(column=1, row=1)

ttk.Button(mainframe, text="Search", command=search).grid(column=2, row=13)

root.mainloop()

I would argue that creating a simple extension of Text and turning text into a property is the cleanest way to go.我认为创建 Text 的简单扩展并将text转换为属性是最简洁的方法。 You can then stick that extension in some file that you always import, and use it instead of the original Text widget.然后,您可以将该扩展名粘贴到您始终导入的某个文件中,并使用它代替原始的Text小部件。 This way, instead of having to remember, write, repeat, etc all the hoops tkinter makes you jump through to do the simplest things, you have a butt-simple interface that can be reused in any project.通过这种方式,您不必记住、编写、重复等所有 tkinter 使您跳过去做最简单的事情,而是拥有一个可以在任何项目中重用的简单界面。 You can do this for Entry , as well, but the syntax is slightly different.您也可以对Entry执行此操作,但语法略有不同。

import tkinter as tk

root = tk.Tk()    
    
class Text(tk.Text):
    @property
    def text(self) -> str:
        return self.get('1.0', 'end-1c')
        
    @text.setter
    def text(self, value) -> None:
        self.replace('1.0', 'end-1c', value)
        
    def __init__(self, master, **kwargs):
        tk.Text.__init__(self, master, **kwargs)

#Entry version of the same concept as above      
class Entry(tk.Entry):
    @property
    def text(self) -> str:
        return self.get()
        
    @text.setter
    def text(self, value) -> None:
        self.delete(0, 'end')
        self.insert(0, value)
        
    def __init__(self, master, **kwargs):
        tk.Entry.__init__(self, master, **kwargs)      
      
textbox = Text(root)
textbox.grid()

textbox.text = "this is text" #set
print(textbox.text)           #get  

entry = Entry(root)
entry.grid()

entry.text = 'this is text'   #set
print(entry.text)             #get

root.mainloop()

I faced the problem of gettng entire text from Text widget and following solution worked for me :我遇到了从 Text 小部件获取整个文本的问题,以下解决方案对我有用:

txt.get(1.0,END)

Where 1.0 means first line, zeroth character (ie before the first!) is the starting position and END is the ending position.其中 1.0 表示第一行,第零个字符(即在第一个之前!)是起始位置,END 是结束位置。

Thanks to Alan Gauld in this link感谢 Alan Gauld 在此链接中

I did come also in search of how to get input data from the Text widget.我确实也是为了寻找如何从 Text 小部件获取输入数据。 Regarding the problem with a new line on the end of the string.关于字符串末尾换行的问题。 You can just use .strip() since it is a Text widget that is always a string.您可以只使用 .strip() 因为它是一个始终是字符串的 Text 小部件。

Also, I'm sharing code where you can see how you can create multiply Text widgets and save them in the dictionary as form data, and then by clicking the submit button get that form data and do whatever you want with it.此外,我正在共享代码,您可以在其中看到如何创建多个 Text 小部件并将它们作为表单数据保存在字典中,然后通过单击提交按钮获取该表单数据并对其进行任何操作。 I hope it helps others.我希望它可以帮助其他人。 It should work in any 3.x python and probably will work in 2.7 also.它应该适用于任何 3.x python 并且可能也适用于 2.7。

from tkinter import *
from functools import partial

class SimpleTkForm(object):
    def __init__(self):
        self.root = Tk()

    def myform(self):
        self.root.title('My form')
        frame = Frame(self.root, pady=10)
        form_data = dict()
        form_fields = ['username', 'password', 'server name', 'database name']
        cnt = 0
        for form_field in form_fields:
            Label(frame, text=form_field, anchor=NW).grid(row=cnt,column=1, pady=5, padx=(10, 1), sticky="W")
            textbox = Text(frame, height=1, width=15)
            form_data.update({form_field: textbox})
            textbox.grid(row=cnt,column=2, pady=5, padx=(3,20))
            cnt += 1

        conn_test = partial(self.test_db_conn, form_data=form_data)
        Button(frame, text='Submit', width=15, command=conn_test).grid(row=cnt,column=2, pady=5, padx=(3,20))
        frame.pack()
        self.root.mainloop()

    def test_db_conn(self, form_data):
        data = {k:v.get('1.0', END).strip() for k,v in form_data.items()}
        # validate data or do anything you want with it
        print(data)


if __name__ == '__main__':
    api = SimpleTkForm()
    api.myform()

Lets say that you have a Text widget called my_text_widget .假设您有一个名为my_text_widgetText小部件。

To get input from the my_text_widget you can use the get function.要从my_text_widget获取输入,您可以使用get函数。

Let's assume that you have imported tkinter .假设您已导入tkinter Lets define my_text_widget first, lets make it just a simple text widget.让我们先定义my_text_widget ,让它只是一个简单的文本小部件。

my_text_widget = Text(self)

To get input from a text widget you need to use the get function, both, text and entry widgets have this.要从text小部件获取输入,您需要使用get函数, textentry小部件都具有此功能。

input = my_text_widget.get()

The reason we save it to a variable is to use it in the further process, for example, testing for what's the input.我们将它保存到变量的原因是为了在进一步的过程中使用它,例如,测试输入是什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM