I wanna make a dictionary program that could be run every platform. I coded it and it works basically, the user selects a word with a double click before clicking 'Q' and it gives selected word definition. Then I need a GUI. I made it but I couldn't connect them.
dict.txt's example : https://i.stack.imgur.com/Z9WMJ.png
Sceptral (a.) Of or pertaining to a scepter; like a scepter.
Scern (v.t.) To discern; to perceive.
Schade (n.) Shade; shadow.
Schah (n.) SeeShah.
Schediasm (n.) Cursory writing on a loose sheet.
main code;
import pyautogui as pya
import pyperclip
import time
import keyboard
import re
import sys
liste = list()
def copy_clipboard():
time.sleep(5)
pya.hotkey('ctrl', 'c')
time.sleep(.01)
return pyperclip.paste()
def click(key, *args,**kwargs): #
oldword = pyperclip.paste()
time.sleep(.01)
pya.hotkey('ctrl','c')
newword = pyperclip.paste()
time.sleep(.01)
pyperclip.copy(oldword)
capitalizing = newword.capitalize()
delete_space = capitalizing.strip()
word = delete_space
print(word)
file = open('dict.txt', 'r')
for line in file:
if word == line.split(" ")[0]:
letters = re.sub(word, " ", line)
liste.append(letters)
print(liste)
file.close()
while True:
try:
if keyboard.on_press_key('q',click):
print('You Pressed a Key!')
sleep(.01)
break
else:
pass
except:
break
gui;
import tkinter as tk
window = tk.Tk()
window.geometry("300x400+1200+200")
window.title("dict")
#window.wm_attributes("-alpha")
button = tk.Button(text = "Yuppi")
button.pack()
sbr = tk.Scrollbar(window)
sbr.pack(side=tk.RIGHT,fill="y")
text1 = tk.Text(window)
text1.insert(tk.INSERT, liste)#letters or liste has to be here
text1.pack()
window.mainloop()
Unfortunately connecting a GUI to a backend program requires a overhaul of the backend code. When you make a Tkinter GUI, a lot of the controls that you would usually use in backend, such as "print (…)" becomes more complicatd with tk.Label(window, text=…).place(x=x,y=y). So you will essentially have to incorporate your GUI into your backend code.
Related
I'm not a programmer so admittingly my title might be a bit off.
I have a program where I select an IFC-file (used in the construction industry, which contains data about the geometry and data connected to the objects in the 3D drawing) and then a dialog opens where I can add a GUID (an identifier) and search for all the information related to that object in the IFC-file, which I then print in the command prompt.
A minor issue which annoys me a bit is that the when is select the file in a more flexible way, using askopenfilename, the function seems to stay active or in a loop after I close the later opening dialog, so that I have to end the process using CTRL+C.
I post the entire code as I don't know if there is something else which causes it:
#imports to search for files
import os
# imports tkinter for selection purposes, so that one can select the files instead of reading in them automaticall from a directory
import tkinter as tk
from tkinter.filedialog import askopenfilename
#importing the counter to counte the occurences in a list
from collections import Counter
#importing regex functionality to check values
import re
#this is the numbering, for example #433, #4781 etc, that we either want to look for or change - now it looks for up to a number of length 7
regexIFCnumbers = '#\d{1,7}'
tk.Tk().withdraw() # we don't want a full GUI, so keep the root window from appearing
file1 = askopenfilename(initialdir=os.getcwd()) # show an "Open" dialog box and return the path to the selected file - this in the current directory where we'll start looking
file1Name = (os.path.basename(file1)) #only the file's name
#read files
def readFile(file):
x = []
f = open(file, 'r')
x = f.readlines()
f.close()
return(x)
x1 = readFile(file1)
#checks the GUIDs
def checkGUID(GUID, IFC):
A = []
for row in IFC:
if GUID in row:
#print(re.findall(regexIFCnumbers, row))
A.extend(re.findall(regexIFCnumbers, row))
return(A)
#the numbering is not perfectly ordered and varies in some places, so need to index it all to find the correct lines
def indexIFC(IFC):
A = []
for index, row in enumerate(IFC):
if re.findall('^#', row): #starts with a hash #
B = re.findall(r'\#\w+', row)[0]
A.append([B, index])
return(A)
def recurseThrough(inputList, IFC, checkedList, fullList, indexednumbersList):
for item in inputList:
for hashvalueList in indexednumbersList:
if item == hashvalueList[0]:
positionInIFC = hashvalueList[1]
if re.search('^'+item, IFC[positionInIFC]) and item not in checkedList: #if the row begins with the number item in the list
checkedList.append(item)
fullList.append(IFC[positionInIFC])
recurseThrough(re.findall(regexIFCnumbers, IFC[positionInIFC])[1:], IFC, checkedList, fullList, indexednumbersList) #recurses through the next list
return(fullList)
from os import system, name
def clear():
if name == 'nt':
_ = system('cls')
def runTheGUIDCheck(setValue):
inputValue = str(setValue)
print(inputValue)
clear()
try:
B1 = checkGUID(inputValue, x1) #This returns a list with for example [#122, #5, #7889]
checkedList = [] #the list of already checked items
fullList = []
indexedIFClist1 = indexIFC(x1)
#run the function with the initial input, sending in empty array as well as they should be empty/none at the start
outList1 = recurseThrough(B1, x1, [], [], indexedIFClist1)
for index, item in enumerate(outList1):
print(index, item.strip())
return None
except:
print("inserted GUID not found or didn't work")
#dialog
dialog = tk.Tk()
dialog.geometry('500x200')
t1 = tk.Label(dialog, text = 'Check GUID')
t1.grid(row = 0, column = 0, sticky = 'w')
testGUIDAttributes = tk.Entry(dialog, width = 40)
testGUIDAttributes.grid(row = 0, column = 1, columnspan = 50)
button = tk.Button(dialog, text='Run GUID', command = lambda: runTheGUIDCheck(testGUIDAttributes.get()))
button.grid(row = 5, column = 0, sticky = 'w')
dialog.mainloop()
If I select the file directly like this...
file1 = 'thefile.ifc'
instead of with the above this...
tk.Tk().withdraw() # we don't want a full GUI, so keep the root window from appearing
file1 = askopenfilename(initialdir=os.getcwd()) # show an "Open" dialog box and return the path to the selected file - this in the current directory where we'll start looking
then this issue doesn't come up and the command prompt will accept new commands after I close the dialog which is "created" at the end.
Since you have created two instances of Tk(): one in the line tk.Tk().withdraw() and one in the line dialog = tk.Tk(), so the line dialog.mainloop() will not return until both windows are closed. However you cannot close the withdrawn window because it is invisible.
You should create only one instance of Tk(), hide it and then show the file dialog. Then show it back and proceed as normal:
...
# create the main window and hide it initially
dialog = tk.Tk()
dialog.withdraw()
file1 = askopenfilename(initialdir=os.getcwd()) # show an "Open" dialog box and return the path to the selected file - this in the current directory where we'll start looking
...
# show back the main window
dialog.deiconify()
dialog.geometry('500x200')
...
dialog.mainloop()
I'm writing a script and I'd like to use Tkinter GUI (or any other module which could do this) to show how many times in total this script has been run, store the number in file and update GUI dynamically from this file. But each time I call label.mainloop() nothing past this line gets executed, it just freezes there.
import tkinter
import time
def tracker():
f = open('howmanytimes.txt', 'r')
thenumber = f.read()
f.close()
tracker = 'Script has run this many times: ' + (str(thenumber))
label = tkinter.Label(text=tracker, font=(
'Times', '20'), fg='red', bg='black')
label.master.overrideredirect(True)
label.master.geometry("+0+0")
label.pack()
label.master.wm_attributes("-topmost", True)
label.mainloop()
tracker() # <- Nothing past this line gets executed
time.sleep(2)
i = 0
while i < 20:
print('Script has been run')
time.sleep(3)
f = open('howmanytimes.txt', 'w+')
thenumber = f.read()
g = int(thenumber) + 1
f.write(str(g))
f.close()
tracker()
i+=1
Here's a way to implement what you want. I put all the tkinter related code into a class to better encapsulate what it does and allow it to be put into a separate thread. It uses the universal widget method after() to periodically "poll" the file for changes without interfering with tkinter's mainloop() — which is a very common way to do that sort of thing.
I also had to change your file handling quite a bit to get it working and handle all the possible cases of it not existing yet or being empty — as well as deleting it at the end so its existence can't affect a subsequent run of the same program.
import os
from threading import Lock, Thread
import tkinter as tk
import time
class Tracker:
def __init__(self):
self.root = tk.Tk()
self.root.overrideredirect(True)
self.root.geometry("+0+0")
self.root.wm_attributes("-topmost", True)
# Create empty label widget to be updated.
self.label = tk.Label(self.root, font=('Times', '20'), fg='red', bg='black')
self.label.pack()
self.update() # Start polling file.
self.root.mainloop()
def update(self):
try:
with open(FILE_PATH, 'r') as f:
thenumber = next(f)
except (FileNotFoundError, StopIteration):
thenumber = '0'
self.label.config(text=f'Script has run this many times: {thenumber}')
with running_lock:
if running:
self.label.after(1000, self.update)
else:
self.root.quit() # Stop mainloop.
FILE_PATH = 'howmanytimes.txt'
running_lock = Lock()
running = True
bkg_thread = Thread(target=Tracker)
bkg_thread.start()
for i in range(5):
try: # Create or update file.
with open(FILE_PATH, 'r+') as f:
thenumber = f.read()
try:
g = int(thenumber) + 1
except ValueError: # Empty file.
g = 1
f.seek(0) # Rewind.
f.write(str(g))
except FileNotFoundError:
with open(FILE_PATH, 'w') as f:
g = 1
f.write(str(g))
print('Script has been run')
time.sleep(3)
with running_lock:
running = False # Tell background thread to stop.
try:
os.remove(FILE_PATH) # Clean-up.
except Exception:
pass
Bit of a beginner here :)
So for the past couple of days I've been working on a relatively simple web scraper, but with a special goal in mind. Namely, I wanted to get better with tkinter.
So, I've made a devlog window, which is simply going to be a separate console kind of thing. But the problem is that I want to insert text "live" in to the devlog window, and the text comes from a different script in a different thread. How could I implement this feature? This devlog window is ALSO run in a thread, as well as 3 other scripts along side it. This is the code I have so far:
import Manager as AM
import tkinter as tk
from time import sleep # For some simple timing algorithms
Width = 700
Height = 500
FrameGeometry = str(Width) + "x" + str(Height)
# COLORS
LightGrey = "#D9D9D9"
DarkGrey = "#AAAAAA"
# Global variables.
ThreadsList = list()
def CreateDevLogWindow():
global Width
global Height
ThreadTemp_ = str(AM.FileManager(ReadData=2))
devlog = tk.Tk() # Secondary Devlog Interface.
FrameInfo = tk.Frame(master=devlog)
FrameText = tk.Frame(master=devlog)
ThreadText = tk.Label(master=FrameInfo, text="Total Threads: " + ThreadTemp_, bg="white")
ThreadTextActive = tk.Label(master=FrameInfo, text="Active Threads: " + ThreadTemp_, bg="white")
InfoText = tk.Text(FrameText, border=1, highlightthickness=1)
devlog.title("Devlog: YourOptimalScrapper")
devlog.geometry(str(Width) + "x" + str(Height))
devlog.config(bg="white")
FrameInfo.config(bg="white")
FrameText.config(bg="white", padx=5, pady=5)
FrameInfo.pack(side=tk.TOP, fill=tk.BOTH)
FrameText.pack(side=tk.BOTTOM, expand=True, fill=tk.BOTH)
ThreadText.grid(row=0)
ThreadTextActive.grid(row=1)
InfoText.pack(expand=True, fill=tk.BOTH)
while True:
if ThreadTemp_ != AM.FileManager(ReadData=2):
ThreadTemp_ = str(AM.FileManager(ReadData=2))
ThreadText.config(text="Total Threads: " + ThreadTemp_)
ThreadTextActive.config(text="Active Threads: " + ThreadTemp_)
devlog.update()
Any and all help is appreciated, and NOTE: There is more code under this, but I don't think its particularly necessary :)
First of all you can insert text in your TextBox with just a few lines.
def update_textbox(textbox, data):
textbox.config(state=tk.NORMAL) # unlock the textbox
textbox.insert(tk.END, "\n"+str(data)) # add newline and append the data
textbox.config(state=tk.DISABLED) # lock back the textbox to readonly
textbox.see(tk.END) # scroll to the bottom to see the last line
With that if your script is in a different thread, then you can create a file that will be the "carrier" of your data.
Whenever you need to write data to the textbox, simply write data to the file with your text in any thread and update the while loop in the above code to read this file and update the textbox if the file isn't empty.
EDIT: You don't need to call this function outside of this thread. Just check in your while loop whether new data has to be added to the log
...
while True:
with open("carrier.txt", 'r') as f:
content = f.read() # read carrier data
if content: # if file isn't empty
update_textbox(InfoText, content) # update the textbox with the data in the file
open("carrier.txt", 'w').close() # clear the file to prevent reading the data twice
if ThreadTemp_ != AM.FileManager(ReadData=2):
ThreadTemp_ = str(AM.FileManager(ReadData=2))
ThreadText.config(text="Total Threads: " + ThreadTemp_)
ThreadTextActive.config(text="Active Threads: " + ThreadTemp_)
devlog.update()
And in your other thread
def update_log(data):
with open("carrier.txt", 'a') as f: # append to the file
f.write(str(data))
Quite a beginner here. I have a command line script that works fine for what I do and I'm looking to move it into a GUI.
os.chdir(ImageDirST)
for f in sorted(os.listdir(ImageDirST)):
f_name,f_ext = (os.path.splitext(f))
f_sku = (f_name.split(' ')[0])
f_num = (f_name[-2:])
n_name = ('{}_{}{}'.format(f_sku,f_num,f_ext))
print(f, "-->", n_name)
I would like this to display in the same fashion within a message window in tkinter.
With some help from here, I managed to print the filenames in the directory when a button is pushed with:
filenames = sorted(os.listdir(ImageDirBT))
text = "\n".join(filenames)
print_filename_test.set(text)
I have tried to use my split code to setup a list of what the new filenames would look like, prior to setting the variable, with the following, where print_filenames() is the function triggered by the press of a button.
def print_filenames():
filenames = sorted(os.listdir(ImageDirBT))
for filenames in sorted(os.listdir(ImageDirBT)):
f_name,f_ext = (os.path.splitext(filenames))
f_sku = (f_name.split('_')[0])
f_num = (f_name[-2:])
n_name = ('{}_{}{}'.format(f_sku,f_num,f_ext))
newlist = "\n".join(n_name)
print_filename_test.set(newlist)
I don't get any errors with this code for print_filenames(), however what is displayed in the message panel is the last filename in the list, vertically, one character wide:
eg:
F
I
L
E
_
1
1
.
e
x
t
I would like to display the output as:
oldfilename_01.ext --> newfilename_csvdata_01.ext
oldfilename_02.ext --> newfilename_csvdata_02.ext
oldfilename_03.ext --> newfilename_csvdata_03.ext
oldfilename_04.ext --> newfilename_csvdata_04.ext
The command line program I have written uses numbers to chose menu options for what needs to be done, confirming before any renaming is done, hence printing the file name comparisons. My struggle is manipulating the strings in the list to be able to do the same thing.
Using messagebox:
import os
import tkinter as tk
from tkinter import messagebox
ImageDirST = r"your_path"
os.chdir(ImageDirST)
root = tk.Tk()
names = []
for f in sorted(os.listdir(ImageDirST)):
f_name,f_ext = (os.path.splitext(f))
f_sku = (f_name.split(' ')[0])
f_num = (f_name[-2:])
n_name = ('{}_{}{}'.format(f_sku,f_num,f_ext))
names.append(f"{f} --> {n_name}\n")
messagebox.showinfo(title="Something", message="".join(names))
root.mainloop()
Or using Text widget with scrollbar:
import os
import tkinter as tk
from tkinter.scrolledtext import ScrolledText
ImageDirST = r"your_path"
os.chdir(ImageDirST)
root = tk.Tk()
txt = ScrolledText(root, font="Arial 8")
txt.pack()
for f in sorted(os.listdir(ImageDirST)):
f_name,f_ext = (os.path.splitext(f))
f_sku = (f_name.split(' ')[0])
f_num = (f_name[-2:])
n_name = ('{}_{}{}'.format(f_sku,f_num,f_ext))
txt.insert("end",f"{f} --> {n_name}\n")
root.mainloop()
I've been playing around with this quite a bit and I feel like I'm making a mess of it.
I need an interface where if someone enters a word in the text field, it'll print any lines within a .txt file containing that word in the box next to it.
Here's what I have so far:
import Tkinter as tk
from Tkinter import *
from scipy import *
import math
def cbc(id, tex):
return lambda : callback(id, tex)
def callback(id, tex):
t = Search(id)
tex.insert(tk.END, t)
tex.see(tk.END)
#def retrieve_input():
# input = self.entn.get("0.0",END)
def Search(id):
with open("file.txt", "r") as s:
searchlines = s.readlines()
for i, line in enumerate(searchlines):
if entn.get() in line:
for line in searchlines[i:i+1]: print line,
print
top = tk.Tk()
tex = tk.Text(master=top)
tex.pack(side=tk.RIGHT)
bop = tk.Frame()
bop.pack(side=tk.LEFT)
entn = tk.Entry()
entn.pack(side=tk.TOP, fill=Y)
tb = "Search"
b = tk.Button(bop, text=tb, command=cbc(id, tex))
b.pack()
tk.Button(bop, text='Exit', command=top.destroy).pack()
top.mainloop()
I'm pretty new to this, as you can probably tell - so any help will be really appreciated.
Your callback is inserting the result of Search(id) but that function isn't returning anything. You need to add a return statement in that function to return the strings you want to show in the text widget.
A better way might be to pass in a reference to tne text widget to Search so that you can directly insert each match as you find them.