Creating popup using Return in pandastable - python

How can I customize the package panastable so that when i press Return in the display, a warning pops up. I tried to bind Return to the function callback, which should create the messagebox. But nothing happens. It should give the warning after I enter new content in the cell and press Return. This is code I'm using:
import pandas as pd
from pandastable import Table
import tkinter as tk
from tkinter import messagebox
class MyTable(Table):
def callback(self, event):
messagebox.showinfo(title="Achtung", message="Achtung")
def showWarning(self):
self.bind('<Return>', self.callback)
top = tk.Tk()
top.geometry("300x1000")
df = pd.DataFrame()
df["column1"] = [1,2,3,4,5]
frame = tk.Frame(top)
frame.pack(fill="both", expand=True)
pt = MyTable(frame, dataframe=df)
pt.show()
pt.focus_set()
pt.showWarning()
button = tk.Button(top, text="Änderungen speichern", command=top.quit)
button.pack()
top.mainloop()

So there is a much better approach to this IMO (because using what is inherited):
import pandas as pd
from pandastable import Table
import tkinter as tk
from tkinter import messagebox
class MyTable(Table):
#staticmethod
def show_info():
messagebox.showwarning(title="Achtung", message="Achtung")
def handleCellEntry(self, row, col):
super().handleCellEntry(row, col)
self.show_info()
root = tk.Tk()
root.geometry("300x1000")
df = pd.DataFrame()
df["column1"] = [1, 2, 3, 4, 6]
frame = tk.Frame(root)
frame.pack(fill="both", expand=True)
pt = MyTable(frame, dataframe=df)
pt.show()
button = tk.Button(root, text="Änderungen speichern", command=root.quit)
button.pack()
root.mainloop()
Using the inherited method handleCellEntry which is called when enter key is pressed while editing the entry, just what you seem to need. You can see in the source code how this method is bound to '<Return>' sequence to that specific entry (so just override it, call the super method (so it does what it is supposed to do) and then your own method (or vice versa but then the entry will be changed only after you close the dialog)).

The solution was binding it the top window. The following code get the wanted result:
import pandas as pd
from pandastable import Table
import tkinter as tk
from tkinter import messagebox
top = tk.Tk()
top.geometry("300x1000")
df = pd.DataFrame()
df["column1"] = [1,2,3,4,5]
frame = tk.Frame(top)
frame.pack(fill="both", expand=True)
def callback(*args):
messagebox.showinfo(title="Achtung", message="Achtung")
top.bind('<Return>', callback)
pt = Table(frame, dataframe=df)
pt.show()
button = tk.Button(top, text="Änderungen speichern", command=top.quit)
button.pack()
top.mainloop()

Related

fix tkinter Progressbar with Threading

