searching in strings from tk-inter text fails - python

Why does the search fail when taking a string from a tk-inter text box?
The search works fine if I define the keyword as a string.
Minimal example:
import tkinter as tk
root = tk.Tk()
string="banana\napplepie\napple\n"
def searchcall():
textboxcontent=textExample.get("1.0","end")
keyword=filterbox.get("1.0","end")
keyword="apple" # search works as expected
print("keyword",keyword)
print("is keyword in textbox",keyword in textboxcontent)
for elem in textboxcontent.split():
print("seaching for",keyword,"in",elem,keyword in elem)
textExample=tk.Text(root, height=10)
textExample.insert(1.0,string)
textExample.pack()
filterbox=tk.Text(root, height=1)
filterbox.insert(1.0,"apple")
filterbox.pack()
btnRead=tk.Button(root, height=1, width=11, text="search",
command=searchcall)
btnRead.pack()
root.mainloop()

The problem is that tk inter appends a line break "\n" at the end when you read the contents of a widget.
Remove the "\n" at the end of the strings. For example, with strip
keyword=filterbox.get("1.0","end").strip()
you can also choose to read everything but the last character like this (source):
keyword=filterbox.get("1.0",'end-1c')

Related

Python text editor with "programatically" typing capabilities

I need a text editor which, as a feature, must have the capability of changing some of the information it shows on the screen, while open.
For example, I open the text file using that text editor mentioned above, and I can see on the screen:
|--------------------------------------------------------|
| My Text Editor (C:\myfile.txt) [Button] |
|--------------------------------------------------------|
|Name: John |
|Age: 32 |
|Gender: Male |
| |
| |
Then, for example, if I hit the button [Button], I want that the Age 32 change for, say, 30, while the text file is open.
But I want to do that without using keyboard and mouse automation...
Is that possible? Will Tkinter be enough for that task?
Here is a contrived example that both has a button to change the age, and also will update the time every second.
It does this with a context manager which preserves the insertion cursor and then inserts or deletes any text you want. This isn't particularly good coding style, but it shows what tkinter can do with its text widget.
import tkinter as tk
from datetime import datetime
from contextlib import contextmanager
#contextmanager
def preserve_insert_cursor(text):
"""Performs an action without changing the insertion cursor location"""
saved_insert = text.index("insert")
yield
text.mark_set("insert", saved_insert)
def change_age():
"""Change the age on line 3"""
with preserve_insert_cursor(text):
text.delete("3.5", "3.0 lineend")
text.insert("3.5", "30")
def update_time():
with preserve_insert_cursor(text):
# find all ranges of text tagged with "time" and replace
# them with the current time
now = datetime.now()
timestring = now.strftime("%H:%M:%S")
ranges = list(text.tag_ranges("time"))
while ranges:
start = ranges.pop(0)
end = ranges.pop(0)
text.delete(start, end)
text.insert(start, timestring, "time")
# call this function again in a second
text.after(1000, update_time)
root = tk.Tk()
header = tk.Frame(root, bd=1, relief="raised")
text = tk.Text(root)
header.pack(side="top", fill="x")
text.pack(fill="both", expand=True)
button = tk.Button(header, text="Button", command=change_age)
button.pack(side="right", padx=10)
# insert "Time:" with no tags, "<time>" with the tag "time",
# and then a newline with no tags
text.insert("end", "Time: ", "", "<time>", "time", "\n")
text.insert("end", "Name: John\n")
text.insert("end", "Age: 32\n")
text.insert("end", "Gender: Male\n")
update_time()
root.mainloop()
You can't tell from a static screenshot, but if you run the code you'll see that the time updates in real time even while you're typing.
I think, the best way to achieve this is to take a simple TextEditor example for PyQT and add a button to do what you want.
In a quick search I found for example this one:
https://www.learnpyqt.com/examples/no2pads-simple-notepad-clone/

Read one line at a time from tkinter textbox

I can read one line at a time, from an input box, and display it in a new box, but I need to advance to the next line of code.
Here are the text boxes in the GUI
self.sourcecode = Text(master, height=8, width=30)
self.sourcecode.grid(row=1, column=1, sticky=W)
self.nextline = Button(master, text="Next Line", fg="orange", command=lambda:[self.nextLine(self.intcount), self.lexicalResult()])
self.nextline.grid(row=12, column=1, sticky=E)
self.lexicalresult = Text(master, height=8, width=30)
self.lexicalresult.grid(row=1, column=3, sticky=W)
These are my functions to copy from one box, to the other (output would insert() into the lexicalResult() function)
def nextLine (self, intcount):
print("Reading from source")
self.linenumber.delete('1.0', END)
self.intcount = self.intcount + 1
self.linenumber.insert('0.0', self.intcount)
self.retrieve_input()
def retrieve_input(self):
lines = self.sourcecode.get('1.0', '2.0') #I need to take this and move to the next line but i am new to python and don't know what functions there are or their arguments
self.lexicalresult.insert('1.0', lines)
def lexicalResult (self):
print("Printing to result")
You can read a single line of text by using the "lineend" modifier on an index. For example, to get all of line 1 you could use something like this:
text.get("1.0", "1.0 lineend")
That will get everything on the line except the trailing newline. If you want the trailing newline, get just one character more:
text.get("1.0", "1.0 lineend+1c")
To delete an entire line you could use the very same indexes and pass them to the delete method.
As a more general purpose rule, given any index, to compute the beginning of the next line you can use something like this:
next_line = text.index("{} lineend+1c".format(index))
The index method converts an index into it's canonical form. The "lineend" modifier changes the index to the end of the line, and +1c moves it one character further.

