other component not showing after I show the scrolltext - python

i am doing a project to calculate the charges for different weight of the parcel. however, the position of the component(label, button, textbox and scrolltext) did not place it in the manner i want.
i want the length label to be in the center top, and the length textbox next to it. similar to width label and height label.
the following is my code.
from tkinter import *
import tkinter.scrolledtext as st
class Delivery(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Delivery Charges Calculator(Ong Jia Sheng)")
self.master.geometry("700x350") #width by height dimension
#create the components
#create RadioButtons
self._salute = StringVar() #common variable for Radio buttons
self._rb1 = Radiobutton(self,text="cm",variable=self._salute,value="cm")
self._rb2 = Radiobutton(self,text="inch",variable=self._salute,value="inch")
self._salute.set("cm") #value of radiobutton, this is to set default selection
#create other components
self._lenLb = Label(self, text="Length:")
self._widLb = Label(self, text="Width:")
self._heiLb = Label(self, text="Height:")
self._weiLb = Label(self, text="Weight(kg):")
self._lenTb = Entry(self, width=25)
self._widTb = Entry(self, width=25)
self._heiTb = Entry(self, width=25)
self._weiTb = Entry(self, width=25)
self._charButt = Button(self, width=15, text="Calculate Charge",command=self.calcCharges)
self._cleButt = Button(self, width=15,text="Clear",command=self.Clear)
self._stxt = st.ScrolledText(self,width=700,height=5)
#place onto the window use grid layout
self._lenLb.grid(row=0,column=4)
self._lenTb.grid(row=0,column=5)
self._widLb.grid(row=1,column=4)
self._widTb.grid(row=1,column=5)
self._heiLb.grid(row=2,column=4)
self._heiTb.grid(row=2,column=5)
self._rb1.grid(row=5,column=6)
self._rb2.grid(row=5,column=7)
self._weiLb.grid(row=8,column=4)
self._weiTb.grid(row=8,column=5)
self._charButt.grid(row=9,column=5)
self._cleButt.grid(row=9,column=6)
self._stxt.grid(row=9,column=0)
self.grid()
def calcCharges(self):
self._salute.set("inch")
def Clear(self):
self._salute.set("cm")
def main():
app = Delivery()
app.mainloop()
main()

The width of ScrolledText constructor is expressed in characters (not in pixels).
Since it is very wide (700 char) and alone in the first column, other widgets are moved far to the right and outside the screen.

Related

Python tkinter use canvas to create dynamically window with scroll bar

My objective is to solve the problem of the grid exceeding the window(shown as figure.1)
enter image description here
My program function is creating a grid that number of columns defined by user.
I tried using canvas to solve this problem, but it still doesn't work successfully.
It doesn't show the full grid in the canvas.(shown as figure.2)
enter image description here
Below is my code, could you please help solve the problems or give me some advice.
Thanks a lot.
Code:
import tkinter as tk
import tkinter.messagebox
import tkinter.filedialog
MainWindow = tk.Tk()
MainWindow.title('Helloworld')
MainWindow.geometry('1000x800')
def btn_generate():
global EntryNamelist
global Entrycoordinatelist
global EntryLabellist
con_num = en_condition_num.get()
if con_num != '':
#### Grid Body
for i in range(1,int(con_num) +1 ):
lb_name = tk.Label(fm_grid, text="Condition" + str(i) )
lb_name.grid(row=i, column=0, padx=2, pady=1, ipadx=20, ipady=5)
En_name = tk.Entry(fm_grid, bd = 2,width = 10,font=('Ubuntu', 10))
En_name.grid(row=i, column=1, padx=2, pady=1, ipadx=35, ipady=5)
En_coor = tk.Entry(fm_grid, bd = 2,width = 10,font=('Ubuntu', 10))
En_coor.grid(row=i, column=2, padx=2, pady=1, ipadx=200, ipady=5)
else:
tk.messagebox.showerror("Error", "Please input a num of conditions")
fm_main = tk.Frame()
fm3 = tk.Frame(fm_main)
lb_condition = tk.Label(fm3,text = 'Please input the number of condition')
lb_condition.pack(side="left")
en_condition_num = tk.Entry(fm3, bd = 2,width = 5)
en_condition_num.pack()
fm3.pack()
btn_generate = tk.Button(fm_main,text="Generate Grid",command=btn_generate)
btn_generate.pack()
lb_en = tk.Label(fm_main,text = '')
lb_en.pack()
def myfunction(event):
canvas.configure(scrollregion=canvas.bbox("all"),width=200,height=200)
canvas=tk.Canvas(fm_main)
fm_grid = tk.Frame(canvas)
fm_grid.pack()
myscrollbar=tk.Scrollbar(fm_main,orient="vertical",command=canvas.yview)
canvas.configure(yscrollcommand=myscrollbar.set)
myscrollbar.pack(side="right",fill="y")
canvas.pack(side="left")
canvas.create_window((4,4),window=fm_grid,anchor='nw')
fm_grid.bind("<Configure>",myfunction)
fm_main.pack()
MainWindow.mainloop()
Question: It doesn't show the full grid in the canvas
You have to sync, the width of the Canvas with the width of the Frame inside.
Note: fm_grid = tk.Frame(canvas, bg='blue') is shown in 'blue'.
Dont's:
Remove fm_grid.pack(), you layout with: canvas.create_window(....
Also, i recommend not to use a offset (4, 4), because you have to calculate with this offset on every canvas.configure(..., width=width + 4. Use (0, 0) instead.
# fm_grid.pack()
...
canvas.create_window((4,4),window=fm_grid,anchor='nw')
Useless, to create dynamically window:
Your usage of canvas.bbox is useless, because it's the dimension you want to layout this widget.
Using a fixed width=200, smaller than fm_grid.width will allways cut the fm_grid content, it's not dynamically either.
canvas.configure(scrollregion=canvas.bbox("all"),width=200,height=200)
How to sync the width of the Canvas with the width of the Frame inside?
You bound fm_grid.bind("<Configure>", therefore the event.widget is fm_grid, the Frame inside.
Get the dimensions of the event.widget from there w.winfo_... and build a bbox tuple to set scrollregion.
Use width to set canvas.width, to be in sync with the event.widget.winfo_width().
class ScrollCanvas(tk.Canvas):
def __init__(self, parent, **kwargs):
super().__init__(parent, **kwargs)
def create_window(self, child):
super().create_window((0, 0), window=child, anchor='nw')
child.bind("<Configure>", self.on_configure)
def on_configure(self, event):
w = event.widget
bbox = x, y, width, height = 0, 0, w.winfo_width(), w.winfo_height()
self.configure(scrollregion=bbox, width=width)
Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6

Tkinter / Python - disabling resizing of buttons when a window is resized

I have a window with a listbox that resize with one another. I'm using grid for this. There are a row of buttons under the list box which are currently moving and resizing with the window. I'd like the buttons to remain in place and remain a consistent size while window and listbox resize (so the buttons always remain in the bottom left corner of the listbox).
Is there an easy way to do this? I just started using Tkinter today so I may have just missed it in the docs or might just be confused on grid layouts.
The buttons are set up as follows:
nextbutton = Button(self, width = 30, height = 30, image = ffbtn)
nextbutton.image = ffbtn
nextbutton.bind("<Button-1>", self.forward)
nextbutton.grid(row = 10, column=4, sticky='w')
I've tried all sticky combinations but the ones that don't resize the buttons still allow them to move around, which I don't want.
EDIT: Heres an very basic example of what I'm talking about, as requested. When the window is resized, the buttons move apart from each other. I don't want that.
On a side note, do I need all those grid configures at the end to set the weight even if I use its one column or row with column/rowspan taking up all the space?
import tkinter
from tkinter import *
from tkinter import ttk
class Application(tkinter.Tk):
def __init__(self, parent):
tkinter.Tk.__init__(self, parent)
self.minsize(300,300)
self.parent = parent
self.main()
def main(self):
self.grid()
listbox = tkinter.Listbox(self, width=20, height=25, bg = 'grey')
listbox.grid(padx=30, pady=30, columnspan=11, sticky='NEW')
bt1 = Button(self, width = 5, height = 5)
bt1.grid(row=10, column=0, padx=(30,0), sticky='w')
bt2 = Button(self, width = 5, height = 5)
bt2.grid(row = 10, column=1, sticky='w')
bt3 = Button(self, width = 5, height = 5)
bt3.grid(row = 10, column=2, sticky='w')
bt4 = Button(self, width = 5, height = 5)
bt4.grid(row = 10, column=3, sticky='w')
bt5 = Button(self, width = 5, height = 5)
bt5.grid(row = 10, column=4, sticky='w')
self.grid_columnconfigure(0,weight=1)
self.grid_columnconfigure(1,weight=1)
self.grid_columnconfigure(2,weight=1)
self.grid_columnconfigure(3,weight=1)
self.grid_columnconfigure(4,weight=1)
self.grid_columnconfigure(5,weight=1)
self.grid_columnconfigure(6,weight=1)
self.grid_columnconfigure(7,weight=1)
self.grid_columnconfigure(8,weight=1)
self.grid_columnconfigure(9,weight=1)
self.grid_columnconfigure(10,weight=1)
self.grid_rowconfigure(0,weight=1)
self.grid_rowconfigure(1,weight=1)
self.grid_rowconfigure(2,weight=1)
self.grid_rowconfigure(3,weight=1)
self.grid_rowconfigure(4,weight=1)
self.grid_rowconfigure(5,weight=1)
self.grid_rowconfigure(6,weight=1)
self.grid_rowconfigure(7,weight=1)
self.grid_rowconfigure(8,weight=1)
self.grid_rowconfigure(9,weight=1)
self.grid_rowconfigure(10,weight=1)
app = Application(None)
app.mainloop()
By giving non-zero weights to all the rows and columns in the grid, you explicitly make them resize with the main window.
Since you only want the listbox to resize, give non-zero weights only to the row and one of the columns that contain the listbox:
def main(self):
...
# The default weight of all rows/columns is 0. Only modify it for row 0 and column 10
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(10, weight=1)
For more info, check the documentations of the pack, grid and place methods.

How to position widgets using tkinter (entries,labels)

I want to create a GUI with Tkinter, such that you are at a grocery store, you enter the item, price, and quantity, and each item will appear on the top part of the screen.
I have a top and bottom frame, and when I place an entry it goes right in the middle of the bottom frame. I have tried justifying the position to the left, anchoring it, sticking it and doing whatever, but it's not moving.
This is my code.
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
textInput = StringVar()
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
labelFrame = Frame(self.master, bg = "red",height=40,width=700)
labelFrame.grid(row=0,column=0,sticky = N)
welcomeLabel = Label(self.master, text = "",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0,sticky = N)
actual = MenuBoard(root)
root.mainloop()
-Use
bottomFrame.grid_propagate(False)
to expand the frame and
storeItemEntry.grid(pady=30)
Or whatever value you want for pady. You might have to give row and column numbers to grid() if you're going to place other widgets in bottomFrame.
You saw "a strange dark grey background" as mentioned in the comment because you gave bg = "grey" to bottomFrame. The background wasn't visible initially because the frame shrank to fit the Entry. You can change the color to what you want or remove it entirely.
The following should be close to what you're looking for:
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
textInput = StringVar()
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
labelFrame = Frame(self.master, bg = "red",height=40,width=700)
labelFrame.grid(row=0,column=0,sticky = N)
welcomeLabel = Label(self.master, text = "Main Heading Here",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0,sticky = N)
bottomFrame = Frame(self.master, bg = "grey", height=450,width=700) #Change/remove bg
bottomFrame.grid(row=1, column=0)
bottomFrame.grid_propagate(False)
storeItemEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), textvariable=textInput, bd =4)
storeItemEntry.grid(pady=30)
actual = MenuBoard(root)
root.mainloop()
UPDATE:
Based on your comments, here is a rough implementation to work with.
from Tkinter import *
root = Tk()
root.title("project")
root.geometry("700x850+0+0")
class MenuBoard(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master,bg = "white",width=700,height=400)
mainFrame.grid(row=0,column=0)
mainFrame.grid_propagate(False)
mainFrame.grid_columnconfigure(0, weight=1)
heading = " Store Item".ljust(45)[:45] + "Item Price" # Pad the text with white spaces
listHeading = Label(mainFrame, text=heading, anchor="w", font=("Courier New",14,"bold"))
listHeading.grid(row=1, column=0, pady=5, stick="we")
# Use Text widget so you can keep inserting items
self.listItems = Text(mainFrame, font=("Courier New",12))
self.listItems.grid(row=2, column=0, pady=5, stick="we")
self.listItems.config(state="disabled") # Prevents edits on the Text
welcomeLabel = Label(mainFrame, text = "Main Heading Here",fg= "black",bg="red",)
welcomeLabel.config(font=("Courier New",23))
welcomeLabel.grid(row=0,column=0, stick="we")
bottomFrame = Frame(self.master, bg = "grey", height=450,width=700) #Change/remove bg
bottomFrame.grid(row=1, column=0)
bottomFrame.grid_propagate(False)
storeItemLabel = Label(bottomFrame, text="Food Item: ")
storeItemLabel.grid(row=0, column=0)
self.storeItemEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), bd =4)
self.storeItemEntry.grid(row=0, column=1, pady=15)
priceLabel = Label(bottomFrame, text="Price: ")
priceLabel.grid(row=2, column=0)
self.priceEntry = Entry(bottomFrame, font=("Courier New",10,"bold"), bd =4)
self.priceEntry.grid(row=2, column=1,)
btn = Button(bottomFrame, text="Add Item", command=self.add)
btn.grid(row=3, column=1, pady=15)
def add(self):
price = self.storeItemEntry.get() # Get item name from Entry
#Get price, format name and price
groceryItem = price.ljust(50)[:50] + "$%s" %(self.priceEntry.get())
self.listItems.config(state="normal") # Enable edits on the Text
self.listItems.insert("end", "\n "+groceryItem) # Edit Text
self.listItems.config(state="disabled") # Prevents edits on the Text
actual = MenuBoard(root)
root.mainloop()
A couple of things to note:
I removed some of your frames because they seemed redundant, you can add them back if needed.
Since you're working with a class, I added the self keyword to some of the attributes so I can use/call them later in other methods without errors. I left out the attributes that I do not need to call after creation.
StringVar/textvariable is not needed since you're updating the list with a button click.
There are lots of refinements I did not do (i.e. checking to see if a valid input is given before updating the list, ability to delete from the list, etc).
I used methods and features that you may or may not be aware of (.ljust(50)[:50], %s, etc)
I hope this helps :).

