I have wrriten this code with the great help from two stackoverflow users. It is the code that is supposed to extract value of filament used from the GCODE (a code for 3D printer to create objects). So far it is working good and the value is shown in the tkinter window as I want. The thing is that this value is expressing Volume of the filament used. Now I would like to two two other values to be calculated and displayed in tkinter window as well 1)mass which will be the volume*1,13
and then price which will be newly found mass*0.175
. The problem is that I can't figure out how to use this value which is found in the gcode and make it usable for calculations. self.value
is the initial variable that is found from the loaded file (here I attach the sample gcode file that you can use to test the code: smaple gcode). I think the problem is that this value is a String and it should be an integer to make calculation int he code I have tried to change it to integer but it didn't work so I have commented it out. Thank you very much for all possible tips and help.
P.S Additionaly I would like the status bar to change after I upload the file, I have also problems achieving this.
The wholde code:
from tkinter import *
import re
from tkinter import messagebox
from tkinter import filedialog
# Here, we are creating our class, Window, and inheriting from the Frame
# class. Frame is a class from the tkinter module. (see Lib/tkinter/__init__)
class Window(Frame):
# Define settings upon initialization. Here you can specify
def __init__(self, master=None):
# parameters that you want to send through the Frame class.
Frame.__init__(self, master)
#reference to the master widget, which is the tk window
self.master = master
#with that, we want to then run init_window, which doesn't yet exist
self.init_window()
# Load the gcode file in and extract the filament value
def get_filament_value(self, fileName):
with open(fileName, 'r') as f_gcode:
data = f_gcode.read()
re_value = re.search('filament used = .*? \(([0-9.]+)', data)
if re_value:
value = float(re_value.group(1))
return('Volume of the print is {} cm3'.format(value))
else:
value = 0.0
return('Filament volume was not found in {}'.format(fileName))
return value
def read_gcode(self):
root.fileName = filedialog.askopenfilename(filetypes = (("GCODE files", "*.gcode"), ("All files", "*.*")))
# self.value.set(self.get_filament_value(root.fileName))
volume = self.get_filament_value(root.fileName)
mass = volume * 1.13
price = mass * 0.175
self.volume_text.set('Volume is {}'.format(volume))
self.mass_text.set('Mass is {}'.format(mass))
self.price_text.set('Price is {}'.format(price))
def client_exit(self):
exit()
def about_popup(self):
messagebox.showinfo("About", "Small software created by Bartosz Domagalski to find used filament parameters from Sli3er generated GCODE")
#Creation of init_window
def init_window(self):
# changing the title of our master widget
self.master.title("Filament Data")
# allowing the widget to take the full space of the root window
self.pack(fill=BOTH, expand=1)
# creating a menu instance
menu = Menu(self.master)
self.master.config(menu=menu)
# create the file object)
file = Menu(menu)
help = Menu(menu)
# adds a command to the menu option, calling it exit, and the
# command it runs on event is client_exit
file.add_command(label="Exit", command=self.client_exit)
help.add_command(label="About", command=self.about_popup)
#added "file" to our menu
menu.add_cascade(label="File", menu=file)
menu.add_cascade(label="Help", menu=help)
#Creating the labels
l_instruction = Label(self, justify=CENTER, compound=TOP, text="Load GCODE file to find volume, \n weight and price of used filament.")
l_instruction.pack()
#Creating the button
gcodeButton = Button(self, text="Load GCODE", command=self.read_gcode)
gcodeButton.pack()
# gcodeButton.place(x=60, y=50)
#Label of the used filament
l1 = Label(self, text="")
l1.pack()
l2 = Label(self, text="")
l2.pack()
self.volume_text = StringVar()
l = Label(self, justify=CENTER, compound=BOTTOM, textvariable=self.volume_text)
l.pack()
self.mass_text = StringVar()
m = Label(self, justify=CENTER, compound=BOTTOM, textvariable=self.mass_text)
m.pack()
self.price_text = StringVar()
p = Label(self, justify=CENTER, compound=BOTTOM, textvariable=self.price_text)
p.pack()
#status Bar
status = Label(self, text="Waiting for file...", bd=1, relief=SUNKEN, anchor=W)
status.pack(side=BOTTOM, fill=X)
# root window created. Here, that would be the only window, but you can later have windows within windows.
root = Tk()
root.resizable(width=False,height=False);
root.geometry("220x300")
#creation of an instance
app = Window(root)
#mainloop
root.mainloop()
This is the error I get:
Traceback (most recent call last):
File "/Users/domagalski/Desktop/test.py", line 112, in <module>
app = Window(root)
File "/Users/domagalski/Desktop/test.py", line 20, in init
self.init_window()
File "/Users/domagalski/Desktop/test.py", line 95, in init_window
self.mass = self.value(self.get_filament_value(root.fileName))
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/tkinter/__init__.py", line 1939, in getattr
return getattr(self.tk, attr)
AttributeError: '_tkinter.tkapp' object has no attribute 'fileName'
In your init_window
method, you are trying to access root.fileName
:
def init_window(self):
# ...
self.mass = self.value.set(self.get_filament_value(root.fileName))
# ...
root.fileName
gets set in read_gcode
:
def read_gcode(self):
root.fileName = filedialog.askopenfilename(filetypes = (("GCODE files", "*.gcode"), ("All files", "*.*")))
# ...
But read_gcode
gets called only when the user clicks a button:
gcodeButton = Button(self, text="Load GCODE", command=self.read_gcode)
Because you need the user to click the Load GCODE button in order to obtain the file name, you should remove the self.mass = ...
code from init_window
: when init_window
gets called, root.fileName
is not available yet. Move that code inside read_gcode
.
Another problem you have is that you are assigning self.mass
to the value returned by self.value.set()
, which is None
. You should instead use the return value from self.get_filament_value()
.
In other words, change this:
def get_filament_value(self, fileName):
# ...
if re_value:
value = float(re_value.group(1))
return('Volume of the print is {} cm3'.format(value))
else:
value = 0.0
return('Filament volume was not found in {}'.format(fileName))
return value
def read_gcode(self):
root.fileName = filedialog.askopenfilename(filetypes = (("GCODE files", "*.gcode"), ("All files", "*.*")))
self.value.set(self.get_filament_value(root.fileName))
def init_window(self):
# ...
self.value = StringVar()
l = Label(self, justify=CENTER, compound=BOTTOM, textvariable=self.value)
l.pack()
# self.mass = self.value.set(self.get_filament_value(root.fileName))
# int(self.mass)
# m = Label(self, justify=CENTER, compound=BOTTOM, textvariable=self.mass)
# m.pack()
# ...
to this:
def get_filament_value(self, fileName):
# ...
if re_value:
return float(re_value.group(1))
else:
return 0.0
def read_gcode(self):
root.fileName = filedialog.askopenfilename(filetypes = (("GCODE files", "*.gcode"), ("All files", "*.*")))
volume = self.get_filament_value(root.fileName)
mass = volume * 1.13
self.volume_text.set('Volume is {}'.format(volume))
self.mass_text.set('Mass is {}'.format(mass))
def init_window(self):
# ...
self.volume_text = StringVar()
self.mass_text = StringVar()
volume_label = Label(self, justify=CENTER, compound=BOTTOM, textvariable=self.volume_text)
volume_label.pack()
mass_label = Label(self, justify=CENTER, compound=BOTTOM, textvariable=self.mass_text)
mass_label.pack()
# ...