How to store the input from the text box in python?

I want to make a program that show me the divisors of the number introduced in a text box using python tkinter GUI and store the results into a plain text file.
I don't how to get the value from the text box. I understood that is something linked with get() , I read something but I still don't get it.
Here is the code:
from tkinter import *
def create_file():
file_object = open("C:/Users/valis/Desktop/Divisors.txt","w+")
def evaluate():
show_after= Label(text= "Check your Desktop !")
show_after.pack(pady=2, anchor=SW)
create_file()
#Windows size and Title
window = Tk()
window.title("Show Divisors")
window.geometry("300x100")
message = Label(window, text="Enter a number : ")
message.pack(pady=2, anchor=NW)
textbox_input = Text(window,height=1, width=11)
textbox_input.pack(padx= 2,pady= 2, anchor=NW)
window.mainloop()
The code isn't complete, so what should I do ?
As you said, you will use the get() function but with some additional attributes.
If we have a text box textbox_input, then you can return its input using this line:
test_input = textbox_input.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). END is an imported constant which is set to the string "end". The END part means to read until the end of the text box is reached.
Reference: This answer.

search only whole words in tkinter text widget

I try to search for Python keywords (print, for, if, while....) in tkinter Tetx widget, but my code found both keywords and words, which contains keywords and i have to eliminate this words. Thanks for help.
My code:
import tkinter as Tk
def search(word):
try:
pos = t.search(word,"insert", stopindex="end")
col, line = pos.split(".")
except ValueError:
print("all")
else:
print(pos)
t.mark_set("insert","%i.%i"%(int(col),int(int(line)+len(word))))
search(word)
main=Tk.Tk()
t = Tk.Text(main)
t.pack()
t.insert("insert","word in tkinter")
t.mark_set("insert","1.0")
search("in")
main.mainloop()

Python Tkinter Help Menu

I have a paragraph of help information that I would like to display in a window with an "ok" button at the bottom. My issue is formatting...I want to be able to simply set the paragraph equal to a variable and then send that variable to a message box widget. By default, it formats laterally and in a very ugly manner. Any advice?
def aboutF():
win = Toplevel()
win.title("About")
about = "Top/bottom 3 - Reports only the top/bottom 3 rows for a param you will later specify.\
Set noise threshold - Filters results with deltas below the specified noise threshold in ps.\
Sort output - Sorts by test,pre,post,unit,delta,abs(delta).\
Top 2 IDD2P/IDD6 registers - Reports only the top 2 IDD2P/IDD6 registers.\
Only critical registers - Reports only critical registers.\
Use tilda output format - Converts the output file from csv to tilda.\
Use html output format - Converts the output file from csv to html."
Label(win, text=about, width=100, height=10).pack()
Button(win, text='OK', command=win.destroy).pack()
Use a text widget with word wrapping, and either define your string more accurately or do a little post-processing to remove all that extra whitespace. Using the code from this answer makes it easy to use multiple colors, fonts, etc.
For example:
import Tkinter as tk
import re
class CustomText(tk.Text):
'''A text widget with a new method, HighlightPattern
example:
text = CustomText()
text.tag_configure("red",foreground="#ff0000")
text.HighlightPattern("this should be red", "red")
The HighlightPattern method is a simplified python
version of the tcl code at http://wiki.tcl.tk/3246
'''
def __init__(self, *args, **kwargs):
tk.Text.__init__(self, *args, **kwargs)
def HighlightPattern(self, pattern, tag, start="1.0", end="end", regexp=True):
'''Apply the given tag to all text that matches the given pattern'''
start = self.index(start)
end = self.index(end)
self.mark_set("matchStart",start)
self.mark_set("matchEnd",end)
self.mark_set("searchLimit", end)
count = tk.IntVar()
while True:
index = self.search(pattern, "matchEnd","searchLimit",count=count, regexp=regexp)
if index == "": break
self.mark_set("matchStart", index)
self.mark_set("matchEnd", "%s+%sc" % (index,count.get()))
self.tag_add(tag, "matchStart","matchEnd")
def aboutF():
win = tk.Toplevel()
win.title("About")
about = '''Top/bottom 3 - Reports only the top/bottom 3 rows for a param you will later specify.
Set noise threshold - Filters results with deltas below the specified noise threshold in ps.
Sort output - Sorts by test,pre,post,unit,delta,abs(delta).
Top 2 IDD2P/IDD6 registers - Reports only the top 2 IDD2P/IDD6 registers.
Only critical registers - Reports only critical registers.
Use tilda output format - Converts the output file from csv to tilda.
Use html output format - Converts the output file from csv to html.'''
about = re.sub("\n\s*", "\n", about) # remove leading whitespace from each line
t=CustomText(win, wrap="word", width=100, height=10, borderwidth=0)
t.tag_configure("blue", foreground="blue")
t.pack(sid="top",fill="both",expand=True)
t.insert("1.0", about)
t.HighlightPattern("^.*? - ", "blue")
tk.Button(win, text='OK', command=win.destroy).pack()
root=tk.Tk()
aboutF()
root.mainloop()

Categories