Python Tkinter: How to decrease tab space in Treeview - python

So I have the following code that creates the GUI in the picture below:
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
# Some code
# Creating Master TreeView
treeView = ttk.Treeview(root)
treeView.heading("#0", text="Variables", anchor=tk.W)
treeView.place(relx=0, rely=0.00,relwidth=0.1,relheight=1)
# Some Code
# Creating Folders/Sub Folders
var = treeView.insert("", 0, text=name)
treeView.insert(var, "end", text="Type: "+type)
treeView.insert(var, "end", text="Value: "+str(value))
This is what It looks like without being pressed and then pressed
Is there anyway to decrease the tabspace of the sub folders? Like bring it back to where the black point is?
For context, this is what the whole gui looks like:
I have to reserve so much space for the Treeview just to make sure the subfolders appear on the screean, and it takes up way to much space. I tend to find that the treeview uses a lot of unnecessary space when adding subfolders

You can try and constain the tree column:
treeView.column('#0', width=your_width, stretch=False)

Related

Conceptual question (and optimization) of creating a bunch of buttons in Tkinter

I am making a personal project using Tkintr to create an interactive Periodic Table of Elements. Instead of making each Button for each element individually, I used the following code to create a bunch of buttons (beginner coder so sorry for formatting, etc):
from tkinter import *
from tkinter import messagebox
import pandas as pd
raw_csv = pd.read_csv('data/elements.csv')
el_symbols = {row.Number: row.Symbol for (index, row) in raw_csv.iterrows()}
img_ref_dict = {f'{sym}_img': f'images/{num}.png' for num, sym in el_symbols.items()}
window = Tk()
window.title("Periodic Table of Elements")
window.config(width=1202, height=676)
# All da buttons
# Creating population for button assignment
for name, path in img_ref_dict.items():
exec(f'{name} = PhotoImage(file="{path}")')
exec(f'{name}_button = Button(image={name}, highlightthickness=0, command=lambda: popup())')
window.mainloop()
To my understanding, the code contained within .mainloop() is continuously looping so is my for loop creating the buttons repeatedly? Would it be better to just create each button one by one? This method is just so much cleaner to me.
As per #acw1668's advice, you're on the right track but are better off doing something like:
for path in img_ref_dict.values(): # you don't really need 'name'
img = PhotoImage(file=path)
btn = Button(image=img, highlightthickness=0, command=lambda: popup())
btn.pack() # add the button to the UI (you'll probably want to tweak this a bit)
Minor Edit to say that unless you really need the name for each button image, you could tweak img_ref_dict to create a list of image paths instead, like so:
img_refs = [f'images/{num}.png' for num in el_symbols.keys()]
...and then modify the for loop slightly:
for path in img_refs:
# yadda yadda

How do you make Tkinter GUI output text from print statement?

I am trying to get my code to display text from a print statement onto the Tkinter GUI - does anyone know how to do this?
Use this:
import tkinter as tk
# This function acts just like the `print` function:
def print_on_gui(*args, sep=" ", end="\n"):
text = sep.join(args) + end
# Set the Text widget's state to normal so that we can edit its text
text_widget.config(state="normal")
# Insert the text at the end
text_widget.insert("end", text)
# Set the Text widget's state to disabled to disallow the user changing the text
text_widget.config(state="disabled")
# Create a new tkinter window
root = tk.Tk()
# Create a new `Text` widget
text_widget = tk.Text(root, state="disabled")
# Show the widget on the screen
text_widget.pack(fill="both", expand=True)
# Your code should go here
print_on_gui("Hello world!")
print_on_gui("Hello", "world!")
# Go inside tkinter's mainloop
root.mainloop()
The problem with this approach is that if your program runs for too long, it can make the window unresponsive. To avoid that you can use threading but that will complicate things a lot more. If you want to, I can write a solution that uses threading.

How to remove indent left on the widget Tkinter Treeview?

