Tkinter Metin Widget'ından girdi nasıl alınır?


106

Widget'tan Tkinter girdisi nasıl alınır Text?

DÜZENLE

Aynı sorunla yardım başkalarına bu soruyu sordu - o hiçbir örnek kod yoktur nedeni budur. Bu konu beni saatlerdir rahatsız ediyordu ve bu soruyu başkalarına öğretmek için kullandım. Lütfen gerçek bir soru gibi değerlendirmeyin - önemli olan cevaptır.

Yanıtlar:


138

Metin kutusundan Tkinter girdisi almak için, normal .get()işleve birkaç özellik daha eklemelisiniz . Bir metin kutumuz varsa myText_Box, bu onun girdisini alma yöntemidir.

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

İlk kısım, "1.0"girişin birinci satırdan, karakter sıfırdan (yani: ilk karakterden) okunması gerektiği anlamına gelir. ENDdizeye ayarlanmış içe aktarılmış bir sabittir "end". ENDMetin kutusunun sonuna ulaşılıncaya kadar bölüm aracı okumak için. Bununla ilgili tek sorun, girdimize aslında bir satırsonu eklemesi. Bu yüzden, düzeltmek için değiştirmemiz ENDgerekir end-1c(Teşekkürler Bryan Oakley ) -1c1 karakteri -2csilerken, iki karakteri silmek anlamına gelir, vb.

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

20
Sen yapmalıyım "end-1c"veya END+"1c"aksi takdirde metin Widget her zaman eklediği ekstra yeni satır alırsınız.
Bryan Oakley

2
@xxmbabanexx: Hayır, "-1c", "eksi bir karakter" anlamına gelir.
Bryan Oakley

2
İstediğin şey bu:.get('1.0', 'end-1c')
Dürüst Abe

1
Teşekkürler! Merak ediyorum, eğer yazacak olsaydım, end+1cbu koda yeni bir satır ekler mi? Son olarak Bryan ve Dürüst Abe, basit Tkinter ve Python sorularımda bana yardımcı olduğunuz için çok teşekkür ederim. Dili daha derinlemesine anlamama gerçekten yardımcı oldunuz ve her zaman nazik, hızlı ve en iyisi - bilinebilir davrandınız. Liseye ve ötesine geçerken tavsiyenizin bana yardımcı olacağına eminim!
xxmbabanexx

1
Eklediğiniz örnek işe yaramıyor. 'end-1c'Tek bir dize olması için etrafındaki tırnak işaretleri gereklidir. 'end'son karakterden sonraki dizinin diğer adıdır. Yani eğer 'end'oldu '3.8'o zaman 'end-1c'olurdu '3.7'. Tekrar gözden geçirmenizi tavsiye etmek istiyorum: Metin widget indeksleri .
Dürüst Abe

20

İşte bunu python 3.5.2 ile nasıl yaptım:

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

bununla, metin widget'ına "blah blah" yazıp düğmeye bastığımda, yazdığım her şey yazdırıldı. Bu yüzden, Metin widget'ından değişkene kullanıcı girişini depolamanın cevabı budur.


9

Python 3'teki metin kutusundan Tkinter girdisi almak için, kullandığım tam öğrenci seviyesi programı aşağıdaki gibidir:

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

7

Bir Textparçacığın içindeki dizeyi elde etmek getiçin, Textkendisi için 1 ila 2 argümanı startve endkarakterlerin konumlarını kabul eden, tanımlanan yöntemi basitçe kullanabiliriz text_widget_object.get(start, end=None). Keşke startgeçirilir ve endyalnızca yerleştirilmiş tek bir karakter döndürür geçirilmediği starttakdirde, end bir sıra geçti, bu konumları arasında tüm karakterleri verir startve endstring.

Ayrıca temel Tk değişkenleri olan özel dizgeler de vardır . Bunlardan biri, "end"veya parçacığın tk.ENDen son karakterinin değişken konumunu temsil eder Text. Son satırsonu karakteri ile text_widget_object.get('1.0', 'end')veya text_widget_object.get('1.0', 'end-1c')istemiyorsanız, widget'taki tüm metni döndürmek buna bir örnek olabilir .

Demo

Kaydırıcılarla verilen konumlar arasındaki karakterleri seçen aşağıdaki gösterime bakın :

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

2

Bunun daha iyi bir yol olduğunu düşünüyorum.

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)

