How to reload part of the code in tkinter many times? - python

In the code below, a part of the main code is placed. I want this file, which is updated at different times, to be updated in tekinter, but the problem is that my UI is not updated until it is closed and opened.
style = ttk.Style(GLabel_820)
style.theme_use('clam')
style.configure("mystyle.Treeview", highlightthickness=0,bd=0,font=('Far_Nazanin', 11))
style.configure("mystyle.Treeview.Heading", font=('Far_Nazanin', 15))
style.layout("mystyle.Treeview", [('mystyle.Treeview.treearea', {'sticky': 'nswe'})])
tree = ttk.Treeview(GLabel_820)
tedadtardod=0
filename = 'output/pelak1.xlsx'
filename = r"{}".format(filename)
df = pd.read_excel(filename,engine='openpyxl')
tedadkhat=len(df)
tree["column"] = list(df.columns)
tree["show"] = "headings"
for col in tree["column"]:
tree.heading(col, text=col)
df_rows = df.to_numpy().tolist()
for row in df_rows:
tedadtardod=tedadtardod+1
if tedadtardod>tedadkhat-10:
tree.insert("",0,values=row)

Have you tried placing that part of the code in a loop.
You can use a while loop or a for loop.

Well, with my research I managed to solve my problem, so I'm posting the result here for others to use
def reload(self):
while True :
try :
gf = pd.read_excel('output/pelak1.xlsx',engine='openpyxl')
break
except EOFError as e:
time.sleep(1)
NewPelakLength=len(gf)
global LastPelakLength
global toc
tic = time.perf_counter()
elap=tic-toc
if NewPelakLength != LastPelakLength:# or elap>10
toc = time.perf_counter()
LastPelakLength=len(gf)
self.pelak_list()
self.after(6000, self.reload)

Related

Tkinter GUI to be able to change variables of an separate continuous process