good evening for all
for a project I have to read and filter a big table (more than 50k lines) using tkinter for this I created a progressbar which is activated while the application calls the filter function in the background.
the problem is that my progress bar does not move i tried with the threading library but nothing changed. does anyone have a solution?
if you also have an idea to insert the lines more quickly in the treeview it would really help me a lot
import tkinter as tk
from tkinter import *
from tkinter import ttk
import numpy as np
import pandas as pd
from threading import *
import time
class Application(tk.Tk):
def __init__(self):
Tk.__init__(self)
self.title("table manipulation")
# I create a random table with 50 rows
self.my_table=pd.DataFrame(np.random.rand(50,4))
#I create a Progressbar
self.progressbar=ttk.Progressbar(self,orient='horizontal',mode='indeterminate',length=280,value=0)
self.progressbar.pack(fill=X)
#I create a single filter for the example
self.filter_frame = Frame(self)
self.filter_frame.pack()
self.create_filter()
#I create a table with tkinter treeview
self.table_frame = Frame(self)
self.table_frame.pack()
self.tree = ttk.Treeview(self.table_frame, show='headings')
self.create_table()
def create_filter(self):
#for example i create one filter
self.my_filter=ttk.Combobox(self.filter_frame,values=[''] +list(set(self.my_table.values.tolist()[0])) , state="readonly")
self.my_filter.pack()
self.my_filter.bind('<<ComboboxSelected>>', self.threading)
def create_table(self):
self.tree["columns"] =self.my_table.columns.values.tolist()
self.tree.pack(expand=TRUE, fill=X)
for i in self.my_table.columns.values.tolist():
self.tree.column(i, anchor="w")
self.tree.heading(i, text=i, anchor="w")
for n in range(len(self.my_table)):
self.tree.insert("", "end", text=n, values=self.my_table.values.tolist()[n])
def filter_function(self,*args):
for n in self.tree.get_children():
time.sleep(1) #to check if my progressbar moves
if self.tree.item(n)['values'][0]!=self.my_filter.get():
self.tree.delete(n)
def threading(self,*args):
self.progressbar.start()
t1=Thread(target=self.filter_function())
t1.start()
self.progressbar.stop()
Application().mainloop()
I found the solution for those who need it
import tkinter as tk
from tkinter import *
from tkinter import ttk
import numpy as np
import pandas as pd
import threading
import time
class Application(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("table manipulation")
# I create a random table with 10 rows
self.my_table=pd.DataFrame(np.random.rand(10,4))
#I create a Progressbar
self.progressbar=ttk.Progressbar(self,orient='horizontal',mode='indeterminate',length=280,value=0)
self.progressbar.pack()
#I create a single filter for the example
self.filter_frame = tk.Frame(self)
self.filter_frame.pack()
self.create_filter()
#I create a table with tkinter treeview
self.table_frame = tk.Frame(self)
self.table_frame.pack()
self.treeview = ttk.Treeview(self.table_frame, show='headings')
threading.Thread(target=self.create_table() , daemon=True).start()
def create_filter(self):
#for example i create one filter
self.my_filter=ttk.Combobox(self.filter_frame,values=[''] +list(set(self.my_table.values.tolist()[0])) , state="readonly")
self.my_filter.pack()
self.my_filter.bind('<<ComboboxSelected>>', self.threading)
def create_table(self):
self.treeview["columns"] =self.my_table.columns.values.tolist()
self.treeview.pack()
for i in self.my_table.columns.values.tolist():
self.treeview.column(i, anchor="w")
self.treeview.heading(i, text=i, anchor="w")
for n in range(len(self.my_table)):
self.treeview.insert("", "end", text=n, values=self.my_table.values.tolist()[n])
def test(self):
for n in range(200):
time.sleep(1) #to check if my progressbar moves
def filter_function(self,*args):
self.progressbar.start()
for n in self.treeview.get_children():
time.sleep(1) #to check if my progressbar moves
if self.treeview.item(n)['values'][0]!=self.my_filter.get():
self.treeview.delete(n)
self.progressbar.stop()
def threading(self,*args):
threading.Thread(target=self.filter_function , daemon=True).start()
Application().mainloop()

Add DataFrame to Tkinter's tab's

I need to add a Pandas DataFrame to Tkinter one of the tabs. DataFrame is made from csv file.
I have a code
from tkinter import ttk
import tkinter as tk
from tkinter import *
root = tk.Tk()
root.title("Inofin Sprendimai")
root.geometry('500x400')
nb = ttk.Notebook(root)
page1 = ttk.Frame(nb)
page2 = ttk.Frame(nb)
page3 = ttk.Frame(nb)
page4 = ttk.Frame(nb)
nb.add(page1, text='ID And Statistic')
nb.add(page2, text='Table With Names')
nb.add(page3, text="Table With ID's")
nb.add(page4, text='Settings')
nb.pack(fill=BOTH, expand=1)
root.mainloop()`
DataFrame should be in the second and third tab of the table...
I can put DataFrame to Tkinter with this code:
root = Tk()
root.geometry('580x250')
# I put dataframe in here. Now it is just a random df
dates = pd.date_range('20210101', periods=8)
dframe=pd.DataFrame(np.random.randn(8,4),index=dates,columns=list('ABCD'))
txt = Text(root)
txt.pack()
class PrintToTXT(object):
def write(self, s):
txt.insert(END, s)
sys.stdout = PrintToTXT()
print (frame)
mainloop()
Grateful for any help!

How to expand entry box with window in tkinter?

I'm just creating simple window using tkinter which have entry box and search button. What is want is when i maximize window search bar also starch but it is not happening,
Here is my code
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry("500x500")
root.title("Wikipedia")
class first:
def labels(self):
search_frame = ttk.LabelFrame(root)
search_frame.pack(side = "top",fill = "both")
search_var = tk.StringVar()
search_bar = tk.Entry(search_frame,width = 40,textvariable = search_var)
search_bar.grid(row = 0,column = 0)
search_button = ttk.Button(search_frame,text = "Search")
search_button.grid(row = 1,column = 0)
boot = first()
boot.labels()
root.mainloop()
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry("500x500")
root.title("Wikipedia")
class first:
def labels(self):
search_frame = ttk.LabelFrame(root)
search_frame.pack(side="top", fill="both")
search_var = tk.StringVar()
search_bar = tk.Entry(search_frame, width=20, textvariable=search_var)
search_bar.pack(fill="x")
search_button = ttk.Button(search_frame, text="Search")
search_button.pack()
boot = first()
boot.labels()
root.mainloop()
Not sure this is what you're looking for but try it out.
Here I have used fill='x' in the .pack() geometry manager to fill the row

Getting variable out of Tkinter

I would like to ask if anyone knows how to get out a variable from an Entry in Tkinter to be used in future calculation.
Let us assume that I want to create a prompt where the user needs to place two numbers in the two different Entry widgets.
These numbers are to be used in another script for calculation. How can I retrieve the values from the prompt created in Tkinter?
In my opinion, I would need to create a function with the code bellow and make it return the value from the Tkinter prompt. However, I cannot return the numbers because I'm destroying the root window. How can I get pass this, preferably without global variables.
Best Regards
from tkinter import *
from tkinter import ttk
#Start of window
root=Tk()
#title of the window
root.title('Title of the window')
def get_values():
values=[(),(value2.get())]
return values
# Creates a main frame on the window with the master being the root window
mainframe=ttk.Frame(root, width=500, height=300,borderwidth=5, relief="sunken")
mainframe.grid(sticky=(N, S, E, W))
###############################################################################
#
#
# Label of the first value
label1=ttk.Label(master=mainframe, text='First Value')
label1.grid(column=0,row=0)
# Label of the second value
label2=ttk.Label(master=mainframe, text='Second Value')
label2.grid(column=0,row=1)
###############################################################################
#
#
# Entry of the first value
strvar1 = StringVar()
value1 = ttk.Entry(mainframe, textvariable=strvar1)
value1.grid(column=1,row=0)
# Entry of the second value
strvar2 = StringVar()
value2 = ttk.Entry(mainframe, textvariable=strvar2)
value2.grid(column=1,row=1)
# Creates a simplle button widget on the mainframe
button1 = ttk.Button(mainframe, text='Collect', command=get_values)
button1.grid(column=2,row=1)
# Creates a simplle button widget on the mainframe
button2 = ttk.Button(mainframe, text='Exit', command=root.destroy)
button2.grid(column=2,row=2)
root.mainloop()
You use a class because the class instance and it's variables remain after tkinter exits.https://www.tutorialspoint.com/python/python_classes_objects.htm And you may want to reexamine some of your documentation requirements, i.e. when the statement is
"root.title('Title of the window')", adding the explanation "#title of the window" is just a waste of your time..
""" A simplified example
"""
import sys
if 3 == sys.version_info[0]: ## 3.X is default if dual system
import tkinter as tk ## Python 3.x
else:
import Tkinter as tk ## Python 2.x
class GetEntry():
def __init__(self, master):
self.master=master
self.entry_contents=None
self.e = tk.Entry(master)
self.e.grid(row=0, column=0)
self.e.focus_set()
tk.Button(master, text="get", width=10, bg="yellow",
command=self.callback).grid(row=10, column=0)
def callback(self):
""" get the contents of the Entry and exit
"""
self.entry_contents=self.e.get()
self.master.quit()
master = tk.Tk()
GE=GetEntry(master)
master.mainloop()
print("\n***** after tkinter exits, entered =", GE.entry_contents)
So, I have taken Curly Joe's example and made a function with the his sketch
The final result, for anyone wanting to use this as a template for a input dialog box:
def input_dlg():
import tkinter as tk
from tkinter import ttk
class GetEntry():
def __init__(self, master):
self.master=master
self.master.title('Input Dialog Box')
self.entry_contents=None
## Set point entries
# First point
self.point1 = ttk.Entry(master)
self.point1.grid(row=0, column=1)
self.point1.focus_set()
# Second point
self.point2 = ttk.Entry(master)
self.point2.grid(row=1, column=1)
self.point2.focus_set()
# labels
ttk.Label(text='First Point').grid(row=0, column=0)
ttk.Label(text='Second Point').grid(row=1, column=0)
ttk.Button(master, text="Done", width=10,command=self.callback).grid(row=5, column=2)
def callback(self):
""" get the contents of the Entries and exit the prompt"""
self.entry_contents=[self.point1.get(),self.point2.get()]
self.master.destroy()
master = tk.Tk()
GetPoints=GetEntry(master)
master.mainloop()
Points=GetPoints.entry_contents
return list(Points)
In python, functions are objects, as in get_values is an object.
Objects can have attributes.
Using these two, and the knowledge that we can't really return from a button command, we can instead attach an attribute to an already global object and simply use that as the return value.
Example with button
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
def on_button_press(entry):
on_button_press.value = entry.get()
entry.quit()
def main():
root = tk.Tk()
entry = tk.Entry(root)
tk.Button(root, text="Get Value!", command=lambda e = entry : on_button_press(e)).pack()
entry.pack()
tk.mainloop()
return on_button_press.value
if __name__ == '__main__':
val = main()
print(val)
Minimalistic example
Similarly modules are also objects, if you want to avoid occupying global namespace extremely, you can attach a new attribute to the module you're using
See:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
if __name__ == '__main__':
tk.my_value = lambda: [setattr(tk, 'my_value', entry.get()), root.destroy()]
root = tk.Tk()
entry = tk.Entry(root)
root.protocol('WM_DELETE_WINDOW', tk.my_value)
entry.pack()
tk.mainloop()
print(tk.my_value)

Tkinter Image icon not working or aligning properly in a Labelframe

This question concerns Python's Tkinter.
I first produced this GUI, a simple two-column set of rows in a Labelframe, with an icon on the right:
The above behaviour was correct and expected, based on this following code:
import tkinter as tk
import tkinter.ttk as ttk
from PIL import Image, ImageTk
root = tk.Tk()
icon_colours_fp = r"D:\Dropbox\coding\python\experiments\icon_component.gif"
icon_col = tk.PhotoImage(file=icon_colours_fp)
# icon_col = ImageTk.PhotoImage(Image.open(icon_colours_fp))
tk.Label(root, text="Past").grid(row=0, column=0)
tk.Label(root, text="Today").grid(row=1, column=0)
tk.Label(root, text="Future").grid(row=2, column=0)
_b = ttk.Button(root, image=icon_col)
_b['image'] =icon_col
_b.grid(row=0, column=1)
root.mainloop()
I then re-wrote the code as a class, hoping to produce something similar within a Labelframe:
import tkinter as tk
import tkinter.ttk as ttk
from PIL import Image, ImageTk
class Options(tk.Frame):
def __init__(self, parent):
super().__init__()
main_labelframe = ttk.LabelFrame(parent, text="Test Labelframe")
main_labelframe.pack(fill=tk.BOTH, expand=1)
frame_1 = tk.Frame(main_labelframe)
frame_1_sep = ttk.Separator(main_labelframe, orient=tk.VERTICAL)
frame_2 = tk.Frame(main_labelframe)
frame_1.pack(side=tk.LEFT)
frame_1_sep.pack(side=tk.LEFT, fill=tk.BOTH)
frame_2.pack(side=tk.LEFT)
tk.Label(frame_1, text="Past").grid(row=0, column=0)
tk.Label(frame_1, text="Today").grid(row=1)
tk.Label(frame_1, text="Future").grid(row=2)
icon_colours_fp = r"D:\Dropbox\coding\python\experiments\icon_component.gif"
icon_col = tk.PhotoImage(file=icon_colours_fp)
_b = ttk.Button(frame_2, image=icon_col)
_b['image'] = icon_col
_b.grid(row=0, column=0)
class Gui(tk.Tk):
def __init__(self):
super().__init__()
options = Options(self)
options.pack()
gui = Gui()
gui.mainloop()
The code then failed, in two respects:
The icon fails to appear.
The ttk Button becomes misaligned. (It appears in the centre, whereas by the grid, it should appear at the top.)
The failed code appears as follows:
I have experimented: among others, I changed the geometry manager to .pack(), and changed the parent of ttk.Button, but without success. Would appreciate some pointers as to where I've gone wrong, especially as to the disappearing icon.
You didn't keep a reference to the image. Easiest way here is to change:
icon_col = tk.PhotoImage(file=icon_colours_fp)
b = ttk.Button(frame_2, image=icon_col)
_b['image'] = icon_col
To:
self.icon_col = tk.PhotoImage(file=icon_colours_fp)
b = ttk.Button(frame_2, image=self.icon_col)

Categories