Using scrollbars with canvas in tkinter

I'm trying to put together a window that displays a bunch of labels generated from a dict. I'm having trouble getting the scrollbars to work properly. They won't stick to the sides of the frame when I resize the window, and I can't get the canvas to respond to the scroll command. I need the window to support a large number of labels.
from Tkinter import *
from math import floor
bits = {}
#the dict is then built
class Bitbox(Canvas):
def __init__(self, parent, bitdict, *args, **kwargs):
Canvas.__init__(self, parent, background="black")
self.bitdict = bitdict
self.parent = parent
self.lbllist = []
n=0
for i in bitdict.keys():
label = Label(self, text=i, bg='black', fg='green')
n += 1
label.grid(row = ((n-1)%30), column=int(floor((n-1)/30)))
self.lbllist.append(label)
def main():
root = Tk()
frame = Frame(root)
frame.grid(sticky=N+S+E+W)
bts = Bitbox(frame, bits)
bts.grid(row=0, column=0)
vbar = Scrollbar(frame, orient=VERTICAL)
vbar.grid(row=0, column=1, sticky=N+S)
vbar.config(command=bts.yview)
hbar = Scrollbar(frame, orient=HORIZONTAL)
hbar.grid(row=1, column=0, columnspan=2, sticky=W+E)
bts.config(xscrollcommand=hbar.set)
hbar.config(command=bts.xview)
bts.config(yscrollcommand=vbar.set)
bts.config(scrollregion=(0,0,500,1000))
root.mainloop()
Clearly I'm new at all this. It's entirely possible I have a fundamental misunderstanding of how these widgets interact. Any help is much appreciated.
to get the scrollbar to react to the mouse bind the mouse to the scrollbar like this:
def on_mousewheel(event):
bts.yview_scroll(-1*(event.delta/120), "units")
def main():
global bts
#your code...
root.bind_all("<MouseWheel>",on_mousewheel)