I have designed an marine engine simulator - it's a program that sends some serial DATA using a certain protocol called "BlueVision". The data is encoded based on a header, a block number, a block type, actual data (indexed), a checksum and a footer. Due to the fact that if you want to change a value in the actual data - then the checksum changes - I designed an recalculation of the block with the correct checksum when the data is changed. I made a GUI that allows me to change the value of 2 data points in order to be able to test live. The problem is that I don't know how to use threads or subprocesses correctly and the window keeps on freezing. The application works - but works badly and I kept on searching for a similar issue - and did find some suggestions but I haven't been able to implement it. Can someone help? PS: the code is awkward at best - please don't judge - I know I could of made it way better - but this is the best I could do with the time I had. The issue might not be clear to you if you don't have a COM port where the program writes to.
# Blue Vision is a MTU serial communication protocol - based on HEX values grouped in BLOCKS
import tkinter as tk
from tkinter import ttk
import time
import serial
def split_by_n(seq, n):
while seq:
yield seq[:n]
seq= seq[n:]
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."""
win = tk.Tk()
win.title("GUI - TEST VERSION")
win.geometry("750x250")
label = tk.Label(win, text = "Main Engine Overspeed")
label.pack()
v = tk.StringVar()
v.set('00')
c = tk.StringVar()
c.set("00")
def setText(word):
v.set(word)
a = ttk.Button(win, text ="01", command =lambda:setText("01"))
a.pack()
b = ttk.Button(win, text="00", command = lambda:setText("00"))
b.pack()
label1 = tk.Label(win, text ="Main Engine Speed")
label1.pack()
name_entry = tk.Entry(win, textvariable=c)
name_entry.pack()
def task():
MyVar = v.get()
priEngSp =c.get()
if len(priEngSp) == 0:
priEngSp = '00'
block_3 = 'FAF500030002000000290100000001000100000001000001000000000000000000000000000222AF5F'
block_4 = 'FAF500040003000001A000004650000047E00000000000000000000000000007EF4000083D6000000000000000000000000000000000000000000000012C000006D600000000000000000000278D00000000000000007FFFFFFF000000000001991500000000000000000016E36000000000000923D8000971F8000001F40000059F000026AC00002774000005800000251C00000580000027740000283C0000056200001D4C00001F400000061800000000000060FB00004650000036B000007D0000008CA0000006180000251C0000000000000000000000000000284800192D500017A6B00000051B0000251CFFFFFFA8000002580000044C000000FA0000000000000000000006770000CB200000D6D8000006770000CB200000D6D80000060600005DC000000000000027100000000000000000000000000000000000000000000003C2000061A8000000000000000000000000000000000000000000000000000000000000000000000000000000000000363300000EA6000249F0FFFFFB1E000F42400000000000000000000000000000000000000000000032D9AF5F'
block_5 = 'FAF5000500020000005600000000000000000000000000000000000000000000007F7F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034AAF5F'
block_6 = 'FAF5000600020000003D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000234AF5F'
block_7 = 'FAF5000700030000008C000006280000064A0000064A0000068D0000066B0000068D0000068D000006AE0000000000000000000006AE000006070000060700000607000005E5000005A2000006070000064A00000000000000000000062A000006AE000005A20000350EFFFFF07C00003CDEFFFFE8AC00000000000000000000000000000000000012DEAF5F'
block_8 = 'FAF50008000300000070000000000000112900000000000000000000059C000027740000283C000047E000000000000000000000000000000000000000000000000000000000000000007FFFFFFF7FFFFFFF0000055100002CEC0000000000000000000000000000000000000DD1AF5F'
block_9 = 'FAF50009000200000020000000000000000000000000000000000000021AAF5F'
block_10 = 'FAF5000A0002000000260000000000000000000000000000000000000000000000000221AF5F'
block_11 = 'FAF5000B0003000000EC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E9AF5F'
block_12 = 'FAF5000C000200000045000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000242AF5F'
block_2 = 'FAF50002000200000074010001000000000000000000000000000000000000000000007F0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E9AF5F'
checksum = hex(0x00)
block_2split = list(split_by_n(block_2,2))
block_2split[10] = MyVar.upper() #Overspeed Alarm Position
for i in range(len(block_2split)-6):
checksum = hex(int(checksum, 16) + int(block_2split[i], 16))
checksum_string = str(checksum)
checksum_actvalue = checksum_string[2:]
checksum_long = checksum_actvalue.rjust(8,'0').upper()
checksum_split = list(split_by_n(checksum_long,2))
block_2split[len(block_2split)-3] = checksum_split[3]
block_2split[len(block_2split)-4] = checksum_split[2]
block_2split[len(block_2split)-5] = checksum_split[1]
block_2split[len(block_2split)-6] = checksum_split[0]
Block_2Output = ''.join(str(item) for item in block_2split)
iEngineSpeed = int(priEngSp,10)
hEngineSpeed = hex(iEngineSpeed * 10)
sEngineSpeed = str(hEngineSpeed)[2:].upper()
while (len(sEngineSpeed)<8):
sEngineSpeed = '0' + sEngineSpeed
block_4split = list(split_by_n(block_4,4))
sEngineSpeed_split = list(split_by_n(sEngineSpeed,4))
block_4split[5] = sEngineSpeed_split[0]
block_4split[6] = sEngineSpeed_split[1]
Block_4joint = ''.join(str(item) for item in block_4split)
Block_4joint_sp = list(split_by_n(Block_4joint,2))
checksumb4 = hex(0x00)
for i in range(len(Block_4joint_sp)-6):
checksumb4 = hex(int(checksumb4, 16) + int(Block_4joint_sp[i], 16))
checksumb4_string = str(checksumb4)
checksumb4_actvalue = checksumb4_string[2:]
checksumb4_long = checksumb4_actvalue.rjust(8,'0').upper()
checksumb4_split = list(split_by_n(checksumb4_long,2))
Block_4joint_sp[len(Block_4joint_sp)-3] = checksumb4_split[3]
Block_4joint_sp[len(Block_4joint_sp)-4] = checksumb4_split[2]
Block_4joint_sp[len(Block_4joint_sp)-5] = checksumb4_split[1]
Block_4joint_sp[len(Block_4joint_sp)-6] = checksumb4_split[0]
Block_4Output = ''.join(str(item) for item in Block_4joint_sp)
blocks = [Block_2Output, block_3, Block_4Output, block_5, block_6, block_7, block_8, block_9, block_10, block_11, block_12]
with serial.Serial('COM5', '9600') as ser: #you might wanna comment this part out
for block in blocks:
print(block)
ser.write(bytes.fromhex(block.strip())) #you might wanna comment this part out
time.sleep(1)
win.after(200, task)
win.after(200, task)
win.mainloop()
To avoid freezing, one of the way is to use thread:
from threading import Thread
...
def task():
while True:
MyVar = v.get()
...
blocks = [Block_2Output, block_3, Block_4Output, block_5, block_6, block_7, block_8, block_9, block_10, block_11, block_12]
with serial.Serial('COM5', '9600') as ser: #you might wanna comment this part out
for block in blocks:
print(block)
ser.write(bytes.fromhex(block.strip())) #you might wanna comment this part out
time.sleep(1)
time.sleep(0.2)
# run task() in a thread
Thread(target=task, daemon=1).start()
win.mainloop()

Using guizero and a text datafile to create GUI

So I'm trying to help a student figure out how to create a simple quiz by reading from a text file with the questions, options, and answers. He wants to use guizero instead of the simple built-in input() and print() functions.
I would like him to avoid creating a separate check function for each question, but I don't have much experience with guizero. I've been reading the manual pages, and the below code approximates what we are trying to accomplish but doesn't work because selected_value is not defined until after the program runs. Am I approaching this the wrong way?
from guizero import App, Text, ButtonGroup
app = App(title="Quiz Test", height=800, width=600)
def check_answer(selected_value, answer):
if selected_value == answer:
result.value = "Correct"
else:
result.value = "Wrong"
question_data = []
data_file = open("quiz_ques.txt", 'r')
for line in data_file.read().splitlines():
question_data = line.split(", ")
question_data.reverse() ; question = question_data.pop()
question_data.reverse() ; answer = question_data.pop()
q_options = question_data
text = Text(app, text=question)
choice = ButtonGroup(app, options=q_options, selected=1, command=check_answer, args=[selected_value, answer])
result = Text(app)
data_file.close()
app.display()
try changing
command=check_answer()
to
command=check_answer
in the original version you were calling check_answer() as soon as you defined your program... in the second version it will not be called until the button is clicked
I figured this out using a couple of lists for anyone looking for a solution. Someone who is more of a python expert could probably simplify this, using some pythonic idiom, built-in functions, or standard modules, but this solution works even if it's a bit of a hack. Improvements on this are welcomed. :)
from guizero import App, Text, ButtonGroup
app = App(title="Quiz Test", height=800, width=600)
def check_answer(answer, result, cnt):
if choices[cnt].value == answer:
result.text_color = 'green'
result.value = "Correct"
update_score()
else:
result.text_color = 'red'
result.value = "Wrong"
update_score()
def update_score():
score = 0
for result in results:
if result.value == "Correct":
score += 1
score_txt.value = "Score: " + str(score)
question_data = []
data_file = open("quiz_ques.txt", 'r')
cnt = 0
results = []
choices = []
for line in data_file.read().splitlines():
question_data = line.split(", ")
question_data.reverse() ; question = question_data.pop()
question_data.reverse() ; answer = question_data.pop()
q_options = question_data
question = Text(app, text=question)
question.text_color = 'white'
results.append(Text(app))
choices.append(ButtonGroup(app, options=q_options, command=check_answer, args=[answer, results[cnt], cnt]))
cnt += 1
score_txt = Text(app, color='white', size=40)
data_file.close()
app.display()

How to convert below tkinter code into multi threading?

I have method in my tkinter application. This method is used to export data into CSV from another application. The loop for export the data is very heavy. It takes days of time to complete.
I just came across the multi threading concept. Its kind of difficult to understand, I spent an entire day on this but couldn't achieve anything. Below is the code I use in my loop. Can this be handled by multiple threads without freezing my tkinter UI?
I have a Label that shows the number of records(cells) exported, in the tkinter window.
def export_cubeData(self):
exportPath = self.entry_exportPath.get()
for b in itertools.product(*(k.values())):
self.update()
if (self.flag == 0):
list1 = list()
for pair in zip(dims, b):
list1.extend(pair)
list1.append(self.box_value.get())
mdx1 = mdx.format(*temp, *list1)
try:
data = tm1.cubes.cells.execute_mdx(mdx1)
data1 = Utils.build_pandas_dataframe_from_cellset(data)
final_df = final_df.append(data1)
cellCount = tm1.cubes.cells.execute_mdx_cellcount(mdx1)
finalcellCount = finalcellCount + cellCount
self.noOfRecordsProcessed['text'] = finalcellCount
except:
pass
else:
tm.showinfo("Export Interrupted", "Data export has been cancelled")
return
final_df.to_csv(exportPath)
print(time.time() - start)
tm.showinfo("info", "Data export has been completed")
self.noOfRecordsProcessed['text'] = '0'

Passing a variable between two functions

The following is a piece of code that I have been working on for awhile. I've been able to compile and run the code without error. However, I am having a difficult time with passing a variable from one function to another in my code.
The problem seems to occur after I run choose() and create self.newLists based on the desired indices. You'll notice that I added print(self.newLists) at the end of this function so that I can check to see if it is producing what I want.
The next function, simplify(), is where my issue arises. When I try to pass self.newLists from the previous function it doesn't seem to produce anything. I also tried printing and/or returning the variable named answer but it returns "none". I've been stumbling over this obstacle for awhile without any progress. Below is the code I am working on along with an example of what I want simplify() to produce.
from tkinter import *
from tkinter.filedialog import askopenfilename
class myFileOpener:
def __init__(self, master):
frame = Frame(master)
frame.pack()
print()
self.newLists = ()
self.printButton = Button(frame, text="Select File", command=self.openfile)
self.printButton.pack(side=LEFT)
self.runButton = Button(frame, text="Run", command=self.combine)
self.runButton.pack(side=LEFT)
self.quitButton = Button(frame, text="Quit", command=frame.quit)
self.quitButton.pack(side=LEFT)
def openfile(self):
filename = askopenfilename(parent=root)
self.lines = open(filename)
# print(self.lines.read())
def choose(self):
g = self.lines.readlines()
for line in g:
matrix = line.split()
JD = matrix[2]
mintime = matrix[5]
maxtime = matrix[7]
self.newLists = [JD, mintime, maxtime]
print(self.newLists)
def simplify(self):
dates = {}
for sub in self.newLists:
date = sub[0]
if date not in dates:
dates[date] = []
dates[date].extend(sub[1])
answer = []
for date in sorted(dates):
answer.append([date] + dates[date])
return answer
def combine(self):
self.choose()
self.simplify()
root = Tk()
b = myFileOpener(root)
root.mainloop()
Example of desired output from simplify():
[['2014-158', '20:07:11.881', '20:43:04.546', '20:43:47.447', '21:11:08.997', '21:11:16.697', '21:22:07.717'],
['2014-163', '17:12:09.071', '17:38:08.219', '17:38:28.310', '17:59:25.649', '18:05:59.536', '18:09:53.243', '18:13:47.671', '18:16:53.976', '18:20:31.538', '18:23:02.243']]
It essentially groups times by certain dates.
You are not producing a list of lists. You are resetting self.newLists each loop iteration, to a single list with 3 elements:
for line in g:
matrix = line.split()
JD = matrix[2]
mintime = matrix[5]
maxtime = matrix[7]
self.newLists = [JD, mintime, maxtime]
You need to instead use list.append() to add those 3 elements to a list you set once, outside of the loop:
self.newLists = []
for line in g:
matrix = line.split()
JD = matrix[2]
mintime = matrix[5]
maxtime = matrix[7]
self.newLists.append([JD, mintime, maxtime])
Your simplify method is adding the individual characters of mintime to your output lists:
for sub in self.newLists:
date = sub[0]
if date not in dates:
dates[date] = []
dates[date].extend(sub[1])
You want to use list.append() there, not list.extend(). That loop can be simplified using dict.setdefault() rather than test for the key manually:
for date, mintime, maxtime in self.newLists:
dates.setdefault(date, []).append(mintime)

Python Tkinter Treeview - Iterating 'get_children' output

I am trying to later iterate through the data inside of the Treeview. I will then hope to be able to sort through it.
from tkinter import *
from tkinter.ttk import *
import pickle
root = Tk()
def treeData(event):
children = tree.get_children()
print(children)
entry = StringVar()
a = Entry(root, textvariable=entry)
a.grid(column=0,row=0)
a.bind("<Key>", function)
file_data = []
file = open('data.dat', 'rb')
while True:
try:
file_data.append(pickle.load(file))
except EOFError:
break
file.close()
column_names = ("Column 1", "Column 2")
tree = Treeview(root, columns=column_names)
tree['show'] = 'headings'
for x in file_data:
a = tree.insert('', 'end', values=x)
for col in column_names:
tree.heading(col, text=col)
tree.grid(column=0, row=1)
In the function, called 'treeData' when I print(children) it outputs a list that looks similar to this - ('I001', 'I002', 'I003', 'I004')
I am hoping someone will know how to convert these pieces of data into what is actually shown in the row of the Treeview?
Thanks,
What you are asking is documented in the official tkinter documentation for the Treeview widget.
The get_children method returns a list of item IDs, one for each child. The item method of the treeview will return a dictionary of data for a given item. Thus, you can iterate over the values with something like this:
for child in tree.get_children():
print(tree.item(child)["values"])

Categories

Resources