Düğmeye basıldığında, metin alanındaki değer yazdırılır. Ancak ttk'yi ayrı olarak içe aktardığınızdan emin olun.

Tam kod bir için temel bir uygulama 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()

0

Ayrıca Metin widget'ından giriş verilerini nasıl alacağımı araştırmaya geldim. Dizenin sonundaki yeni bir satırdaki problemle ilgili olarak. Her zaman bir dize olan bir Metin widget'ı olduğu için .strip () kullanabilirsiniz.

Ayrıca, çoklu Metin widget'larını nasıl oluşturabileceğinizi ve bunları sözlüğe form verileri olarak kaydedebileceğinizi görebileceğiniz ve ardından gönder düğmesine tıklayarak bu form verilerini alabileceğiniz ve onunla istediğinizi yapabileceğiniz kodu paylaşıyorum. Umarım başkalarına yardımcı olur. Herhangi bir 3.x python'da çalışmalı ve muhtemelen 2.7'de de çalışacaktır.

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

Arayan stripfazla Widget birkaç boş satırlar varsa sadece tek sondaki satırdan başka silme yeterli olabilir. Amaç, kullanıcının girdiği şeyi tam olarak almaksa, bu doğru çözüm değildir.
Bryan Oakley

0

Metin için basit bir uzantı oluşturmanın ve textbir özelliğe dönüştürmenin en temiz yol olduğunu iddia ediyorum . Daha sonra bu uzantıyı her zaman içe aktardığınız bir dosyaya yapıştırabilir ve orijinal Textwidget yerine kullanabilirsiniz . Bu şekilde, hatırlamak, yazmak, tekrarlamak vb. Zorunda kalmak yerine, tüm çemberler en basit şeyleri yapmak için atlamanızı sağlar, herhangi bir projede yeniden kullanılabilecek basit bir arayüze sahip olursunuz. Bunu için de yapabilirsiniz Entry, ancak sözdizimi biraz farklıdır.

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

Ayarlayıcıyı kullanmak, ihtiyacınız olan tek şey metin widget'ının tüm içeriğiyse iyidir. Ancak, genellikle metnin yalnızca bir bölümünü çıkarmanız gerekir (örneğin, bir kelimeyi, cümleyi veya paragrafı keserken). Bu yüzden bu "çemberler" var.
Bryan Oakley

@BryanOakley - Sana ilgili kolayca kabul edebilir tk.Text... çok değil ilgili tk.Entry.
Michael Guidry

-1

Metin widget'ından tüm metni alma sorunuyla karşılaştım ve aşağıdaki çözüm benim için çalıştı:

txt.get(1.0,END)

1.0, ilk satır anlamına gelirken, sıfırıncı karakter (yani ilk karakterden önce!) Başlangıç ​​konumudur ve END, bitiş konumudur.

Bu bağlantıdaki Alan Gauld'a teşekkürler


İlk argüman tırnak içinde olmalıdır. Bu bir kayan sayı değil, iki tam sayı ve nokta ayırıcı içeren bir dizedir.
RufusVS

Bu bağlantıda bu hata vardı ve bu bağlantının kaynağı bile hatalıydı. İşte daha iyi bir bağlantı: mail.python.org/pipermail/tutor/2005-February/035667.html
RufusVS

Bu, soruda yazılan problemin aynısını verecektir. Artı, teknik olarak, dizin 1.0doğru değil. Dizinler dizelerdir, kayan noktalı sayılar değildir. Tkinter bu konuda biraz affedicidir 1.0ve "1.0"aynı şekilde muamele görür ama benzer bir 1.10şey kesinlikle aynı değildir "1.10".
Bryan Oakley

-3

Adında bir Textwidget'ınız olduğunu varsayalımmy_text_widget .

To get girdi my_text_widgetkullanabilirsinizget işlevi.

İthal ettiğinizi varsayalım tkinter. my_text_widgetÖnce tanımlayalım , onu sadece basit bir metin widget'ı yapalım.

my_text_widget = Text(self)

To olsun bir girdi textwidget'ı kullanmak gerekir getişlevi, hem textve entrywidget'lar bu var.

input = my_text_widget.get()

Onu bir değişkene kaydetmemizin nedeni, onu sonraki işlemlerde kullanmaktır, örneğin, girdinin ne olduğunu test etmek.


1
Bu cevap yanlış. TextEklendi getyöntem, en az bir bağımsız değişken gerektirir.
Bryan Oakley
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.