How to make a background image on frame in python

I have a problem i want to put a image as the background for this little converter can someone help me? I was looking online and on stackoverflow but none of the things i found would work with the class.
__author__ = 'apcs'
from tkinter import *
class FarenheitToCelsius(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Farenheit To Celsius Conversion")
self.grid()
self.farenheitLabel = Label(self, text="Farenheit")
self.farenheitLabel.grid(row=0, column=0)
self.farVar = DoubleVar()
self.farEntry = Entry(self, textvariable=self.farVar)
self.farEntry.grid(row=0, column=1)
self.celsiusLabel = Label(self, text="Celsius")
self.celsiusLabel.grid(row=1, column=0)
self.celVar = DoubleVar()
self.celEntry = Entry(self, textvariable=self.celVar)
self.celEntry.grid(row=1, column=1)
self.button = Button(self,
text="Convert to Celsius",
command=self.convertToFarenheit)
self.button2 = Button(self,
text="Convert to Farenheit",
command=self.convertToCelsius)
self.button.grid(row=2, column=1, columnspan=1)
self.button2.grid(row=2, column=0, columnspan=1)
def convertToFarenheit(self):
fare = self.farVar.get()
cels = (fare - 32) * 5 / 9
self.celVar.set(cels)
def convertToCelsius(self):
cel = self.celVar.get()
far = cel * 9 / 5 + 32
self.farVar.set(far)
def main():
FarenheitToCelsius().mainloop()
main()
I can think of at least three ways to do this:
Create an image in a label, and use place to put it in the frame. Then create all of the other widgets and use pack or grid as you normally would. Make sure you create the frame first, then the label with the image, then the children of the frame, so that the stacking order is correct.
Use a canvas instead of a frame, and use the create_image method to add an image. Then you can pack/place/grid children as normal.
Instead of a frame, use a label as the container, and then pack/place/grid widgets into the label (yes, you can add children to a label widget).

Categories

Resources