如何从 Tkinter 文本小部件获得输入?

如何从 Text小部件获得 Tkinter 输入?

剪辑

我问这个问题是为了帮助其他人解决同样的问题—— 那个就是没有示例代码的原因。这个问题困扰了我好几个小时,我用这个问题来教别人。求你了不评价它好像它是一个真正的问题-答案是事情的关键。

323570 次浏览

要从文本框中获取 Tkinter 输入,必须向普通的 .get()函数添加几个属性。如果我们有一个文本框 myText_Box,那么这就是检索其输入的方法。

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

第一部分 "1.0"意味着输入应该从第一行字符0(即第一个字符)读取。END是导入的常量,设置为字符串 "end"END部分的意思是读到文本框的末尾。唯一的问题是它实际上向输入添加了一个换行符。因此,为了解决这个问题,我们应该将 END改为 end-1c(感谢 布莱恩 · 奥克利)。 -1c删除1个字符,而 -2c意味着删除两个字符,以此类推。

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

要从 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()

下面是我在 python 3.5中的做法:

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()

这样,当我在文本小部件中输入“吧啦吧啦”并按下按钮时,我输入的任何内容都会被打印出来。因此,我认为这是存储用户输入从文本小部件到变量的答案。

为了获得 Text小部件中的字符串,可以简单地使用为 Text定义的 get2方法,该方法接受1到2个参数作为字符 startend的位置,即 text_widget_object.get(start, end=None)。如果只传递了 start,而没有传递 end,那么它只返回定位在 start的单个字符,如果 end也传递了 get3,那么它将返回位置 startend之间的所有字符作为字符串。

还有一些特殊的字符串,它们是底层 Tk 的 变量。其中之一是 "end"tk.END,它代表 Text小部件中最后一个字符的可变位置。一个例子是返回小部件中的所有文本,如果不想要最后一个换行符,则使用 text_widget_object.get('1.0', 'end')text_widget_object.get('1.0', 'end-1c')

演示

请看下面的演示,选择的字符之间的给定位置与滑块:

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()

我觉得这样更好

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)

在按下按钮时,文本字段中的值将被打印出来。 但要确保你单独导入 TTK。

基本应用完整代码是-

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()

假设您有一个名为 my_text_widgetText小部件。

要从 my_text_widget输入 走开,可以使用 get函数。

让我们假设您已经导入了 tkinter。 让我们先定义 my_text_widget,让它只是一个简单的文本小部件。

my_text_widget = Text(self)

对于 text小部件的 走开输入,您需要使用 get函数,textentry小部件都有这个函数。

input = my_text_widget.get()

我们将它保存到一个变量中的原因是为了在进一步的过程中使用它,例如,测试输入是什么。

我遇到了从 Text widget 获取整个文本的问题,下面的解决方案对我很有效:

txt.get(1.0,END)

其中1.0表示第一行,第零个字符(即在第一个字符之前!) 是起始位置,END 是结束位置。

感谢艾伦高尔德在这 链接

我还来搜索如何从 Text 小部件获取输入数据。关于字符串末尾新行的问题。你可以用。Strip () ,因为它是一个总是字符串的 Text 小部件。

此外,我还分享了一些代码,在这些代码中,您可以看到如何创建多重 Text 小部件并将它们作为表单数据保存在字典中,然后通过单击提交按钮获取表单数据并对其进行任何处理。我希望它能帮助别人。它应该可以在任何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()

我认为创建一个简单的 Text 扩展并将 text转换为一个属性是最干净的方法。然后,您可以将该扩展插件插入到您总是导入的某个文件中,并使用它来代替原始的 Text小部件。这样,你就不必记住、写、重复等所有这些让你跳过去做最简单的事情,你有一个对接简单的界面,可以在任何项目中重用。对于 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()