Python text editor with "programatically" typing capabilities - python

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/

Related

Moving text from a button to another using python tkinter

def move(sp, t):
if sp == "eightA":
sps = eightA
if t == "sixA":
st = sixA
if st == " ":
# target is empty
sps["text"] = " "
st["text"] = str(sps["text"])
Hello Everyone, Im trying to make this function to "move" text from a tkinter button to another, lets say sp is what i want to move, and t is the target so i want to move text
from the button eightA to sixA, also note that i want to be able to use this function on any 2 buttons, Its hard to explain, but please help if you can, the code above is one i tried out of alot other which didnt work,
Thanks
Procedure
Store the text on first button in a variable
Configure first button to have no text
Configure second button to have text stored in variable
Example
btn1 = tk.Button(text="Hello")
btn2 = tk.Button(text="Not Hello")
# store text on btn1 in a variable
txt = btn1['text']
# configure btn1 to have no text
btn1.config(text="")
# configure btn2 to have text stored in variable
btn2.config(text=txt)
So your function would look like
def move(btn1, btn2):
txt = btn1['text']
btn1.config(text=" ")
btn2.config(text=txt)

How to update variables from a text file in a GUI in real time? Python and tkinter

I have a script that continuously updates numbers on a text file in the same directory. I made a GUI using tkinter to display these numbers. I'm having a hard time getting the GUI to update the numbers in real time. It will display the numbers as they were when the GUI first started, but will not update the display as the text file changes. Here's some basic code to demonstrate:
def read_files(file, line):
old = open(f'{file}.txt', 'r').readlines()[line]
new = old.replace('\n', '')
return new
number = read_files('Statistics', 0)
number_label = Label(frame1, text=f'{number}')
number_label.grid(row=0, column=0)
The above code shows the number from the text file as it was when the GUI first opened. However, it does not update the number as its value in the text file changes. I did some reading around and also tried the following:
def read_files(file, line):
old = open(f'{file}.txt', 'r').readlines()[line]
new = old.replace('\n', '')
return new
number = read_files('Statistics', 0)
number_label = StringVar()
number_label.set(number)
number_display = Label(frame1, text=f'{number_label.get()}')
number_display.grid(row=0, column=0)
This has the same effect. It shows the value retrieved from the text file at the moment the GUI was opened, but does not update it as the text file is updated. Any help is appreciated.
Since there is no complete code, take a look at this example:
from tkinter import *
root = Tk()
def update_gui():
number = read_files('Statistics', 0) # Call the function
number_display.config(text=number) # Change the text of the label, also same as text=f'{number}'
root.after(1000,update_gui) # Repeat this function every 1 second
def read_files(file, line):
old = open(f'{file}.txt', 'r').readlines()[line]
new = old.replace('\n', '')
return new
number_display = Label(root) # Empty label to update text later
number_display.grid(row=0, column=0)
update_gui() # Initial call to the function
root.mainloop()
Here the label is created outside the function but the text is not given, but inside the function we are repeating the function every 1 second, with after, and changing the text of the label with config method. I have avoided the use of StringVar() as it's of no use here, you can just store it in a normal variable and use it.
Here is a plagiarized look at how after should be used:
def after(self, ms, func=None, *args):
"""Call function once after given time.
MS specifies the time in milliseconds. FUNC gives the
function which shall be called. Additional parameters
are given as parameters to the function call. Return
identifier to cancel scheduling with after_cancel."""

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.

Change the color of a single word in a tk option menu?