Can I somehow remove this indentation? I know that I can remove the first column, but then I can not insert the image.
import tkinter as tk
import tkinter.ttk as ttk
from PIL import Image, ImageTk
class App:
def __init__(self, master):
self.tree = ttk.Treeview(master)
self.tree.heading('#0', text='Directory', anchor='w')
self.tree["columns"]=("num_files")
self.tree.heading('num_files', text='Number of files', anchor='w')
self.image_tk = ImageTk.PhotoImage(Image.open('icon.png'))
for i in range(10):
self.tree.insert('', 'end', text="Dir %d" % (i+1), values=(15), open=False, image=self.image_tk)
self.tree.pack(expand=1,fill="both")
root = tk.Tk()
app = App(root)
root.mainloop()
Assuming the indentation you're referring to is the left side of the first column (left of all the icons), you can adjust the entire widget padding as needed. For your application, start with:
self.tree = ttk.Treeview(master, padding=[-15,0,0,0])
What you have highlighted in red is the area in which the Treeview's indicator resides -- the open or close toggle icon -- that is shown if any of the Item objects contain subitems of their own.
One way to accomplish removing that area would be to just remove the indicator altogether while using a ttk theme that allows you to do so.
s = ttk.Style()
s.theme_use('default')
s.configure('Treeview.Item', indicatorsize=0)
This approach seems to only work for the default, clam and classic themes on Windows 10. For other themes, Ron's answer may be your best bet.

Tkinter Python listbox

I am a new python user. I'm used to programing on matlab.
I've trying to make a simple GUI with Tkinter pack, but I'm having some problems with that. I had already read and searched what i want but I couldn't develop it.
What I'm trying to do is to make a listbox and when I choose one (or more) options the index be returned (and stored) as a variable (array or vector) that could be used to indexing another array.
The best result I got was a listbox where the index were printed, but not stored as a variable (at least it hasn't been shows in the variables list)
I'm using spyder (anaconda).
I tryied a lot of codes and I don't have this anymore.
Sorry for the dumb question. I guess I still thinking in a Matlab way to write
To keep this application simple, your best option is to get the listbox selection when you want to do something with it:
from tkinter import Tk, Listbox, MULTIPLE, END, Button
def doStuff():
selected = lb.curselection()
if selected: # only do stuff if user made a selection
print(selected)
for index in selected:
print(lb.get(index)) # how you get the value of the selection from a listbox
def clear(lb):
lb.select_clear(0, END) # unselect all
root = Tk()
lb = Listbox(root, selectmode=MULTIPLE) # create Listbox
for n in range(5): lb.insert(END, n) # put nums 0-4 in listbox
lb.pack() # put listbox on window
# notice no parentheses on the function name doStuff
doStuffBtn = Button(root, text='Do Stuff', command=doStuff)
doStuffBtn.pack()
# if you need to add parameters to a function call in the button, use lambda like this
clearBtn = Button(root, text='Clear', command=lambda: clear(lb))
clearBtn.pack()
root.mainloop()
I've also added a button to clear the listbox selection because you cannot unselect items by default.
First, import tkinter, then, create the listbox. Then, you can use curselection to get the contents of the listbox.
import tkinter as tk
root = tk.Tk() #creates the window
myListbox = tk.Listbox(root, select=multiple) #allows you to select multiple things
contentsOfMyListbox = myListbox.curselection(myListbox) #stores selected stuff in tuple
See the documentation here.

Randomly add buttons to Tkinter GUI?

How do I randomly add buttons to a Tkinter GUI? I need it to be able to create a button, then put it anywhere on the window, is this possible? I am using Python 2.6 on Windows.
If you want random button placement (or anything not aligned along a grid, etc.), you can use the place geometry manager. Depending on platform, overlapped buttons may not behave as you expect, though, so you may want to avoid them.
Here's a simple example:
from Tkinter import *
from random import random
root = Tk()
frame = Frame(root, height=200, width=200)
for i in range(10):
Button(frame, text=str(i)).place(x=random() * 150, y=random() * 180)
frame.pack()
root.mainloop()
There are several options to choose from. For example, you could design on a grid where you have six buttons per row. Then it's just a matter of starting at row 0, incrementing the column for each button. When you get to the last column, reset the column to 0 and increment the row by one.
Another option is to use a text widget as the container, and embed your buttons in the text widget with wrapping enabled. With this trick the buttons will fill a row automatically and wrap if the user grows or shrinks the main windows. It's a tiny bit more work, but it works well if that's the behavior you want.

Categories

Resources