I'm currently trying to print a table of data gathered from a database onto a GUI in tkinter, at the moment I'm using tabulate which runs fine in console, but as soon as I try to set the table as text as print as a label the table skews and the values are not aligned. I am still new to tkinter and so my code is by far not the most efficient or effective, any ideas on why this is happening or a way around?
order = (key_1,name_1,price_1,quantity_1,total_1)
table.append(order)
count +=1
print_table = (tabulate(table,headers=headers,tablefmt= "rst"))
c.fetchall()
conn.commit()
conn.close()
label_table = tk.Label(self,text=print_table)
label_table.pack()
Expected Result:
!file:///var/folders/59/89rdtwpd4vnf6pv7pbd3l60m0000gn/T/com.apple.Safari/WebKitDropDestination-rwh55dGn/Screen%20Shot%202019-02-03%20at%2011.49.29%20PM.png
Actual Result:
!file:///var/folders/59/89rdtwpd4vnf6pv7pbd3l60m0000gn/T/com.apple.Safari/WebKitDropDestination-tZziKT9D/Screen%20Shot%202019-02-03%20at%2011.47.15%20PM.png
https://i.stack.imgur.com/bgG4C.png
I would highly recommend creating a grid of tk.Entry widgets where you place your headers and values in discrete entries. If you recorded the tk.Entry widget objects in a list you would be able to call on them individually outside of the loop if you preferred that. You could substitute the tk.Label widget in the place of tk.Entry with other formatting changes if you were partial to the Label widget.
tableWindow=tk.Toplevel()
tableHeaderList=["Header1","Header2","Header3","Header4"]
for i in range(height): #Rows
for j in range(width): #Columns
b = tk.Entry(tableWindow, text="")
b.grid(row=i, column=j)
if i == 0:
b.insert(0,tableHeaderList[j])
I suggest you to use a monospaced font. I face the same problem and use
Cascadia Mono font and it worked. use the parameter font=("Cascadia Mono", 10) in the label. Hope it helps.
Related
I have created a window using tkinter, this window contains a grid of Labels and Entries. In the Entries I have edited some text that I want to save back to the source.
Everything I'm reading so far says that I need to create a separate list and save each entry text variable in the list.
But isn't there a better way to get the values directly from the controls themselves? I know I can loop over mywindow.winfo_children or mywindow.children. So if I can do this, then I should be able to get the text values directly, no?
I just don't know which property to get the value from.
Any ideas out there?
This is the answer.
for child in context.grid_slaves():
if(type(child) is label):
print (child['text'])
if(type(child) is entry):
print(child.get())
I can also find out where I am in the grid like this: child.grid_info() and so I can synch back to the source.
Just to elaborate on the answer.
Loop through the window grid items using the grid_slaves method.
Get the row and column using the widget's grid_info method:
for child in window.grid_slaves():
g_info = child.grid_info()
if type(child) is Button:
row = g_info['row']
col = g_info['column']
text = child['text']
print(row, col, text)
I have to write a program for some coursework I'm doing, and I chose to do an A-Level revision game to help others. I'm trying to get use a ttk separator to split up the area of the window where the game part occurs, and the area of the window where the question sits. My window is split up into 3 frames; one with 4 labels in, one with 4 buttons in and one with a ttk.Separator widget and a label. I cannot get the separator however to span the whole window.
I've been looking around and testing things, but nothing seems to work. I've looked at these two previous posts in terms of on this website:
ttk.Separator set the length/width
A Label in a Frame in a window won't stretch, why?
but neither of these solutions seemed to fix my problem, and I'm now out of ideas. Any help would be greatly appreciated.
main_revision_game_question_frame = Frame(parent_window, bg='#c2f0f0')
main_revision_game_question_frame.pack()
main_revision_game_question_frame.grid_propagate(1)
main_revision_game_question_frame.config(width=screen_width, height=40)
separator = ttk.Separator(main_revision_game_question_frame, orient=HORIZONTAL)
separator.grid(column=0, row=0, sticky='ew')
question_label = Label(main_revision_game_question_frame,
text=' Placeholder text for a question goes here!
\n######################################################',
bg='#c2f0f0', fg='#ff2824', font='"Open Sans" 26 bold')
question_label.grid(column=0, row=1, sticky='ew')
main_revision_game_question_frame.grid_columnconfigure(0,weight=1)
main_revision_game_question_frame.grid_rowconfigure(0, weight=1)
This is the code I've ended up with upon trying to combine a few solutions, and this is how it looks:
You can see the separator is there, but it does not stretch across the frame. Thank you for reading.
The separator is expanding to fill the frame, but the frame hasn't been configured to fill the space it has been given.
You need to expand the frame. One way to do that is to use the fill option of pack:
main_revision_game_question_frame.pack(fill="x")
Try to use
main_revision_game_question_frame.pack(fill="both")
so the frame fills the whole space it is given
I want to create an interactive text box in a tkinter GUI, the text box should get the text to wrap to the next line after the length of 30 characters, like it would do using the wraplength=30 attribute in a label widget. I am trying to get it to work using an Entry widget, this is what I am aiming for (apart from the wraplength attribute needs to be changed to something that works in an Entry widget:
ent = Entry(root, width=30, wraplength=30)
I also need to be able to make the Entry widget taller than one line, is there a way i can do that, for example making it vertically fill a frame (similarly to expand=True making it horizontally fill a frame).
Thank you!
I believe that Entry widgets are single line only, you may want to try Text widget
https://tkdocs.com/tutorial/morewidgets.html#text
The entry widget doesn't support wrapping. If you want to have multiple lines -- even if it's one long line that's wrapped -- you'll need to use either a Text, Label, or Message widget. Only the Text widget supports user input, the other two are strictly for display.
As for making the entry widget taller, you can do that with a geometry manager. For example, you can use the sticky option of grid or the fill and expand options of pack. This will make the widget taller, but the text will still just appear as a single line.
but text can't use (show="")
I have made a text widget in my gui but cannot figure out how to write to it on certain specified lines. Is it possible to make it always have some words in one place when the program is started and then to have other numbers associated with variables entered in other places.
txtReciept = Text(root)
txtReciept = Text(root, width=76, height=50)
txtReciept.pack()
The text widget cannot be written to sparsely. That is, if you want to write to row 10, you must have data on rows 1-9. Likewise, if you want to display something at a specific column, you must have data in all of the columns leading up to it.
I am looking to write a program which outputs a bunch (around 30) of boxes like in this image:
I have been researching for weeks, I thought that to layout text in a graphically pleasing way I could use QTableWidget in PyQT, but I now realise that it is far too difficult to learn for such a simple task, there must be a quicker way. So I am thinking now to pass to Tkinter or maybe just draw the information with a Drawing Module like PyCairo and only then place each image in a PyQT interface. Sorting out all the positioning in a drawing module would be much quicker than learning how to do the same in PyQT.
But I feel I am missing something, I would have thought a much easier task to layout in a nice way a bunch of numbers in a repetitive format.
Some of the boxes will need also some graphical content has bars and charts for which I though to use plotly or cairo.
Whilst you're probably better off doing this with HTML and CSS as has been mentioned above, this isn't too difficult to do with Python and can be achieved with the use of just tkinter. Please see my code below for an example of how this could work:
from tkinter import *
root = Tk()
frame1 = []
frame2 = []
c = 0
numberofboxes = 8 #change this to increase the number of boxes
for i in range(numberofboxes):
if i % 4 == 0: #checks if the current box is the fourth in row
c = c + 1 #if the current box is the forth in the row then this runs and increases a counter which we later use to determine the row
if len(frame1) != c: #checks if the number of rows currently existing matches the number there should be
frame1.append(Frame(root)) #if the numbers don't match this runs and creates a new frame which acts as another row
frame1[c-1].pack(expand="True", fill="both") #packs the new row
frame2.append(Frame(frame1[c-1], bg="green")) #this is where the boxes are created
frame2[i].pack(ipadx="50", ipady="50", side="left", padx="10", pady="10", expand="True", fill="both") #this is where the boxes are placed on the screen
for i in range(len(frame2)): #this for loop places the items inside each box, all of this can be replaced with whatever is needed
Label(frame2[i], text="CO"+str(i), bg="green", fg="white").pack(side="top", anchor="w")
Label(frame2[i], text="12165.1"+str(i), bg="green", fg="white").pack(side="top", anchor="w")
Label(frame2[i], text="+60.7"+str(i), bg="green", fg="white").pack(side="bottom", anchor="e")
Label(frame2[i], text="+1.2"+str(i)+"%", bg="green", fg="white").pack(side="bottom", anchor="e")
root.mainloop()
So essentially, we create a frame for each row and each box is a frame which has elements packed inside it and is fitted in the "row frame" 4 to each row.
You should take a close look at all of the options for .pack() during this script as well as they are necessary to achieve the desired layout and results.
For your triangles you would most likely need to either import an image or draw them within a canvas positioned properly or (as was pointed out by Bryan Oakley below) you could use unicode characters for the arrows, which would be an awful lot simpler.