So I'm grabbing links of events off a website and putting them into a drop down menu to be selected. My code for the menu:
import Tkinter as tk
from Tkinter import StringVar
selectMenu = tk.Tk()
# #-> this is what I have
# Followed by what you can use
#var = Vars()
#events = var.GetVars('Event')
events = " "
options = []
links = []
#forms = (driver.find_elements_by_class_name("with-cats")) #This is what I have
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself
for x in forms:
#info = x.text
info = x #Again, this is so you can try it for yourself
if events in info.lower():
links.append(x)
for link in range(0,len(links)):
#options.append(links[link].text)
options.append(links[link])
list(set(options))
selection = []
for link in range(0,len(options)):
selection.append(options[link])
select = StringVar(selectMenu)
select.set("--None Selected--")
menu = tk.OptionMenu(selectMenu, select, *(selection))
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menu.pack(side="top", pady=10)
selectMenu.attributes('-topmost', True)
selectMenu.mainloop()
So this works fine and dandy, but I would like to improve the look to make it more obvious which events are open. To clarify, an event found that is open and put into the menu may look like "This is a cool event", but one that is closed would be read as "This is a cool event Closed". My aim is to be able to make the foreground red of either just the word Closed or the string containing Closed, whichever is possible if any (And I'm not sure if it's possible because menus and buttons on osx are usually defaulted to system settings, maybe there is a way around this?).
Current: Desired:
According to the documentation for OptionMenu here and here I don't think there is a way to set the color of text.
You might be able to get something close to what you want by using a listBox instead. See post here for the listBox example.
Found a solution! Using a Menu inside of a MenuButton the same way Tkinter creates MenuOptions, I was able to create a custom MenuOption. If you want to add more options, you can use the menbutton.configure() option to edit the button, and menbutton.menu to edit the menu items.
import Tkinter as tk
from Tkinter import Menu, Menubutton
class Vars():
global vari
vari = {}
def GetVars(self, var):
return vari.get(str(var))
def SendVars(self, var, val):
vari[str(var)] = val
class App():
def buttselect(self, link, menbutton, selectMenu):
var = Vars()
var.SendVars("Selection", link) # Store selected event
menbutton.configure(text=link) # Set menu text to the selected event
def prnt(self, link):
var = Vars()
print var.GetVars("Selection") # Print event
def __init__(self, selectMenu):
events = " "
options = []
links = []
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself
menbutton = Menubutton (selectMenu, text="--None Selected--", relief="raised")
menbutton.grid()
menbutton.menu = Menu (menbutton, tearoff=0)
menbutton["menu"] = menbutton.menu
#Get a list of event names
for x in forms:
info = x #Again, this is so you can try it for yourself
#If desired event keyword is in an event name, add it to the correct links
if events in info.lower():
links.append(x)
#Remove duplicates
for link in range(0,len(links)):
options.append(links[link])
list(set(options))
#Final list of event names turned into menu commands
for link in options:
if "Closed" in link:
menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu), foreground='red')
else:
menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu))
b = tk.Button(selectMenu, text="Selection", command= lambda link=link: self.prnt(link)) #Print selected event
b.pack()
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menbutton.pack(side="top", pady=10)
selectMenu = tk.Tk()
selectMenu.attributes('-topmost', True)
app = App(selectMenu)
selectMenu.mainloop()
This results in exactly the result desired:
I found a way!
Let's say x is an optionmenu with options:
options=['Red','Blue','Green']
defopt=tk.StringVar(options[0]) #StringVariable to hold the selected option.
x=tk.OptionMenu(self.optmenuframe,defopt,*options)
Now, get the menu object from the optionmenu and use entryconfig method. That's it!
x.children['menu'].entryconfig(0,foreground='red')
x.children['menu'].entryconfig(1,foreground='blue')
x.children['menu'].entryconfig(2,foreground='green')
#0 is the index of the option you want to apply the configurations to.

Remove tkinter text default binding

I'm making a simple tkinter Text editor, but i want all default bindings of the Text widget removed if possible.
For example when i press Ctrl + i it inserts a Tab character by default.
I made an event binding that prints how many lines are in the text box, I set the event binding to Ctrl + i as well.
When i run it, It prints the number of lines inside the text box, but also inserts a tab character.
I want to know how i can Overwrite the default bindings, or learna way how to remove all the default bindings.
Heres my code btw:
from tkinter import *
class comd: # Contains primary commands
# Capital Rule ----------------------------
# G = Get | I = Insert | D = Draw | S = Set
# -----------------------------------------
def Ggeo(self): # Get Geometry (Get window geometry)
x = root.winfo_width()
y = root.winfo_height()
print("Current Window Geometry")
print(str(x) + " x " +str(y))
def Idum(self): # Insters "Dummy Insert"
import tkinter as tkin
tbox.insert(INSERT, "Dummy Insert")
def Ilim(self): # Prints How many lines are in
info = int(tbox.index('end-1c').split('.')[0])
print(info)
root = Tk()
root.geometry("885x600-25-25")
tbox = Text(root, font=("Courier","14","bold"))
tbox.pack(expand = True , fill = BOTH)
# Problem here --------------------
tbox.bind("<Control-i>", comd.Ilim)
# ---------------------------------
mainloop()
You can overwrite a binding by having your function return the string "break". For example:
def Ilim(self): # Prints How many lines are in
info = int(tbox.index('end-1c').split('.')[0])
print(info)
return "break"
If you want to completely remove all bindings (including the bindings that allow you to insert characters), that can be easily accomplished. All of the bindings are associated with a "bind tag" (or "bindtag"). If you remove the bindtag, you remove the bindings.
For example, this removes all of the default bindings:
bindtags = list(tbox.bindtags())
bindtags.remove("Text")
tbox.bindtags(tuple(bindtags))
For more information on bind tags, see this answer: https://stackoverflow.com/a/11542200/7432

Categories