I've searched around on the Internet and couldn't seem to find a way to remove the image I placed on a button. I was wondering if there is a way to remove the image but keep the button or any other simple quick fix. Here's some of my code for reference.
def breakcup():
if firstroom.cupnotbroken:
messagebutton.config(text="You broke the cup, and the key was inside the cup.")
cup.config(image=photo4)
firstroom.cupnotbroken=False
else:
cup.config(image=None, state=DISABLED)
messagebutton.config(text="You picked up the key")
firstroom.keynotfound=False
Obviously, image=None does not work, but it was the closest thing I could find as a solution.
root = Toplevel(bob)
root.geometry("640x360+200+250")
root.resizable(0, 0)
app = Room1(root)
The windows are made using the Toplevel(parent) function. Just to clarify.
This appears to be a bug with Tkinter. From my experimentation it seems safe to set the image to an empty string rather than None:
messagebutton.configure(image="")
This works because in the underlying tcl/tk interpreter "everything is a string". That is, the tcl equivalent to None is "". When you specify an empty string, Tkinter passes that empty string to tcl, and tcl interprets it as "no image".
Related
It doesn't look like it has that attribute, but it'd be really useful to me.
You have to change the state of the Text widget from NORMAL to DISABLED after entering text.insert() or text.bind() :
text.config(state=DISABLED)
text = Text(app, state='disabled', width=44, height=5)
Before and after inserting, change the state, otherwise it won't update
text.configure(state='normal')
text.insert('end', 'Some Text')
text.configure(state='disabled')
Very easy solution is just to bind any key press to a function that returns "break" like so:
import Tkinter
root = Tkinter.Tk()
readonly = Tkinter.Text(root)
readonly.bind("<Key>", lambda e: "break")
The tcl wiki describes this problem in detail, and lists three possible solutions:
The Disable/Enable trick described in other answers
Replace the bindings for the insert/delete events
Same as (2), but wrap it up in a separate widget.
(2) or (3) would be preferable, however, the solution isn't obvious. However, a worked solution is available on the unpythonic wiki:
from Tkinter import Text
from idlelib.WidgetRedirector import WidgetRedirector
class ReadOnlyText(Text):
def __init__(self, *args, **kwargs):
Text.__init__(self, *args, **kwargs)
self.redirector = WidgetRedirector(self)
self.insert = self.redirector.register("insert", lambda *args, **kw: "break")
self.delete = self.redirector.register("delete", lambda *args, **kw: "break")
If your use case is really simple, nbro's text.bind('<1>', lambda event: text.focus_set()) code solves the interactivity problem that Craig McQueen sees on OS X but that others don't see on Windows and Linux.
On the other hand, if your readonly data has any contextual structure, at some point you'll probably end up using Tkinter.Text.insert(position, text, taglist) to add it to your readonly Text box window under a tag. You'll do this because you want parts of the data to stand out based on context. Text that's been marked up with tags can be emphasized by calling .Text.tag_config() to change the font or colors, etc. Similarly, text that's been marked up with tags can have interactive bindings attached using .Text.tag_bind(). There's a good example of using these functions here. If a mark_for_paste() function is nice, a mark_for_paste() function that understands the context of your data is probably nicer.
This is how I did it. Making the state disabled at the end disallows the user to edit the text box but making the state normal before the text box is edited is necessary for text to be inserted.
from tkinter import *
text=Text(root)
text.pack()
text.config(state="normal")
text.insert(END, "Text goes here")
text.config(state="disabled")
from Tkinter import *
root = Tk()
text = Text(root)
text.insert(END,"Some Text")
text.configure(state='disabled')
Use this code in windows if you want to disable user edit and allow Ctrl+C for copy on screen text:
def txtEvent(event):
if(event.state==12 and event.keysym=='c' ):
return
else:
return "break"
txt.bind("<Key>", lambda e: txtEvent(e))
If selecting text is not something you need disabling the state is the simplest way to go. In order to support copying you can use an external entity - a Button - to do the job. Whenever the user presses the button the contents of Text will be copied to clipboard. Tk has an in-build support of handling the clipboard (see here) so emulating the behaviour of Ctrl-C is an easy task. If you are building let's say a console where log messages are written you can go further and add an Entry where the user can specify the number of log messages he wants to copy.
Many mentioned you can't copy from the text widget when the state is disabled. For me on Ubuntu Python 3.8.5 the copying issue turned out to be caused by the widget not having focus on Ubuntu (works on Windows).
I have been using the solution with setting the state to disabled and then switching the state, when I need to edit it programmatically using 1) text.config(state=tkinter.NORMAL) 2) editing the text and 3) text.config(state=tkinter.DISABLED).
On windows I was able to copy text from the widget normally, but on Ubuntu it would look like I had selected the text, but I wasn't able to copy it.
After some testing it turned out, that I could copy it as long as the text widget had focus. On Windows the text widget seems to get focus, when you click it regardless of the state, but on Ubuntu clicking the text widget doesn't focus it.
So I fixed this problem by binding the text.focus_set() to the mouse click event "<Button>":
import tkinter
root = tkinter.Tk()
text0 = tkinter.Text(root, state=tkinter.DISABLED)
text0.config(state=tkinter.NORMAL)
text0.insert(1.0, 'You can not copy or edit this text.')
text0.config(state=tkinter.DISABLED)
text0.pack()
text1 = tkinter.Text(root, state=tkinter.DISABLED)
text1.config(state=tkinter.NORMAL)
text1.insert(1.0, 'You can copy, but not edit this text.')
text1.config(state=tkinter.DISABLED)
text1.bind("<Button>", lambda event: text1.focus_set())
text1.pack()
For me at least, that turned out to be a simple but effective solution, hope someone else finds it useful.
Disabling the Text widget is not ideal, since you would then need to re-enable it in order to update it. An easier way is to catch the mouse button and any keystrokes. So:
textWidget.bind("<Button-1>", lambda e: "break")
textWidget.bind("<Key>", lambda e: "break")
seems to do the trick. This is how I disabled my "line numbers" Text widget in a text editor. The first line is the more powerful one. I'm not sure the second is needed, but it makes me feel better having it there. :)
This can also be done in Frames
from tkinter import *
root = Tk()
area = Frame(root)
T = (area, height=5, width=502)
T.pack()
T.insert(1.0, "lorem ipsum")
T.config(state=DISABLED)
area.pack()
root.mainloop()
You could use a Label instead. A Label can be edited programmatically and cannot be edited by the user.
I asked a question yesterday explaining a basic calculator I was making. So far, I haven't been able to get text to display AT ALL in a text widget. This is what I'm using:
text = Tk()
ans_text = Text(text, width=40, height=10)
ans_text.pack
ans_text.insert("1.0", 0, 'test')
mainloop()
That's just something from effbot with modified variables. I haven't bothered to create any classes or define functions, except for the mathematical functions used in this "calculator." I don't exactly see the need to.
So how can I get text to display? I've just seen stuff about making a canvas and I don't really understand that. I just went some letters and numbers to show up :P
The text (a zero) is being inserted, but the widget isn't visible which is why you aren't seeing it. You are forgetting the () when trying to pack the widget. Change the pack statement to look like this:
ans_text.pack()
With that modification your code will insert a zero as the first character of the text widget and apply the tag text to that character.
Whenever something doesn't appear the way you expect, a really good first thing to try is to temporarily give the widget a distinctive color. It will then become obvious whether the widget isn't working the way you want (eg: text isn't being inserted), or it's working the way you want but it's not visible on the screen.
I've written a Python program for a friend's business, and am using Tkinter for the interface. Up until now, all features have been added in the main program window, but I'm now adding a print feature, have created a simple "File" menu, and want to add a "Print" entry to that menu, including displaying the relevant keyboard shortcut.
On my Mac, I want the shortcut to be Command-P. I found the Mac "command" symbol's Unicode value, and have tried various ways to create an accelerator string that simply concatenates that symbol and the letter "P", but nothing works. I get either the symbol or the letter to display in the menu next to "Print", but never both.
Here is the full line of code that adds the menu item, with the latest attempt at building the string (I believe I found this unicode.join option elsewhere in Stack Overflow):
sub_menu.add_command(label="Print", command=self.print_, accelerator=unicode.join(u"\u2318", u"P"))
// Only the "P" displays
Here are some of the other options that I've tried (lines truncated for clarity). With each of these options, only the "command" symbol appears:
accelerator=u"\u2318\u0050"
accelerator=u"\u2318" + "P"
accelerator=u"\u2318" + u"P"
accelerator=u"\u2318P"
accelerator=u"".join([u"\u2318", u"P"])
Up until now I haven't had a need to learn much about Unicode strings, so perhaps there's something I'm doing wrong in that regard. However, all of the attempts that I've made have come as a result of various searches, both here and elsewhere, and so far nothing has worked. Any insight into how to make this work would be most welcome!
Python 2.7.3, Mac OS X 10.8.3
After further searching online, I finally found a page that has the solution. I was surprised (and a touch annoyed) that this solution was different than the one outlined in the PDF documentation for Tkinter 8.4 that I've been referencing thus far (the one published by New Mexico Tech). I found links to Tkinter 8.5 documentation, but they also list the incorrect process.
Anyway, it's a lot simpler than I thought, and is similar to the syntax used for key binding, but slightly different. Instead of directly including the command symbol in the accelerator string, Tkinter takes the literal word "Command" (or the abbreviated "Cmd"), and internally converts it to the displayable character "⌘" in the menu. So my resulting line is:
sub_menu.add_command(label="Print", command=self.print_, accelerator="Command-P")
...and what I get in my full menu item is:
Print ⌘P
As the page linked above shows, similar shortcut words exist for other modifier keys, and on Mac OS X, these are all automatically translated into their graphical equivalents.
It was actually really easy, all I did was use string formatting to concatenate text="%s%s" % (u"\u2318","P")
Here is a sample Tkinter App, the display is small but it shows what you need.
import Tkinter as tk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.label = tk.Label(text="%s%s" % (u"\u2318","P"))
self.label.pack(padx=10, pady=10)
app = SampleApp()
app.mainloop()
Output:
⌘P
How would i go about locking a Text widget so that the user can only select and copy text out of it, but i would still be able to insert text into the Text from a function or similar?
Have you tried simply disabling the text widget?
text_widget.configure(state="disabled")
On some platforms, you also need to add a binding on <1> to give the focus to the widget, otherwise the highlighting for copy doesn't appear:
text_widget.bind("<1>", lambda event: text_widget.focus_set())
If you disable the widget, to insert programatically you simply need to
Change the state of the widget to NORMAL
Insert the text, and then
Change the state back to DISABLED
As long as you don't call update in the middle of that then there's no way for the user to be able to enter anything interactively.
Sorry I'm late to the party but I found this page looking for the same solution as you.
I found that if you "disable" the Text widget by default and then "normal" it at the beginning of a function that gives it input and "disable" it again at the end of the function.
def __init__():
self.output_box = Text(fourth_frame, width=160, height=25, background="black", foreground="white")
self.output_box.configure(state="disabled")
def somefunction():
self.output_box.configure(state="normal")
(some function goes here)
self.output_box.configure(state="disable")
I stumbled upon the state="normal"/state="disabled" solution as well, however then you are unable to select and copy text out of it. Finally I found the solution below from: Is there a way to make the Tkinter text widget read only?, and this solution allows you to select and copy text as well as follow hyperlinks.
import Tkinter
root = Tkinter.Tk()
readonly = Tkinter.Text(root)
readonly.bind("<Key>", lambda e: "break")
I am re designing a portion of my current software project, and want to use hyperlinks instead of Buttons. I really didn't want to use a Text widget, but that is all I could find when I googled the subject. Anyway, I found an example of this, but keep getting this error:
TclError: bitmap "blue" not defined
When I add this line of code (using the IDLE)
hyperlink = tkHyperlinkManager.HyperlinkManager(text)
The code for the module is located here and the code for the script is located here
Anyone have any ideas?
The part that is giving problems says foreground="blue", which is known as a color in Tkinter, isn't it?
If you don't want to use a text widget, you don't need to. An alternative is to use a label and bind mouse clicks to it. Even though it's a label it still responds to events.
For example:
import tkinter as tk
class App:
def __init__(self, root):
self.root = root
for text in ("link1", "link2", "link3"):
link = tk.Label(text=text, foreground="#0000ff")
link.bind("<1>", lambda event, text=text: self.click_link(event, text))
link.pack()
def click_link(self, event, text):
print("You clicked '%s'" % text)
root = tk.Tk()
app = App(root)
root.mainloop()
If you want, you can get fancy and add additional bindings for <Enter> and <Leave> events so you can alter the look when the user hovers. And, of course, you can change the font so that the text is underlined if you so choose.
Tk is a wonderful toolkit that gives you the building blocks to do just about whatever you want. You just need to look at the widgets not as a set of pre-made walls and doors but more like a pile of lumbar, bricks and mortar.
"blue" should indeed be acceptable (since you're on Windows, Tkinter should use its built-in color names table -- it might be a system misconfiguration on X11, but not on Windows); therefore, this is a puzzling problem (maybe a Tkinter misconfig...?). What happen if you use foreground="#00F" instead, for example? This doesn't explain the problem but might let you work around it, at least...