I have been using a widget in my tkinter programs, but the problem with this widget is the fact that it shows under the windows titlebar, here is the widget I am using:
class LabeledEntry(ttk.Frame):
def __init__(self, master, text, width=120, insertion="0"):
super().__init__(master, width=width)
self.pack_propagate(False)
self.label = ttk.Label(self, text=text)
self.entry = ttk.Entry(self)
self.label.pack(side='left')
self.entry.pack(side='right')
Apparently, the problem is with the pack propagate function, but I need it so that multiple widgets can look equal on the same column.
EDIT: So, apparently, the problem wasnt the fact that it was "being placed behind the window", but because i had to manually input a height for the frame since it doesnt depend on its children for size. Thanks to the commenter who said that.
By the way, if you were wondering what it looked like without the height, here:
https://imgur.com/a/hQCQ8eu
Is this what you want?
Change this ttk.Label(self to ttk.Label(maaster
code:
from tkinter import ttk
import tkinter as tk
win = tk.Tk()
class LabeledEntry(ttk.Frame):
def __init__(self, master, text, width=120, insertion="0"):
super().__init__(master, width=width)
self.pack_propagate(False)
self.label = ttk.Label(master, text=text)
self.entry = ttk.Entry(master)
self.label.pack(side='left')
self.entry.pack(side='right')
win.title('3squares6lines')
app =LabeledEntry(win, 'What to enter')
app.mainloop()
screenshot:
Related
I would like to have two Tkinter buttons (ttk.Button) next to each other under my entry widgets, while still keeping them centre justified. I am already using .pack() for the other widgets in the frame, so I cannot use .grid() or .place() on them. I know that you can use tk.LEFT, tk.RIGHT and so on to place them in a line, but that moves them to the far edge. Is there a way I can use a method like this to place them next to each other in the centre of the window?
this is my code:
class EmailPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
send_button = ttk.Button(self, text='Send Email\'s', command=lambda: send_email())
send_button.pack(padx=10, pady=5)
test_button = ttk.Button(self, text='Test Email', command=lambda: test_email())
test_button.pack(padx=10, pady=5)
Thanks in advance
You can create a tk.Frame and then pack the buttons in them:
from tkinter import ttk
import tkinter as tk
root=tk.Tk()
tk.Label(root,text='These 2 buttons are in centre!').pack()
f1=tk.Frame(root)
f1.pack(expand=1)
b1=ttk.Button(f1,text='Button 1')
b1.pack(expand=True,side=tk.BOTTOM)
b2=ttk.Button(f1,text='Button 2')
b2.pack(expand=True,side=tk.BOTTOM)
root.mainloop()
I have copied your code and appended some necessary methods to make it a working example.
In your example, your button commands do not need lambda since you are not sending data to those methods.
Also, self. needs to be prepended to widgets and tk.Frame needs to be managed.
import tkinter as tk
from tkinter import ttk
class EmailPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
entry = tk.Entry( self, width = 40 )
entry.pack(fill = tk.BOTH, expand = False)
self.send_button = ttk.Button(self, text='Send Email\'s', command = self.send_email)
self.send_button.pack(side=tk.RIGHT, fill = tk.BOTH, expand=True)
self.test_button = ttk.Button(self, text='Test Email', command = self.test_email)
self.test_button.pack(side=tk.LEFT, fill = tk.BOTH, expand=True)
self.pack(fill = tk.BOTH, expand = True)
def send_email( self ):
pass
def test_email( self ):
pass
my_emailer = EmailPage(tk.Tk(), "")
my_emailer.master.mainloop()
From tutorials, I have kind of been under the impression that grid just "kind of figures it out" for width, but it's clearly not the case when it comes to Text (I suppose when combined with list).
With the following code, listbox has is tiny and Text is absolutely massive (Width wise). I can make the listbox equal to the size of the Text by changing sticky="ew", but that's not what I want - I want a reasonable, equivalently styled "grid".
If I hardcode the size of the width, it's even more frustrating, because listbox width seems to equate to approximately 2/3 of Text width.
I've read up on rowconfigure and columnconfiugre, but this seems to actually do nothing with the below code (note - rowconfigure and columnconfigure are not in the below code, but I have tried them, perhaps I'm using them wrong).
Anyways, with the below code - can anyone explain to me how to make these more reasonably sized width wise, and also the same? Should I hardcode a width to Text and then set listbox to sticky="ew"? Seems counter intuitive to the grid layout concept.
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
self.frame = tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
self.initialize()
def initialize(self):
self.lst_bx = tk.Listbox(self.parent, height = 15)
self.lst_bx.grid(row=0, column=0, columnspan=2, padx=(10,10), sticky="w")
self.exe_field = tk.Text(self.parent, height=15)
self.exe_field.grid(row=1, column=0, columnspan=2, padx=(10,10), sticky="w")
self.pick_exe_btn = tk.Button(
self.parent, text="Choose Location", width=15
)
self.pick_exe_btn.grid(row=0, column=2)
if __name__ == "__main__":
root = tk.Tk()
#window_config(root)
MainApplication(root).grid(stick="nesw")
root.resizable(False, False)
root.mainloop()
I'm sorry for being such a noob, I swear I have searched this a lot before posting here - I just cannot find a straight answer on why ListBox is a completely different width from Text (and even moreso when I specify a width).
The how tkinter calculates the dimensions tkinter.ListBox() and tkinter.Text() widgets is a little bit different from most of other widgets where it uses pixels. For these 2 specific widgets, the width is calculated in terms of characters whereas the height is assessed in terms of lines.
You did not set the width of self.lst_bx, so tkinter sets it by default to 20 characters.
You did not specify the width of self.exe_field either. So tkinter calculates this width based on the current default font size.
From 1) and 2) we can conclude that it is quite normal we can not expect from self.exe_field to have the same width as self.lst_bx. This means, you have no option other than hard coding them and visually check the GUI.
With minor changes of your code (mainly provided in the comments below your question) this is how I solved your issue:
import tkinter as tk
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
self.initialize()
def initialize(self):
self.lst_bx = tk.Listbox(self, height = 15, width=70)
self.lst_bx.grid(row=0, column=0, padx=(10,10), sticky="w")
self.exe_field = tk.Text(self, height=15, width=80)
self.exe_field.grid(row=1, column=0, padx=(10,10), sticky="w")
self.pick_exe_btn = tk.Button(self, text="Choose Location", width=15)
self.pick_exe_btn.grid(row=0, column=2, columnspan=2)
if __name__ == "__main__":
root = tk.Tk()
#window_config(root)
MainApplication(root).grid(stick="nesw")
root.resizable(False, False)
root.mainloop()
Note where I moved the columnspace option (it quite does not make a sens in the two places where you have set it previously). Note also that tkinter calculate the character somehow differently between the listbox and text widgets. Depending your operating system (and maybe machine also), you may have to change the 2 width dimensions I set to the widgets in questions.
Here is what I got on my machine:
I've read a few threads all over the internet regarding clearing a text box on tkinter. Basically everyone says it's simple:
text.delete("1.0", END)
However, perhaps it has something to do with the way I structured it, or the way I'm calling it, but for some reason, this does not work for me. It simply does nothing.
I've tried re-positioning the def, and re-writing the text.delete("1.0", END) in a number of ways, most of which lead me to other errors, but I cannot seem to get this to work.
Ultimately, what I'm trying to accomplish is that when I click a button, the text box will clear, before populating with new information.
Below is my code.
from tkinter import *
from PIL import Image, ImageTk
import functions
class MainWindow(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("pyTicket")
# TOOLBAR ####################################################
toolbar = Frame(self.parent, bd=1, relief=RAISED)
self.img = Image.open("Icons\startupcheck.png")
eimg = ImageTk.PhotoImage(self.img)
startupButton = Button(toolbar, text="Re-Check ", image=eimg, compound="left", relief=RAISED, command=self.StartUpChecker)
startupButton.image = eimg
startupButton.pack(side=RIGHT, padx=2, pady=2)
toolbar.pack(side=TOP, fill=X)
self.parent.config(menu=menubar)
self.pack(anchor=N, side=TOP, fill=X, expand=False)
# TOOLBAR ####################################################
# TEXTBOX ####################################################
self.textbox = Text(self, wrap="word", height=5)
self.textbox.pack(side="bottom", fill="both", expand=True)
self.textbox.tag_configure("TextBox", foreground="#b22222")
self.pack(anchor=S, side=BOTTOM, fill=BOTH, expand=True)
# TEXTBOX ####################################################
# Functions ###################################################
def StartUpChecker(self):
self.clear_text()
functions.StartUpChecker()
def clear_text(self):
self.textbox.delete("1.0", END)
class TextRedirector(object):
def __init__(self, widget, tag="stdout"):
self.widget = widget
self.tag = tag
def write(self, str):
self.widget.configure(state="normal")
self.widget.insert("end", str, (self.tag,))
self.widget.configure(state="disabled")
def main():
root = Tk()
#Width X Height
root.geometry("500x300+300+300")
root.update()
root.minsize(400,200)
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
You don't appear to actually use the TextRedirector class in the code you posted, but if you're using it in your actual code, note that its .write() method leaves the textbox in a disabled state - which prevents ALL modifications, even those resulting from code instead of direct user action. Your .clear_text() method needs to temporarily enable the textbox so that you can modify it, exactly as .write() does.
I'm using python2 on Windows. When I run the followig code, I get a gap between the two canvas (see picture below), although there is no padding specified when I grid them.
Is there any possibility to remove this?
import Tkinter as tk
import ttk
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.c1 = tk.Canvas(master=self, background='white', borderwidth=0,
relief=tk.FLAT)
self.c2 = tk.Canvas(master=self, background='white', borderwidth=0,
relief=tk.FLAT)
self.c1.grid(row=0, column=0, sticky=tk.NSEW)
self.c2.grid(row=1, column=0, sticky=tk.NSEW)
self.mainloop()
App()
Thanks for help!
You need to set highlightthickness to zero as well.
self.c1 = tk.Canvas(..., highlightthickness=0)
From the canvas page of effbot highlightthickness explained as:
The width of the highlight border. The default is system specific
(usually one or two pixels). (highlightThickness/HighlightThickness)
I'm trying to create a fairly simple e-reader, and I've managed to use tkinter to create something akin to one. But what I can't seem to work out is how to create a scrollbar to allow the user to scroll through the text at will. I can get it working in other pieces of coding, but I can't make it work within this program and I can't work out what the problem is. I've put my simple e-reader, without the attempted scrollbar below.
from Tkinter import *
import tkFileDialog
import ScrolledText
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("File dialog")
self.pack(fill=BOTH, expand=1)
menubar = Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = Menu(menubar)
fileMenu.add_command(label="Open", command=self.onOpen)
menubar.add_cascade(label="File", menu=fileMenu)
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
def onOpen(self):
ftypes = [('Python files', '*.py'), ('All files', '*')]
dlg = tkFileDialog.Open(self, filetypes = ftypes)
fl = dlg.show()
if fl != '':
text = self.readFile(fl)
self.txt.insert(END, text)
def readFile(self, filename):
f = open(filename, "r")
text = f.read()
return text
self.txt = ScrolledText(self, undo=True)
self.txt['font'] = ('consolas', '12')
self.txt.pack(expand=True, fill='both')
def main():
root = Tk()
ex = Example(root)
root.geometry("300x250+300+300")
root.mainloop()
if __name__ == '__main__':
main()
Adding a scrollbar to a text widget requires you to do two things in addition to creating the actual widgets:
you must set the yscrollcommand attribute of the text widget to point to the set method of the scrollbar
you must set the command attribute of the scrollbar to point to the yview method of the text widget
For example:
self.text.configure(yscrollcommand=self.scrollbar.set)
self.scrollbar.configure(command=self.text.yview)
I've long wondered whether this could really be the answer to your question, but after the discussion in the comments, it seems it is: You just put the code creating the ScrolledText in the wrong place!
Try moving these three lines (that are now outside of the class, causing a NameError for self)
self.txt = ScrolledText(self, undo=True)
self.txt['font'] = ('consolas', '12')
self.txt.pack(expand=True, fill='both')
to where these lines are in your initUI method (replace these lines)
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
With other words, in your initUI method, instead of creating a Text widget, create a ScrolledText. Also, change import ScrolledText to from ScrolledText import ScrolledText so that ScrolledText is the actual widget, and not the module defining the widget.