I have been struggling to get the text in the border of a tk.LabelFrame to change when I open a new text file inside the frame. I have been using essentially the same code as I use elsewhere to change a tk.Label.
I just came across this in some documentation:
"When a new labelframe is created, it has no default event bindings: labelframes are not intended to be interactive."
The last phrase is fairly definitive, but the use of the word 'default' makes me wonder if there is a way of achieving this.
So, my question is, can it be done?
Thanks to #Bryan Oakley who mentioned the magic word 'configure'which got me thinking along different lines and I came up with this solution:
import tkinter as tk
from tkinter import ttk
# root window
root = tk.Tk()
root.geometry('300x200')
root.resizable(False, False)
root.title('LabelFrame Demo')
lf = ttk.LabelFrame(
root,
text='text to change')
lf.grid(column=0, row=0, padx=20, pady=20)
def file_1_label():
my_text = 'editing file 1'
lf.configure(text='editing FILE 1')
def file_2_label():
my_text = 'editing file 2'
lf.configure(text='editing FILE 2')
button1 = tk.Button(lf, text='File 1')
button1.grid(row=0, column=0)
button1.configure(command=file_1_label)
button2 = tk.Button(lf, text='File2')
button2.grid(row=0, column=2)
button2.configure(command=file_2_label)
root.mainloop()
Related
My problem with this code is that the text box that appears when you hover over a button resizes the entire window. What I want is for this frame to have the same size as the Text field which will place the information there.
import tkinter
import re
from tkinter import *
from tkinter import ttk, filedialog
from ctypes import windll
from tkinter.scrolledtext import ScrolledText
class MainApp(Tk):
def __init__(self):
super().__init__()
#self.geometry("500x300")
self.title("My Bioinformatics Toolbox")
def fasta_button_hover(hover):
instructions_field.config(text="This function will allow the user to open, "
"read and see the contents of a .FASTA file. It "
"will also allow the user to save their own sequence "
"as a FASTA file")
def fasta_button_leave(hover):
instructions_field.config(text="")
# Create the menu bar
menu_bar = tkinter.Menu(self)
file_menu = tkinter.Menu(menu_bar, tearoff=0)
# The File cascade in the menu bar
menu_bar.add_cascade(label="File", menu=file_menu)
file_menu.add_command(label="Exit", command=self.destroy)
self.config(menu=menu_bar)
# Create the buttons frame
button_frame = ttk.Frame(self)
#button_frame.configure(height=button_frame["height"], width=button_frame["width"])
#button_frame.grid_propagate(0)
button_frame.pack(side=LEFT)
# Create the text field frame
text_frame = ttk.Frame(self, width=500)
text_frame.pack(side=RIGHT)
# Create the instructions field
instructions_field = Message(text_frame, width=300)
instructions_field.grid(column=0, row=0)
# Create the buttons
fasta_button = ttk.Button(button_frame, text="Read FASTA", width=12)
fasta_button.bind("<Enter>", fasta_button_hover)
fasta_button.bind("<Leave>", fasta_button_leave)
fasta_button.grid(column=0, row=0)
dna_to_rna_button = ttk.Button(button_frame, text="DNA to RNA", width=12)
dna_to_rna_button.grid(column=0, row=1)
example_button = ttk.Button(button_frame, text="Example", width=12)
example_button.grid(column=0, row=2)
example_button2 = ttk.Button(button_frame, text="Example2", width=12)
example_button2.grid(column=0, row=3)
example_button3 = ttk.Button(button_frame, text="Example3", width=12)
example_button3.grid(column=0, row=4)
# A separator line ("rowspan" is set to a safe number of rows)
button_separator = ttk.Separator(button_frame, orient="vertical")
button_separator.grid(column=1, row=0, rowspan=100, sticky="ns")
# Fix for windows DPI scaling
windll.shcore.SetProcessDpiAwareness(1)
app = MainApp()
app.mainloop()
I want my window to have this size full size app at all time, but when I'm not hovering it has this size small puny app
My guess is that I'm missing something from the text_frame, but I can't figure it out...
Edit to update indentation
This amendment to your code seems to achieve this:
# Create the instructions field
instructions_field = ttk.Label(text_frame, width=50, wraplength=300)
instructions_field.grid(column=0, row=0)
The changes made:
Replaced the Message widget with a Label widget
Set both the width and wraplength keyword arguments in the Label
Manually adjusted the wraplength (taken as a number of pixels before wrapping) to fit all of the text inside the widget
It is arguably not the most elegant solution but a working and reliable one nonetheless
Note: The width keyword argument in the Label is taken as a number of characters wide
I am trying to place a greyed out background text inside a textbox, that disappears when someone begins to type. I have tried overlaying a label onto the textbox, but I could not get it to work. Here is some code I am running for the text box
root = tk.Tk()
S = tk.Scrollbar(root)
T = tk.Text(root, height=70, width=50)
S.pack(side=tk.RIGHT, fill=tk.Y)
T.pack(side=tk.LEFT, fill=tk.Y)
S.config(command=T.yview)
T.config(yscrollcommand=S.set)
root.protocol("WM_DELETE_WINDOW", stop)
tk.mainloop()
How can I put in the background text?
Using a callback function you can remove the default text and change the foreground colour
import tkinter as tk
root = tk.Tk()
e = tk.Entry(root, fg='grey')
e.insert(0, "some text")
def some_callback(event): # must include event
e.delete(0, "end")
e['foreground'] = 'black'
# e.unbind("<Button-1>")
e.unbind("<FocusIn>")
return None
# e.bind("<Button-1>", some_callback)
e.bind("<FocusIn>", some_callback)
e.pack()
root.mainloop()
You are probably talking about placeholders , tkinter does not have placeholder attribute for Text widget, but you do something similar with Entry widget . You have to do it manually, by binding an event with the Text widget.
text = tk.StringVar()
text.set('Placeholder text')
T = tk.Entry(root, height=70, width=50, textvariable = text)
def erasePlaceholder(event):
if text.get() == 'Placeholder text':
text.set('')
T.bind('<Button-1>', erasePlaceholder)
Try to ask if you face any issues.
I'm trying to use an Entry field to get manual input, and then work with that data.
All sources I've found claim I should use the get() function, but I haven't found a simple working mini example yet, and I can't get it to work.
I hope someone can tel me what I'm doing wrong. Here's a mini file:
from tkinter import *
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
content = entry.get()
print(content) # does not work
mainloop()
This gives me an Entry field I can type in, but I can't do anything with the data once it's typed in.
I suspect my code doesn't work because initially, entry is empty. But then how do I access input data once it has been typed in?
It looks like you may be confused as to when commands are run. In your example, you are calling the get method before the GUI has a chance to be displayed on the screen (which happens after you call mainloop.
Try adding a button that calls the get method. This is much easier if you write your application as a class. For example:
import tkinter as tk
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Get", command=self.on_button)
self.button.pack()
self.entry.pack()
def on_button(self):
print(self.entry.get())
app = SampleApp()
app.mainloop()
Run the program, type into the entry widget, then click on the button.
You could also use a StringVar variable, even if it's not strictly necessary:
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
v.set("a default value")
s = v.get()
For more information, see this page on effbot.org.
A simple example without classes:
from tkinter import *
master = Tk()
# Create this method before you create the entry
def return_entry(en):
"""Gets and prints the content of the entry"""
content = entry.get()
print(content)
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
# Connect the entry with the return button
entry.bind('<Return>', return_entry)
mainloop()
*
master = Tk()
entryb1 = StringVar
Label(master, text="Input: ").grid(row=0, sticky=W)
Entry(master, textvariable=entryb1).grid(row=1, column=1)
b1 = Button(master, text="continue", command=print_content)
b1.grid(row=2, column=1)
def print_content():
global entryb1
content = entryb1.get()
print(content)
master.mainloop()
What you did wrong was not put it inside a Define function then you hadn't used the .get function with the textvariable you had set.
you need to put a textvariable in it, so you can use set() and get() method :
var=StringVar()
x= Entry (root,textvariable=var)
Most of the answers I found only showed how to do it with tkinter as tk. This was a problem for me as my program was 300 lines long with tons of other labels and buttons, and I would have had to change a lot of it.
Here's a way to do it without importing tkinter as tk or using StringVars. I modified the original mini program by:
making it a class
adding a button and an extra method.
This program opens up a tkinter window with an entry box and an "Enter" button. Clicking the Enter button prints whatever is in the entry box.
from tkinter import *
class mini():
def __init__(self):
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
Button(master, text='Enter', command=self.get_content).grid(row=1)
self.entry = Entry(master)
self.entry.grid(row=0, column=1)
master.mainloop()
def get_content(self):
content = self.entry.get()
print(content)
m = mini()
I'm trying to use an Entry field to get manual input, and then work with that data.
All sources I've found claim I should use the get() function, but I haven't found a simple working mini example yet, and I can't get it to work.
I hope someone can tel me what I'm doing wrong. Here's a mini file:
from tkinter import *
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
content = entry.get()
print(content) # does not work
mainloop()
This gives me an Entry field I can type in, but I can't do anything with the data once it's typed in.
I suspect my code doesn't work because initially, entry is empty. But then how do I access input data once it has been typed in?
It looks like you may be confused as to when commands are run. In your example, you are calling the get method before the GUI has a chance to be displayed on the screen (which happens after you call mainloop.
Try adding a button that calls the get method. This is much easier if you write your application as a class. For example:
import tkinter as tk
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Get", command=self.on_button)
self.button.pack()
self.entry.pack()
def on_button(self):
print(self.entry.get())
app = SampleApp()
app.mainloop()
Run the program, type into the entry widget, then click on the button.
You could also use a StringVar variable, even if it's not strictly necessary:
v = StringVar()
e = Entry(master, textvariable=v)
e.pack()
v.set("a default value")
s = v.get()
For more information, see this page on effbot.org.
A simple example without classes:
from tkinter import *
master = Tk()
# Create this method before you create the entry
def return_entry(en):
"""Gets and prints the content of the entry"""
content = entry.get()
print(content)
Label(master, text="Input: ").grid(row=0, sticky=W)
entry = Entry(master)
entry.grid(row=0, column=1)
# Connect the entry with the return button
entry.bind('<Return>', return_entry)
mainloop()
*
master = Tk()
entryb1 = StringVar
Label(master, text="Input: ").grid(row=0, sticky=W)
Entry(master, textvariable=entryb1).grid(row=1, column=1)
b1 = Button(master, text="continue", command=print_content)
b1.grid(row=2, column=1)
def print_content():
global entryb1
content = entryb1.get()
print(content)
master.mainloop()
What you did wrong was not put it inside a Define function then you hadn't used the .get function with the textvariable you had set.
you need to put a textvariable in it, so you can use set() and get() method :
var=StringVar()
x= Entry (root,textvariable=var)
Most of the answers I found only showed how to do it with tkinter as tk. This was a problem for me as my program was 300 lines long with tons of other labels and buttons, and I would have had to change a lot of it.
Here's a way to do it without importing tkinter as tk or using StringVars. I modified the original mini program by:
making it a class
adding a button and an extra method.
This program opens up a tkinter window with an entry box and an "Enter" button. Clicking the Enter button prints whatever is in the entry box.
from tkinter import *
class mini():
def __init__(self):
master = Tk()
Label(master, text="Input: ").grid(row=0, sticky=W)
Button(master, text='Enter', command=self.get_content).grid(row=1)
self.entry = Entry(master)
self.entry.grid(row=0, column=1)
master.mainloop()
def get_content(self):
content = self.entry.get()
print(content)
m = mini()
Question
I'm trying to make a 'ttk Label' which a) is 20 pixels high by 300 pixels wide, b) is scrollable (in this case horizontally), and c) uses the simplest code possible within reason (except for the fact that the text and scrollbar are both within a frame*). I've found stackoverflow to be helpful in describing the processes I need to go through (put the label in a frame, put the frame in a canvas, put the scroll bar next to or underneath the canvas and 'bind' them together somehow), but despite looking at a fair few docs and stackoverflow questions, I can't figure out why my code isn't working properly. Please could someone a) update the code so that it satisfies the conditions above, and b) let me know if I've done anything unnecessary? Thanks
*the frame will be going in a project of mine, with text that is relevant
Current code
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
myframe_outer = ttk.Frame(root)
mycanvas = tk.Canvas(myframe_outer, height=20, width=300)
myframe_inner = ttk.Frame(mycanvas)
myscroll = ttk.Scrollbar(myframe_outer, orient='horizontal', command=mycanvas.xview)
mycanvas.configure(xscrollcommand=myscroll.set)
myframe_outer.grid()
mycanvas.grid(row=1, sticky='nesw')
myscroll.grid(row=2, sticky='ew')
mycanvas.create_window(0, 0, window=myframe_inner, anchor='nw')
ttk.Label(myframe_inner, text='test ' * 30).grid(sticky='w')
root.mainloop()
Edit:
Current result
Answer
Use a readonly 'entry' widget - it looks the same as a label, and doesn't need to be put in a canvas.
Code
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
mytext = tk.StringVar(value='test ' * 30)
myframe = ttk.Frame(root)
myentry = ttk.Entry(myframe, textvariable=mytext, state='readonly')
myscroll = ttk.Scrollbar(myframe, orient='horizontal', command=myentry.xview)
myentry.config(xscrollcommand=myscroll.set)
myframe.grid()
myentry.grid(row=1, sticky='ew')
myscroll.grid(row=2, sticky='ew')
root.mainloop()
Result