I am trying to create a GUI for a small application I have written in Python 3.10 using Tkinter package. I want to have a single window open with buttons, entry fields, labels and a data table at the bottom that is updated from a database I have created.
I have created the table, and imported it into the frame which is set up into the grid system I have set up for the buttons, as shown in the code below.
What I can't figure out, is how to shrink the pandastable or manipulate it in anyway once it's in the root window? I have tried changing the font, fontsize, and column attributes using the core functions in pandastable on my table variable (.autoResizeColumns(), .setFont(), .zoomOut() and more) but nothing seems to have an effect.
Here is a picture of my current GUI.
I would like for the entire table to be displayed without the horizontal scrollbar, slightly smaller with decreased font size - so it's similar to the top portion of the table.
Am I doing something wrong? Is there something in pandastable I can call to achieve this?
from tkinter import *
from tkinter import ttk
import pandastable as pt
# Tk
root = Tk()
root.resizable(False, False)
#Create GUI
api_entry_btn = Button(root, text = "Add API ", command = lambda: db.get_token(embed = False))
api_entry_btn.grid(row = 0, column = 0, columnspan= 1, sticky='nesw')
api_del_btn = Button(root, text = "Remove API", command = lambda: db.check_del_token())
api_del_btn.grid(row = 1, column = 0, columnspan= 1, sticky='nesw')
scan_now_btn = Button(root, text = "Scan Now", command = db.scan_now)
scan_now_btn.grid(row = 0, column = 1, columnspan= 1, sticky='nesw')
id_list_btn = Button(root, text = "Show ID list", command = db.fetch_id_info)
id_list_btn.grid(row = 1, column = 1, columnspan= 1, sticky='nesw')
id_entry = Entry(root, width = 40,borderwidth=3)
id_entry.grid(row = 0, column = 2, sticky="ns", padx = (3,0))
add_id_btn = Button(root, text = "Add ID", command = lambda: add_id(id_entry.get()))
add_id_btn.grid(row = 0, column = 3, sticky='nesw')
id_del = Entry(root, width = 40,borderwidth=3)
id_del.grid(row = 1, column = 2, sticky="ns", padx = (3,0))
del_id_btn = Button(root, text = "Delete ID", command = lambda: db.remove_id(id_del.get()))
del_id_btn.grid(row = 1, column = 3, sticky='nesw')
frame = Frame(root, width = 150)
frame.grid(row = 3, column = 0, columnspan= 4, sticky = 'nesw')
table = pt.Table(frame, dataframe= db.synth_pandastable())
table.show()
root.mainloop()
Thanks in advance for any help.
Note, I have left out a bit of my code to keep it shorter.
Related
I have created two check buttons and I want them both in row 5 and column 1. But I want the 'YES' check button to be formatted on the left side and the 'NO' check button to be on the right.
I have used sticky but it will not work. I also tried changing the width of the check buttons but this did not work either.
Do you have any suggestions?
Thank you!
self.yes_checkbtn = Checkbutton(self.entry_frame, width = 20, variable = checkbutton1,
anchor = W, text = "YES")
self.no_checkbtn = Checkbutton(self.entry_frame, width = 20, variable = checkbutton2,
anchor = E, text = "NO")
self.yes_checkbtn.grid(row = 5, column = 1, sticky = W)
self.no_checkbtn.grid(row = 5, column = 1, sticky = E)
Outcome:
I dont have enough points yet to show the image without a link - sorry
Put both check buttons under another new frame, then you can grid this new frame to column 1 of row 5, also change option width of Checkbutton to a small number, like 5.
Example code
from tkinter import *
root = Tk()
entry_frame = Frame(root)
entry_frame.grid(row=0, column=0)
for i in range(4):
for j in range(2):
label = Label(entry_frame, text=f'Row {i} Column {j}')
label.grid(row=i, column=j)
frame = Frame(entry_frame)
frame.grid(row=4, column=1)
checkbutton1 = BooleanVar()
checkbutton2 = BooleanVar()
yes_checkbtn = Checkbutton(frame, width = 5, variable = checkbutton1,
anchor = W, text = "YES", bg='green')
no_checkbtn = Checkbutton(frame, width = 5, variable = checkbutton2,
anchor = E, text = "NO", bg='blue')
yes_checkbtn.grid(row = 0, column = 1, sticky = W)
no_checkbtn.grid(row = 0, column = 2, sticky = W)
root.mainloop()
I'm designing an app in tkinter, but there is a button that won't show up. The button is crucial to the program's operation.
import tkinter as tk
global field
root = tk.Tk()
root.resizable(0,0)
root.geometry('368x200')
header = tk.Label(root, text = 'Header Text', pady=20)
header.config(font = ('Tahoma', 24))
header.grid(row = 0, columnspan=2)
enter_here = tk.Label(root, text = 'Question: ')
enter_here.grid(row = 1, column = 0, pady = 50)
field = tk.Entry(root, width = 50)
field.grid(row = 1, column = 1, pady = 50)
answer = tk.Button(root, text = 'Answer', command = answerf, width=10)
answer.grid(row=2, column=2)
root.mainloop()
Title, header text and the letters are all placeholders. I just need to figure out how to use the button. I've looked around and couldn't find any answers; most people had just forgot a geometry manager.
You have to be careful what values you are passing to various parameters of tkinter widgets. In above case, this is the reason why you are not able to see button.
Change
field = tk.Entry(root, width = 50)
field.grid(row = 1, column = 1, pady = 50)
to
field = tk.Entry(root, width = 25)
field.grid(row = 1, column = 1, pady = 30)
And,
answer = tk.Button(root, text = 'Answer', command = answerf, width=10)
answer.grid(row=2, column=2)
to
answer = tk.Button(root, text = 'Answer', command = answerf, width=10)
answer.grid(row=1, column=2)
output:
The problem is simply that you're forcing the window to be a size that is too small for the objects inside it.
A simple fix is to remove this line:
root.geometry('368x200')
If you insist on keeping this line, then you need to adjust the parameters of the other widgets so that they fit in the constrained space. For example, you could reduce the size of the widgets or reduce the padding.
I am new with Python GUI creation and I am trying to get the file path of the .csv file from a directory and print it on a text box in a GUI. I am using tkinter library for the GUI and I can't seem to make it work. Is there anyone who can help me with this problem?
import tkinter as tk
from tkinter.filedialog import askopenfilename
def browseFile1():
global infile1
infile1=askopenfilename()
txt1.insert(0.0, infile1)
root = tk.Tk()
root.title("CSV Comparison Tool")
Label = tk.Label(root, text="Select CSV files to compare").grid(row = 1, column = 0, columnspan = 30)
browseButton1 = tk.Button(root,text="Browse", command=browseFile1).grid(row = 2, column = 30)
txt1 = tk.Text(root, width = 100, height = 1).grid(row = 2, column = 0, columnspan = 30)
root.mainloop()
The error says:
AttributeError: 'NoneType' object has no attribute 'insert'
I tried 1 button first and applying it on the next one it it works. I am using spyder as a tool.
Thanks!
Your problem is these lines:
Label = tk.Label(root, text="Select CSV files to compare").grid(row = 1, column = 0, columnspan = 30)
browseButton1 = tk.Button(root,text="Browse", command=browseFile1).grid(row = 2, column = 30)
txt1 = tk.Text(root, width = 100, height = 1).grid(row = 2, column = 0, columnspan = 30)
The grid method on a widget—like most methods that mutate objects in Python—returns None. So you're just storing None in Label, and browseButton1, and txt1. So when you later try this:
txt1.insert(0.0, infile1)
That's trying to call None.insert, which obviously doesn't work. Tkinter catches the error, prints it out to the terminal, and keeps going as if your function had never been called.
The solution is to just not do that. Instead, do this:
Label = tk.Label(root, text="Select CSV files to compare")
Label.grid(row = 1, column = 0, columnspan = 30)
browseButton1 = tk.Button(root,text="Browse", command=browseFile1)
browseButton1.grid(row = 2, column = 30)
txt1 = tk.Text(root, width = 100, height = 1)
txt1.grid(row = 2, column = 0, columnspan = 30)
Now, not only does your code work, it even fits in a typical editor window or Stack Overflow page.
So I have 2 rows dedicated to a messaged label widget to display any successful/unsuccessful messages to the user while they're using the tkinter GUI.
Some of the messages are to long to fit within the column width, so I have used the wraplength feature for the Label widget to wrap the text to the next line.
The issue that I'm having, is that because of this feature, it shifts the placements of the widgets underneath this widget, by 1 row for every new row it wraps the text onto.
So I was wondering if there's any way to have the text wrap, without moving the lower widgets.
How the message Label looks within the GUI with height = 1:
How the message Label looks when it wrap's the text to a newline with height = 1:
How the message Label looks within the GUI with height = 2:
How the message Label looks when it wrap's the text to a newline with height = 1:
I would like for the message Label in the 2nd image link to display the way it does, but keeping the vertical layout of the widgets as seen in the 1st image link.
The following code is for defining the widgets:
Choice_list = Listbox(window, selectmode=SINGLE, width = 17, height = 9,
justify = CENTER)
image = PhotoImage(file = 'Dummy_Logo.gif')
Image_label = Label(window, image = image)
extract = Button(window, text = "Archive News from Webpage",
command = func1, width = 20)
archive = Button(window, text = "Extract News from Archive",
command = func2, width = 22)
display = Button(window, text = "Display the News",
command = func3, width = 14)
Message_Widget = Label(window, text = '', fg = 'black', justify = CENTER,
height = 2, wraplength = 300)
Log_Event = Checkbutton(window, text = 'Log Event', variable = logState,
command = logEvent)
The following code is the grid alignment for the widgets:
Image_label.grid(row = 1, column = 1)
Choice_list.grid(row = 1, column = 2, rowspan = 9, sticky = W)
Message_Widget.grid(row = 2, column = 1, rowspan = 2)
Log_Event.grid(row = 12, column = 2)
archive.grid(row = 13, column = 1, rowspan = 2, sticky = W)
extract.grid(row = 13, column = 1, rowspan = 2, sticky = E)
display.grid(row = 13, column = 2, rowspan = 2, sticky = W)
Give the label a height of 2 or 3. The problem is simply that it wants to be one character tall by default. Tkinter will allocate only one character worth of height when laying out all the widgets. When the text wraps, the label simply must become taller so that the text will fit.
By giving it a height of 2 or 3 to start out, that extra space is built-in to the GUI. When the text wraps, the label doesn't have to grow to accommodate the new text.
This might not be a proper method of solving this problem, however I have managed to get the outcome I was looking for by only adjusting the rowspan parameter in the Message_Widget to rowspan = 11.
Message_Widget.grid(row = 2, column = 1, rowspan = 11)
This produced the following results:
With a short text:
https://i.stack.imgur.com/XpGLq.png
With a long text:
https://i.stack.imgur.com/iXwlR.png
Have you considered using a text widget for the readout?
For example this below code will wrap the text if it is to long and it will not resize the widgets. This is just an example but should be enough to help you with you problem.
from tkinter import *
import random
root = Tk()
text1 = Text(root, height=1, width=40, wrap="word")
text1.grid(row=0, column=0, sticky="ew")
def update_lbl1():
x = ["Click and drag to see some much longer random text for updating label!!!","some short data"]
text1.delete("1.0", "end")
text1.insert("1.0", random.choice(x))
Button(root, text="Change label from list", command = update_lbl1).grid(row=1, column=0)
root.mainloop()
I have the following code:
from Tkinter import *
master = Tk()
center(master, 300, 200)
#Label(text = 'Clients').grid(row = 0, column = 1)
lb = Listbox(master, selectmode = BROWSE)
sb = Scrollbar(master)
sb.grid(row = 0, column = 0, sticky =NS, rowspan = 1)
lb.grid(row = 0, column = 1)
sb['command'] = lb.yview
lb['yscrollcommand'] = sb.set
Label(master, text = "AAAAA").grid(row = 0, column = 2)
Label(master, text = "BBBBB").grid(row = 1, column = 3)
mainloop()
Which creates this window:
I know I can use sticky = N to make AAAAA cling to the top of the cell and be at the top of the window.
But my question is: How do I make it so that I can put multiple labels next to my listbox widget in a sort of grid of their own? Can I use .grid for this? Or do I have to use .place?
Or am I going about this entirely wrong?