How to write Treeview info for your application in tkinter (Python 3) - python-3.x

I am looking for a way to write information for my treeview in tkinter. I wrote this by using the set method but my sentences disappear when I write on the next line. I want my information for the teeeview to display when I move to the next line.
from tkinter import *
from tkinter import ttk
root =Tk()
tree = ttk.Treeview(root)
tree.insert("","0","item1",text="LANGUAGE")
tree.insert("","1","item2",text="GUI")
tree.insert("item1","1",text="Version")
tree.insert("item2","end",text="Tkinter")
tree.config(columns=("NOTE"))
tree.column("NOTE",width=300)
tree.heading("NOTE",text="Info")
tree.set("item1","NOTE","Am using python version 3.6.1 \n on windows machine
")
tree.set("item2","NOTE","This an example Tkinter Treeview in Python, which
is from \nttk class make sure import ttk\n also from tkinter import *")
tree.pack()
root.mainloop()
Are there any methods in treeview I can use to display this, because I want to write a lot of information for the treeview?

You need to increase the height of the rows so that all your text will be visible. The height of the rows can only be modified by using a style:
style = ttk.Style(root)
style.configure('my.Treeview', rowheight=50)
tree.configure(style='my.Treeview')
As far as I know, it is not possible to adjust the height of a single row.

Related

Defining TkInter StringVars in a loop

My program iterates through a list of values and creates a new frame with relevant information. I want to add a button to refresh the values in just one of the frames. The following image is a mockup of what I'm trying to achieve, where the "reload" button grabs new data for just one printer.
I'm running into an issue where only the last values get updated. The following code is an approximation of what I was trying:
import tkinter as tk
from tkinter import ttk
def buttonupdate(x):
return int(x.get())+1
root=tk.Tk()
values=[0,0,0,0,0,0,0]
stringVarList=[]
for i,item in enumerate(values):
newStringVar=tk.StringVar()
newStringVar.set(item)
stringVarList.append(newStringVar)
valueLabel=tk.Label(root, textvariable=stringVarList[i])
valueLabel.grid(row=0,column=i)
button=tk.Button(root, text="+1", command=lambda:stringVarList[i].set(buttonupdate(stringVarList[i])))
button.grid(row=1, column=i)
root.mainloop()
With this code, only the last value gets updated, no matter which button I press.
What can I try instead? Thank you.

Tkinter best button text flipping method

So I'm working on a tkinter project and one issue I come across is finding a way to flip/rotate a button object's text vertically. One way I can kinda cheat into making this happen is putting a canvas object on top of the button with the canvas being drawn last (as shown below) but is there a cleaner way to approach this by just manipulating the Button object attributes?
from tkinter import*
root = Tk()
windowDimensions = (1300,600)
root.title("Mapper")
root.geometry(str(windowDimensions[0])+"x"+str(windowDimensions[1]))
button1=Button(root,text='',width=2,height=9)
button1.place(x=0,y=20)
can = Canvas(root,width=15,height=80)
can.place(x=2,y=30)
can.create_text(0, 80, anchor="nw", angle=90,text='hello',font=("Purisa", 12))
root.mainloop()
Edit: A problem I get with doing it this way is any place where the canvas is on the button, it obstructs the ability to click where the canvas is.
Your best option (which isn't a great option) is to screenshot the button, rotate it in an image editor, and then use that image in your button instead of text.
from tkinter import*
root = Tk()
# .gif file encoded as base64
vert_button_data = '''
R0lGODlhDQBCAKUkAAAAAAAANgAAYDYAADYANjYAYGAAAGAANmAAYAA2hzY2h4c2AGA2h4c2NgBg
qzZghzZgq2BgNqtgAKtgNjaHhzaHzmCHh6uHNs6HNmCr8PCrYIfOq4fO8PDOh6vwq6vw8M7w8PDw
q/DwzvDw8P//////////////////////////////////////////////////////////////////
/////////////////////////////////////////////ywAAAAADQBCAAAG/sCRcEgsGo+cpFJJ
PDgPAWeUGKpSMFUM5Qggdo2DDAiU+RY7BoXCoDmOQp1OqLisN5/4A7XqqfqPAm5EERVLRwcGeEd+
f0gZGR9uGQQSEgUcXB1CHQFcXkdhHx8ZA0doBQUGmotxc0QOhZFuGhgNCLAcskUiIbQNAg5HHxwV
DwYSRMQQCBMYckUHAxYbIG5wtQwOGRzVRrwaFwEJRiAcGQ4KCxhE5woNEhodIkXw8oL3+Pn35pCS
lJaYjABYxcnTEDNEQo0qZeRUqlVG4DxLVofJkDyKhjDaSLFiQCEYn+zZWEVYhWAjUBYRoOELwoMj
XILiAOBDBYZnoj201oqOIMePI/BEEanRDwBGbl4avKdUyBIAhi4+SURUCMlG+oIAADs=
'''
windowDimensions = (1300,600)
root.title("Mapper")
root.geometry("{}x{}".format(*windowDimensions))
button1_image = PhotoImage(data=vert_button_data)
button1=Button(root,image=button1_image)
button1.place(x=0,y=20)
root.mainloop()
You'll lose the hover animation but again that's something you can recreate with images.
To get the base64 encoded data from a .gif you can use this:
import codecs
with open('export.gif', 'rb') as f:
print(codecs.encode(f.read(), 'base64').decode())

Im having trouble trying to time the update of a tkinter label image

I am trying to make a basic 4 frame animation, I cannot use a tkinter canvas as I want it to use the art which I have drawn (the files). There is nothing wrong with the file type as I have tested it on its own. However the code seems to just remove the window for the 6 seconds and then show the final frame.
import time
import tkinter
window=tkinter.Tk()
frame1=tkinter.PhotoImage(file="file1.ppm")
frame2=tkinter.PhotoImage(file="file2.ppm")
frame3=tkinter.PhotoImage(file="file3.ppm")
frame4=tkinter.PhotoImage(file="file4.ppm")
image=tkinter.Label(window,image=frame1)
image.pack()
time.sleep(2)
image.configure(image=frame2)
time.sleep(2)
image.configure(image=frame3)
time.sleep(2)
image.configure(image=frame4)
I'm not sure whether it is the "time.sleep" or the "image.configure" that is the problem but I have tried to mess around with different types of timing methods which also seem to fail.
import tkinter
window=tkinter.Tk()
frame1=tkinter.PhotoImage(file="file1.ppm")
frame2=tkinter.PhotoImage(file="file2.ppm")
frame3=tkinter.PhotoImage(file="file3.ppm")
frame4=tkinter.PhotoImage(file="file4.ppm")
image=tkinter.Label(window,image=frame1)
image.pack()
def loop(n):
frame = [frame1, frame2, frame3, frame4][n]
window.after(2000, lambda : image.configure(image=frame))
window.after(2000, lambda : loop((n+1)%4))
loop(1)

Application freezes after use of pandas and matplotlib modules

I wrote a script in python 3.4 where I'm making use of the tkinter module to build the GUI and pandas/matplotlib to visualise some data. The visualisation is being produced in a new window through the use of a button in the main window. The problem is that when I close the window that contains the graph (produced by pandas/matplot) the main window widgets are completely unresponsive. Furthermore, when I try to close the main window (through the 'X' button) I get a Fatal Python error: PyEval_RestoreThread: NULL tstate, which I don't get if I close the window without producing the graphs.
In simple words: the rest of the application behaves as it should if I never produce the graphs and becomes completely unresponsive if I do.
Below are the code segments of the caller of the plotting method in the main window and the method itself where the use of pandas and matplot is clearly shown.
Caller:
button_view_browsers = tk.Button(window, text="Display graph", command=lambda: self.threaded_browser_hist(doc))
button_view_browsers.grid(row=2, column=1, sticky=W+E+N+S, columnspan=3)
Visualisation method:
def display_browser_hist(self, data):
ser = Series(data.viewer_browser())
ser.value_counts().plot(kind='bar')
matplotlib.pyplot.show()
def threaded_browser_hist(self, doc):
Thread(target=self.display_browser_hist(doc)).start()
Any help would be greatly appreciated.
EDIT: Just to be sure I'm also including the modules I'm using and how I'm importing them:
from pandas import Series
import matplotlib
import tkinter as tk
from tkinter import W, E, N, S

How to set the background color of a ttk.Combobox

I have a problem to set background color for Combobox using tkinter ttk with 'vista' theme (I'm using Python 3). I've tried code from here ttk.Combobox glitch when state is read-only and out of focus
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
combo = ttk.Combobox(root, values=['1', '2', '3'])
combo['state'] = 'readonly'
combo.pack()
tk.Entry(root).pack()
style = ttk.Style()
style.map('TCombobox', selectbackground=[('readonly', 'red')])
#style.map('TCombobox', fieldbackground=[('readonly', 'blue')]) #not working as well
But this will change only background for text, rest part of combobox rests white. Also I saw a post on the tcl forum: http://wiki.tcl.tk/15780 and I've tried with 'fieldbackground' but it seems that tkinter ignores this parameter. Do you have any idea how to solve it? Maybe there is a way to configure only specific style in specific theme? I saw that for 'default' theme, the background changes to gray color if state is 'readonly'.
Apparently, the order you set the properties of the new style is important to determine if a certain property of the new style will be applied or not. For example, if I set first the background instead of selectbackground, then the color of selection will not be changed, but just the mini button color with the arrow (to list down the options).
I noted also that depending on the value of parent, which I suppose is the parent style from which the new style is derived, some of the new settings and properties of the new style might not be applied. For example, if I try to change the fieldbackground property when parent is set to aqua, it does not work, but if parent is set to alt, it works. (I hope more expert users can help and contribute to improve this answer, which could be helpful also for future users of ttk and tkinter).
This is my solution, where I created a complete new style:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
combostyle = ttk.Style()
combostyle.theme_create('combostyle', parent='alt',
settings = {'TCombobox':
{'configure':
{'selectbackground': 'blue',
'fieldbackground': 'red',
'background': 'green'
}}}
)
# ATTENTION: this applies the new style 'combostyle' to all ttk.Combobox
combostyle.theme_use('combostyle')
# show the current styles
# print(combostyle.theme_names())
combo = ttk.Combobox(root, values=['1', '2', '3'])
combo['state'] = 'readonly'
combo.pack()
entry = tk.Entry(root)
entry.pack()
root.mainloop()
Since I am not an expert on ttk, I was not able to apply a new theme just to a certain instance of type ttk.Combobox, but I applied the theme to all instances of future possible ttk.Combobox. If someone can improve this answer, I would really appreciate the gesture!
For more information on how to create and set new styles, see here or here.
This code below worked fine for me.It is important set the order of the parameters.
style = ttk.Style()
style.map('TCombobox', fieldbackground=[('readonly','white')])
style.map('TCombobox', selectbackground=[('readonly', 'white')])
style.map('TCombobox', selectforeground=[('readonly', 'black')])
self.mycombo = ttk.Combobox(self.frame,textvariable=self.combo_var,
height=15,justify='left',width=21,
values=lista)
self.mycombo['state'] = 'readonly' # Set the state according to configure colors
self.mycombo.bind('<<ComboboxSelected>>',
lambda event: self._click_combo())
If you just want to change the color without regard to the state of the widget (ie. hover, pressed, etc...), then you will want to use the configure method instead of the map method, as the map method is meant specifically for applying various formats to specific widget states. Since you are only using the "readonly" state, I assume this is what you want.
style.configure('TCombobox', fieldbackground='red')

Resources