Python GUI and function calling using Tkinter - python

I am new to python and trying to build a GUI that takes from date and to date from user and reads the data accordingly from a csv file and display the urine output (calculated in the csvimport fucntion). I also want to plot the graph for a specific time and urine output in that time.
Can anyone help me? My code so far is below and it isn't displaying any GUI. Please can anyone correct the basic errors and help me in running this?
import csv
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showwarning, showinfo
import datetime
#csv_file = csv.reader(open("C:\Users\Lala Rushan\Downloads\ARIF Drop Monitoring Final\ARIF Drop Monitoring Final\DataLog.csv"))
from Tools.scripts.treesync import raw_input
class App(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.in_file = None
button1 = Button(self, text="Browse for a file", command=self.askfilename)
button2 = Button(self, text="Count the file", command=self.takedate())
button3 = Button(self, text="Exit", command=master.destroy)
button1.grid()
button2.grid()
button3.grid()
self.grid()
def askfilename(self):
in_file = askopenfilename()
if not in_file.endswith(('.csv')):
showwarning('Are you trying to annoy me?', 'How about giving me a CSV file, genius?')
else:
self.in_file=in_file
def CsvImport(csv_file):
dist = 0
for row in csv_file:
_dist = row[0]
try:
_dist = float(_dist)
except ValueError:
_dist = 0
dist += _dist
print ("Urine Volume is: %.2f" % (_dist*0.05))
def takedate(self):
from_raw = raw_input('\nEnter FROM Date (e.g. 2013-11-29) :')
from_date = datetime.date(*map(int, from_raw.split('/')))
print ('From date: = ' + str(from_date))
to_raw = raw_input('\nEnter TO Date (e.g. 2013-11-30) :')
to_date = datetime.date(*map(int, to_raw.split('/')))
in_file = ("H:\DataLog.csv")
in_file= csv.reader(open(in_file,"r"))
for line in in_file:
_dist = line[0]
try:
file_date = datetime.date(*map(int, line[1].split(' ')[1].split('/')))
if from_date <= file_date <= to_date:
self.CsvImport(in_file)
except IndexError:
pass
root = Tk()
root.title("Urine Measurement")
root.geometry("500x500")
app = App(root)
root.mainloop()

You are calling takedate method as soon as you are initializing your class. Removing parentheses(which means, call the method) would solve your issue.
button2 = Button(self, text="Count the file", command=self.takedate())
^^ remove these
Your GUI doesn't show up because takedate method makes your program to wait for user input because of raw_input(..) calls.
You should consider using Entry instead of raw_input() for getting user input.
EDIT: You can put two Entry in your __init__ then use Entry's get method in takedate. Roughly something like below.
def __init__(self, master):
...
...
self.userInputFromRaw = Entry(self)
self.userInputFromRaw.grid()
self.userInputToRaw = Entry(self)
self.userInputToRaw.grid()
def takedate(self):
...
from_raw = self.userInputFromRaw.get()
...
to_raw = self.userInputToRaw.get()
Also, you should add self parameter when defining your method since it is part of that class.
def CsvImport(self, csv_file):

If you not want to pass parameters into self.takedate() remove ()as below:
button2 = Button(self, text="Count the file", command=self.takedate)
or change to
button2 = Button(self, text="Count the file", command=lambda e=Null: self.takedate())
In this case you can pass e parameter to self.takedate(). Pass it to this maner:
command=lambda e=Null: self.takedate(e)
def takedate(self, parameter): pass

Related

I'm unable to get a string out of tkinter entrybox

import random
import tkinter as tk
frame = tk.Tk()
frame.title("koeweils baldadige encyptor")
frame.geometry('400x200')
printButton = tk.Button(frame,text = "Print", command = lambda: zandkasteel())
printButton.pack()
freek = tk.Text(frame,height = 5, width = 20)
freek.pack()
input_a = freek.get(1.0, "end-1c")
print(input_a)
fruit = 0
fad = input_a[fruit:fruit+1]
print(fad)
schepje = len(input_a.strip("\n"))
print(schepje)
def zandkasteel():
lbl.config(text = "Ingevulde string: "+input_a)
with open("luchtballon.txt", "w") as chocoladeletter:
for i in range(schepje):
n = random.randint()
print(n)
leuk_woord = ord(fad)*n
print(leuk_woord)
chocoladeletter.write(str(leuk_woord))
chocoladeletter.write(str(n))
chocoladeletter.write('\n')
lbl = tk.Label(frame, text = "")
lbl.pack()
frame.mainloop()
I need to get the string that was entered into the text entry field freek. I have tried to assign that string to input_a, but the string doesn't show up.
Right now, input_a doesn't get anything assigned to it and seems to stay blank. I had the same function working before implementing a GUI, so the problem shouldn't lie with the def zandkasteel.
To be honest I really don't know what to try at this point, if you happen to have any insights, please do share and help out this newbie programmer in need.
Here are some simple modifications to your code that shows how to get the string in the Text widget when it's needed — specifically when the zandkasteel() function gets called in response to the user clicking on the Print button.
import random
import tkinter as tk
frame = tk.Tk()
frame.title("koeweils baldadige encyptor")
frame.geometry('400x200')
printButton = tk.Button(frame, text="Print", command=lambda: zandkasteel())
printButton.pack()
freek = tk.Text(frame, height=5, width=20)
freek.pack()
def zandkasteel():
input_a = freek.get(1.0, "end-1c")
print(f'{input_a=}')
fruit = 0
fad = input_a[fruit:fruit+1]
print(f'{fad=}')
schepje = len(input_a.strip("\n"))
print(f'{schepje=}')
lbl.config(text="Ingevulde string: " + input_a)
with open("luchtballon.txt", "w") as chocoladeletter:
for i in range(schepje):
n = random.randint(1, 3)
print(n)
leuk_woord = ord(fad)*n
print(leuk_woord)
chocoladeletter.write(str(leuk_woord))
chocoladeletter.write(str(n))
chocoladeletter.write('\n')
lbl = tk.Label(frame, text="")
lbl.pack()
frame.mainloop()

Generating OTP through python

I'm trying to build a random OTP generator but I coming across this error message, can anyone help me
error :
File "C:\Users\HP\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2692, in insert
self.tk.call(self._w, 'insert', index, string)
_tkinter.TclError: wrong # args: should be ".!entry3 insert index text"
my code:
import random
from tkinter import *
from tkinter.ttk import *
root = Tk()
#generting otp
def generate():
entry.delete(0,END)
digits = "0123456789"
otp1 =""
for i in range (4):
opt1 = otp1 + random.choice (digits)
entry.insert(10,otp1)
#GUI
Usn_label = Label(root , text = "USN")
Usn_label.grid(row = 0 )
Usn_entry = Entry(root , textvariable='usn_var')
Usn_entry.grid(row =0 , column = 1)
phone_label = Label (root , text = " Phone Number ")
phone_label.grid (row = 2)
phone_entry = Entry (root , textvariable='phone number')
phone_entry.grid(row = 2, column = 1)
Gen_label =Button(root , text= 'Generate', command = generate)
Gen_label.grid (row = 3 , column = 1 , sticky='w')
Random_otp = Label (root, text = "OTP")
Random_otp.grid (row = 4 )
entry = Entry(root)
entry.grid(row = 4, column = 1)
root.title("Otp Generator ")
root.mainloop()
I ran your script and didn't get any errors, but you made at least one mistake (arguably more).
you delete the entry text, but then try to insert text at index 10
you misspelled otp1 (as 'opt1') in your loop
#generting otp
def generate(L=4):
entry.delete(0, END)
entry.insert(0, f'{random.choice(range(0, pow(10, L)))}'.zfill(L))
I believe this is much cleaner. The logic is dead simple. Generate a number from 0 to 9999 and pad the left side with zeroes for any number that has less than 4 characters. For longer or shorter numbers just change L.
If you wanted to clean up your entire script. You may want to consider the following:
Unless you intend to do something with your Labels, such as: change their text or remove them entirely, there is no reason to store a reference to them.
textvariable expects a tk.StringVar(), dumping an arbitrary str into it does nothing (for me), but is probably the source of the error for you.
The user does not need to click a Button to generate an arbitrary random number. You can simply generate it automatically as soon as the program executes.
Labels with text like "USN" and "OTP" are not user-friendly.
import random
import tkinter as tk
root = tk.Tk()
root.title("OTP Generator ")
def random_key(L=4):
return f'{random.choice(range(0, pow(10, L)))}'.zfill(L)
#generate otp for this session
otp = random_key(8)
#GUI
tk.Label(root, text="Username:", anchor='e').grid(row=0, sticky='e')
usn_entry = tk.Entry(root)
usn_entry.grid(row=0 , column=1, sticky='w')
tk.Label(root, text="Phone Number:", anchor='e').grid(row=2, sticky='e')
phone_entry = tk.Entry(root)
phone_entry.grid(row=2, column=1, sticky='w')
tk.Label(root, text="PIN:", anchor='e').grid(row=4, sticky='e')
pin = tk.Entry(root, width=len(otp))
pin.grid(row=4, column=1, sticky='w')
pin.insert(0, otp)
pin.configure(state='read')
root.mainloop()
If you wanted to take it even further, you could consider that you keep creating the same Label/Entry combo, over and over. You could simply create a class that represents that combination, and use it instead.
import random
import tkinter as tk
class LabeledEntry(tk.Frame):
#property
def text(self) -> str:
return self.__entry.get()
#text.setter
def text(self, value:str):
self.__entry.delete(0, 'end')
self.__entry.insert(0, value)
#property
def entry(self) -> tk.Entry:
return self.__entry
#property
def state(self) -> str:
return self.__entry['state']
#state.setter
def state(self, value:str):
self.__entry.configure(state=value)
def __init__(self, master, text:str, column=None, row=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.grid(column=column, row=row)
tk.Label(self, text=text, anchor='e', width=12).grid(row=0, column=0, sticky='e')
self.__entry = tk.Entry(self)
self.__entry.grid(row=0, column=1, sticky='w')
root = tk.Tk()
root.title("OTP Generator ")
def random_key(L=4):
return f'{random.choice(range(0, pow(10, L)))}'.zfill(L)
#generate otp for this session
otp = random_key(8)
#GUI
user_field = LabeledEntry(root, 'Username: ')
phone_field = LabeledEntry(root, 'Phone Number: ')
pin_field = LabeledEntry(root, 'PIN: ')
pin_field.text = otp
pin_field.state = 'read'
root.mainloop()

How to retrieve a value from Tkinter class and use it in another?

I have run into a problem with Tkinter and I cannot figure it out with hours of Googling. I found a large chunk of code which creates a calendar in Tkinter and returns the date in a certain format. When I use another class to try and access that data, it returns either errors, the location of where the text is stored, or just not what I need at all.
Here is the baseline code which creates a tkinter calendar application (credit to Rambarun Komaljeet)
import calendar
import tkinter as tk
import time
from tkinter import ttk
import sys
class MyDatePicker(tk.Toplevel):
"""
Description:
A tkinter GUI date picker.
"""
def __init__(self, widget=None, format_str=None):
"""
:param widget: widget of parent instance.
:param format_str: print format in which to display date.
:type format_str: string
Example::
a = MyDatePicker(self, widget=self.parent widget,
format_str='%02d-%s-%s')
"""
super().__init__()
self.widget = widget
self.str_format = format_str
self.title("Date Picker")
self.resizable(0, 0)
self.geometry("+630+390")
self.init_frames()
self.init_needed_vars()
self.init_month_year_labels()
self.init_buttons()
self.space_between_widgets()
self.fill_days()
self.make_calendar()
def init_frames(self):
self.frame1 = tk.Frame(self)
self.frame1.pack()
self.frame_days = tk.Frame(self)
self.frame_days.pack()
def init_needed_vars(self):
self.month_names = tuple(calendar.month_name)
self.day_names = tuple(calendar.day_abbr)
self.year = time.strftime("%Y")
self.month = time.strftime("%B")
def init_month_year_labels(self):
self.year_str_var = tk.StringVar()
self.month_str_var = tk.StringVar()
self.year_str_var.set(self.year)
self.year_lbl = tk.Label(self.frame1, textvariable=self.year_str_var,
width=3)
self.year_lbl.grid(row=0, column=5)
self.month_str_var.set(self.month)
self.month_lbl = tk.Label(self.frame1, textvariable=self.month_str_var,
width=8)
self.month_lbl.grid(row=0, column=1)
def init_buttons(self):
self.left_yr = ttk.Button(self.frame1, text="←", width=5,
command=self.prev_year)
self.left_yr.grid(row=0, column=4)
self.right_yr = ttk.Button(self.frame1, text="→", width=5,
command=self.next_year)
self.right_yr.grid(row=0, column=6)
self.left_mon = ttk.Button(self.frame1, text="←", width=5,
command=self.prev_month)
self.left_mon.grid(row=0, column=0)
self.right_mon = ttk.Button(self.frame1, text="→", width=5,
command=self.next_month)
self.right_mon.grid(row=0, column=2)
def space_between_widgets(self):
self.frame1.grid_columnconfigure(3, minsize=40)
def prev_year(self):
self.prev_yr = int(self.year_str_var.get()) - 1
self.year_str_var.set(self.prev_yr)
self.make_calendar()
def next_year(self):
self.next_yr = int(self.year_str_var.get()) + 1
self.year_str_var.set(self.next_yr)
self.make_calendar()
def prev_month(self):
index_current_month = self.month_names.index(self.month_str_var.get())
index_prev_month = index_current_month - 1
# index 0 is empty string, use index 12 instead,
# which is index of December.
if index_prev_month == 0:
self.month_str_var.set(self.month_names[12])
else:
self.month_str_var.set(self.month_names[index_current_month - 1])
self.make_calendar()
def next_month(self):
index_current_month = self.month_names.index(self.month_str_var.get())
try:
self.month_str_var.set(self.month_names[index_current_month + 1])
except IndexError:
# index 13 does not exist, use index 1 instead, which is January.
self.month_str_var.set(self.month_names[1])
self.make_calendar()
def fill_days(self):
col = 0
# Creates days label
for day in self.day_names:
self.lbl_day = tk.Label(self.frame_days, text=day)
self.lbl_day.grid(row=0, column=col)
col += 1
def make_calendar(self):
# Delete date buttons if already present.
# Each button must have its own instance attribute for this to work.
try:
for dates in self.m_cal:
for date in dates:
if date == 0:
continue
self.delete_buttons(date)
except AttributeError:
pass
year = int(self.year_str_var.get())
month = self.month_names.index(self.month_str_var.get())
self.m_cal = calendar.monthcalendar(year, month)
# build dates buttons.
for dates in self.m_cal:
row = self.m_cal.index(dates) + 1
for date in dates:
col = dates.index(date)
if date == 0:
continue
self.make_button(str(date), str(row), str(col))
def make_button(self, date, row, column):
"""
Description:
Build a date button.
:param date: date.
:type date: string
:param row: row number.
:type row: string
:param column: column number.
:type column: string
"""
exec(
"self.btn_" + date + " = ttk.Button(self.frame_days, text=" + date
+ ", width=5)\n"
"self.btn_" + date + ".grid(row=" + row + " , column=" + column
+ ")\n"
"self.btn_" + date + ".bind(\"<Button-1>\", self.get_date)"
)
def delete_buttons(self, date):
"""
Description:
Delete a date button.
:param date: date.
:type: string
"""
exec(
"self.btn_" + str(date) + ".destroy()"
)
def get_date(self, clicked=None):
"""
Description:
Get the date from the calendar on button click.
:param clicked: button clicked event.
:type clicked: tkinter event
"""
clicked_button = clicked.widget
year = self.year_str_var.get()
month = self.month_str_var.get()
date = clicked_button['text']
self.full_date = self.str_format % (date, month, year)
print(self.full_date)
sys.stderr.write(self.full_date)
# Replace with parent 'widget' of your choice.
try:
self.widget.delete(0, tk.END)
self.widget.insert(0, self.full_date)
except AttributeError:
pass
if __name__ == '__main__':
def application():
MyDatePicker(format_str='%02d-%s-%s')
root = tk.Tk()
btn = tk.Button(root, text="test", command=application)
btn.pack()
root.mainloop()
What I've been trying to do is get that data back into the first tkinter box that I open so I can use it for a search feature. It seems that the actual stuff I need is in the get_date() section where it pulls information and prints out the date in the console as the variable self.full_date.
How do I get this to work within a different class? This is what I have so far (the MyDatePicker is also there but I didn't want to clutter too much space)
class Main_Window(tk.Frame,MyDatePicker):
def __init__(self, root):
self.root=root
#self.MyDatePicker=MyDatePicker()
tk.Frame.__init__(self, root)
self.root.geometry('300x300')
b1 = tk.Button(self.root, text="Add another window", command =lambda: self.newWindow(1))
b1.grid(column=1, row=1)
self.total = 0
self.count=0
self.total_label_text = tk.IntVar()
self.total_label_text.set(self.total)
#self.total_label_text
self.lbl1=tk.Label(self.root,textvariable=self.total_label_text)
self.lbl1.grid(column=1,row=2)
b2 = tk.Button(self.root, text="Add another window", command =lambda: self.newWindow(2))
b2.grid(column=2, row=1)
self.total2 = 0
self.count2=0
self.total_label_text2 = tk.IntVar()
self.total_label_text2.set(self.total2)
#self.total_label_text
self.lbl2=tk.Label(self.root,textvariable=self.total_label_text2)
self.lbl2.grid(column=2,row=2)
b1 = tk.Button(self.root, text="Add another window", command =lambda: self.press_calendar(format_str='%02d-%s-%s',Class=MyDatePicker))
b1.grid(column=1, row=1)
def press_calendar(self,format_str,Class):
self.MyDatePicker1=Class(format_str)
self.MyDatePicker1.get_date(self)
def newWindow(self,m):
if m ==1:
self.count += 1
if m ==2:
self.count2+=1
self.window = tk.Toplevel(self)
but1=tk.Button(self.window,text="Add One",command =lambda:self.close(m))
but1.grid(row=2,column=1)
def close(self,m):
if m==1:
self.total_label_text.set(self.count)
if m==2:
self.total_label_text2.set(self.count2)
self.window.destroy()
if __name__ == "__main__":
root = tk.Tk()
Main_Window(root)
root.mainloop()
I'm trying to make this happen in the press_calendar part of my code where I call the other class, run it, and have it return the date.
All I'm getting is the variable location or I have to initialize all the variables from the MyDatePicker in the Main_Window class.
What can I do better to actually retrieve the date and use it in my main window?
Thank you for the help!
As far as I can see, the MyDatePicker() class is not intended to be inherited, but used as a server. In my example I'm calling MyDatePicker() and providing the widget of master where I'd like the date string to be sent.
class Main_Window(tk.Frame):
def __init__(self, root):
self.root = root
self.root.geometry('300x300')
tk.Frame.__init__(self, root)
self.pack()
b1 = tk.Button(self, text="Pick date", command=self.pick_date)
b1.grid(column=0, row=0)
# Widget to recieve date string from MyDatePicker
self.date_display = tk.Entry(self, text='apa', width=20)
self.date_display.grid(column=0, row=1)
def pick_date(self):
# Call MyDatePicker and provide widget to recieve date string
picker = MyDatePicker(widget=self.date_display, format_str='%02d-%s-%s')
if __name__ == "__main__":
root = tk.Tk()
Main_Window(root)
root.mainloop()
You will have to remove the if __name__ == "__main__": section from the MyDatePicker() code for it to function if the are to be in the same file.

Python Program calculating CSV data as Zero

I have a code that reads the csv file and calculates the liquid output. it was working for previous csv files but now for an updated csv file it is giving output as 0.0. Can anyone explain any glitch in the code?
My code is below:
import csv
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showwarning, showinfo
import datetime
#csv_file = csv.reader(open("C:\Users\Lala Rushan\Downloads\ARIF Drop Monitoring Final\ARIF Drop Monitoring Final\DataLog.csv"))
from Tools.scripts.treesync import raw_input
class App(Frame):
def __init__(self, master):
Frame.__init__(self, master)
button1 = Button(self, text="Browse for a file", command=self.askfilename)
button2 = Button(self, text="Measure The Urine", command=self.takedate)
button3 = Button(self, text="Exit", command=master.destroy)
button1.grid()
button2.grid()
button3.grid()
l1 = Label(self, text="Enter from date (2017/01/01)")
l1.grid()
self.userInputFromRaw = Entry(self)
self.userInputFromRaw.grid()
l2 = Label(self, text="Enter to date (2017/01/01)")
l2.grid()
self.userInputToRaw = Entry(self)
self.userInputToRaw.grid()
self.output = Text(self)
self.output.grid()
self.grid()
def askfilename(self):
in_file = askopenfilename()
if not in_file.endswith(('.CSV')):
showwarning('Are you trying to annoy me?', 'How about giving me a CSV file, genius?')
else:
self.in_file=in_file
def CsvImport(self,csv_file):
dist = 0
for row in csv_file:
_dist = row[0]
try:
_dist = float(_dist)
except ValueError:
_dist = 0
dist += _dist
self.output.insert(END, "Urine Volume is: %.2f" % (_dist * 0.05))
def takedate(self):
from_raw = self.userInputFromRaw.get()
from_date = datetime.date(*map(int, from_raw.split('/')))
print ('From date: = ' + str(from_date))
to_raw = self.userInputToRaw.get()
to_date = datetime.date(*map(int, to_raw.split('/')))
in_file = ("H:\DataLog.csv")
in_file= csv.reader(open(in_file,"r"))
for line in in_file:
_dist = line[0]
try:
file_date = datetime.date(*map(int, line[1].split(' ')[1].split('/')))
if from_date <= file_date <= to_date:
self.CsvImport(in_file)
except IndexError:
pass
root = Tk()
root.title("Urine Measurement")
root.geometry("500x500")
app = App(root)
root.mainloop()
my csv file looks like this:
2 2017/02/17 19:06:17.188

How to write commands to terminal using tkinter?

I wanted to do something like , if i type something in textbox that command would get executed completely
like this
ie the ~Desktop should be displayed to write next command.
but with my code im getting this also there is an error
as you can see ls command gets executed half in second case
my code is
#!/usr/bin/python
import Tkinter
import subprocess
import tkMessageBox
from Tkinter import *
root = Tk()
class HackBar:
def __init__(self,master):
frame=Frame(master,width = 600,height = 250)
#frame.pack()
def printconsole(event):
print("hello dere ")
def retrieve_input(event):
input = self.Text.get("1.0",'end-1c')
#print(input)
#subprocess.call(input,shell=TRUE)
subprocess.Popen(input)
root.quit()
#root = Tk()
#print p.communicate()
self.button1 = Button(root,text = "Execute")
self.button1.bind("<Button-1>",retrieve_input);
self.button1.grid(row = 0,sticky = E)
self.button2 = Button(root,text = " Quit ")
self.button2.bind("<Button-1>",printconsole);
self.button2.grid(row = 1,sticky = E)
self.Text = Text(root,height =4)
self.Text.grid(row = 0,column = 1,rowspan=2)
menu = Menu(root)
def AboutDialog():
tkMessageBox.showinfo('About','For any issues or suggestion contact rushic24#gmail.com ')
root.config(menu = menu)
submenu1 = Menu(menu)
menu.add_cascade(label="Help",menu=submenu1)
submenu1.add_command(label = "About",command = AboutDialog)
b = HackBar(root)
root.mainloop()
i think i need to use the root.quit() and would again need to start root ,
but it is giving the above error.
Any alternate method would also work.

Categories