Jak uzyskać dane wejściowe z Tkinter Text Widget?

103

Jak uzyskać dane wejściowe Tkinter z Textwidżetu?

EDYTOWAĆ

Zadałem to pytanie, aby pomóc innym z tym samym problemem - z tego powodu nie ma przykładowego kodu. Ta kwestia niepokoiła mnie od wielu godzin i użyłem tego pytania, aby uczyć innych. Proszę nie ocenić go tak, jakby to było prawdziwe pytanie - odpowiedź jest rzeczą, która się liczy.

xxmbabanexx
źródło

Odpowiedzi:

136

Aby uzyskać dane wejściowe Tkintera z pola tekstowego, musisz dodać kilka dodatkowych atrybutów do normalnej .get()funkcji. Jeśli mamy pole tekstowe myText_Box, jest to metoda pobierania jego danych wejściowych.

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

Pierwsza część "1.0"oznacza, że ​​wejście powinno być czytane od pierwszego wiersza, znaku zero (czyli: pierwszego znaku). ENDjest zaimportowaną stałą, która jest ustawiona na łańcuch "end". Te ENDśrodki część czytać, dopóki nie zostanie osiągnięty koniec pola tekstowego. Jedynym problemem jest to, że faktycznie dodaje nowy wiersz do naszych danych wejściowych. Tak więc, aby to naprawić, powinniśmy zmienić ENDna end-1c(Dzięki Bryan Oakley ) -1cUsuwa 1 znak, podczas gdy -2coznaczałoby usunięcie dwóch znaków i tak dalej.

def retrieve_input():
    input = self.myText_Box.get("1.0",'end-1c')
xxmbabanexx
źródło
20
Należy to zrobić "end-1c"albo END+"1c", inaczej dostaniesz dodatkowe przełamane, że tekst widget zawsze dodaje.
Bryan Oakley,
2
@xxmbabanexx: Nie, „-1c” oznacza „minus jeden znak”.
Bryan Oakley,
2
Tego chcesz:.get('1.0', 'end-1c')
Honest Abe,
1
Dzięki! Tak z ciekawości, czy gdybym miał pisać, end+1cczy to dodałoby nową linię do kodu? Na koniec, Bryan i Honest Abe, bardzo wam dziękuję za pomoc w moich prostych pytaniach dotyczących Tkintera i Pythona. Naprawdę pomogłeś mi w głębszym zrozumieniu języka i zawsze byłeś uprzejmy, szybki, a co najważniejsze - kompetentny. Jestem pewien, że Twoja rada pomoże mi, gdy będę przenosić się do liceum i nie tylko!
xxmbabanexx
1
Dodany przykład nie działa. Cudzysłowy wokół 'end-1c'są niezbędne, aby był to pojedynczy ciąg. 'end'jest aliasem dla indeksu po ostatnim znaku. Więc jeśli 'end'był '3.8'wtedy 'end-1c'będzie '3.7'. Chcę ponownie polecić przejrzenie: Indeksy widgetów tekstowych .
Honest Abe
19

Oto jak to zrobiłem w Pythonie 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()

dzięki temu, kiedy wpisałem „bla bla” w widżecie tekstowym i nacisnąłem przycisk, cokolwiek wpisałem, zostało wydrukowane. Myślę więc, że jest to odpowiedź na przechowywanie danych wejściowych użytkownika z widżetu Tekst do zmiennej.

Skarga
źródło
9

Aby uzyskać dane wejściowe Tkinter z pola tekstowego w Pythonie 3, używany przeze mnie kompletny program dla uczniów jest następujący:

#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()
Abdul Wahid
źródło
7

W celu uzyskania w ciągu Textwidget można po prostu wykorzystać getmetodę określoną w Textktórym przyjmuje jeden do dwóch argumentów jak starti endpozycje znaków text_widget_object.get(start, end=None). Jeśli tylko startjest przekazywana i endnie przepuszcza ona zwraca tylko jeden znak umieszczony na startrazie end jest przekazywana jako dobrze, zwraca wszystkie znaki pomiędzy pozycjami starti endjako ciąg.

Istnieją również specjalne ciągi, które są zmiennymi dla bazowego Tk. Jednym z nich byłby "end"lub tk.ENDktóry reprezentuje zmienną pozycję ostatniego znaku w Textwidgecie. Przykładem może być zwrócenie całego tekstu w widgecie, z text_widget_object.get('1.0', 'end')lub, text_widget_object.get('1.0', 'end-1c')jeśli nie chcesz ostatniego znaku nowej linii.

Próbny

Zobacz poniższą demonstrację, która wybiera znaki między podanymi pozycjami za pomocą suwaków:

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()
Nie
źródło
2

Myślę, że to lepszy sposób-

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)

Po naciśnięciu przycisku zostanie wydrukowana wartość w polu tekstowym. Ale upewnij się, że importujesz ttk osobno.

Pełny kod dla podstawowych aplikacji 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()
bhaskar
źródło
0

Zmierzyłem się z problemem pobierania całego tekstu z widżetu Tekst i działało u mnie następujące rozwiązanie:

txt.get(1.0,END)

Gdzie 1.0 oznacza pierwszą linię, znak zerowy (tj. Przed pierwszym!) To pozycja początkowa, a END to pozycja końcowa.

Podziękowania dla Alana Gaulda w tym linku

Javad Norouzi
źródło
0

Przyszedłem także w poszukiwaniu sposobu uzyskania danych wejściowych z widżetu Tekst. Odnośnie problemu z nową linią na końcu łańcucha. Możesz po prostu użyć .strip (), ponieważ jest to widget tekstowy, który zawsze jest łańcuchem.

Udostępniam również kod, w którym można zobaczyć, jak można tworzyć widżety z funkcją mnożenia tekstu i zapisywać je w słowniku jako dane formularza, a następnie klikając przycisk przesyłania, uzyskać dane formularza i robić z nimi, co chcesz. Mam nadzieję, że pomaga innym. Powinien działać w każdym Pythonie 3.x i prawdopodobnie będzie również działać w 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()
PythonMan
źródło
0

Twierdziłbym, że stworzenie prostego rozszerzenia tekstu i przekształcenie textgo w właściwość jest najczystszym sposobem. Następnie możesz umieścić to rozszerzenie w jakimś pliku, który zawsze importujesz i używać go zamiast oryginalnego Textwidżetu. W ten sposób, zamiast zapamiętywać, pisać, powtarzać itp. Wszystkie obręcze, które tkinter sprawiają, że przeskakujesz do najprostszych rzeczy, masz prosty interfejs, który można ponownie wykorzystać w każdym projekcie. Możesz to również zrobić Entry, ale składnia jest nieco inna.

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()
Michael Guidry
źródło
-3

Powiedzmy, że masz Textwidżet o nazwie my_text_widget.

Aby uzyskać dane wejściowe z my_text_widget, możesz użyć getfunkcji.

Załóżmy, że dokonałeś importu tkinter. Zdefiniujmy my_text_widgetnajpierw, zróbmy to po prostu prosty widget tekstowy.

my_text_widget = Text(self)

Aby uzyskać dane wejściowe z textwidgetu, musisz użyć tej getfunkcji, zarówno, jak texti entrywidżety mają to.

input = my_text_widget.get()

Powodem, dla którego zapisujemy go w zmiennej, jest użycie go w dalszym procesie, na przykład testowaniu danych wejściowych.

Adam Rajczakowski
źródło
1
Ta odpowiedź jest nieprawidłowa. Metoda Textwidgetu getwymaga co najmniej jednego argumentu.
Bryan Oakley,