I have run into a strange behaviour of Tkinter's Message widget. It worked fine before, but now it is wrapping (Date and time on left image, only date on right image) when it shouldn't. I noticed time wrapped for some seconds and others not, because not all characters are the same length.
Note that the images are cropped, but the widget actually continues about 200 more pixels. I have not set wraplength (which weirdly enough wasn't even recognised as an option, even though it is in the docs) so that is still at its default 0 (no wrapping). I have played around a bunch but I can't figure it out.
The text is generated from a dictionary, roughly as follows:
import tkinter as tk
root = tk.Tk()
root.geometry('500x500+0+0')
root.configure(bg='white')
desc = tk.Message(root)
desc.configure(bg='white')
desc.pack()
description={}
description['Date'] = '11 June 2020'
description['Time'] = '21:26:26'
description['Duration'] = 0
description['Overlay'] = str(False)
descToLines = [f'{key}:\t {val}' for key, val in description.items()]
linesToString = '\n'.join(descToLines)
desc.configure(text=linesToString)
root.mainloop()
In fact, while verifying this minimal code, the time line 21:26:38 is now inline with Time, but the date still isn't. Any help is welcome.
And here is how you can see what is missing: change the background color of the Message box to another color. You'll immediately see that its width is too small. Try:
desc.configure(bg='#FF0000')
And then:
desc.configure(bg='#00FF00', width=200)
Which gives:
As per suggestion I set the Message's width manually and it resolved the problem. What is confusing me is that I thought it would already be set using the line:
desc.place(x=0, y=0, height=0, width=300), but apparently not. At least not so far as to override the aspect ratio.
Tl;dr: Adding desc.configure(width=300) at the end fixes the problem.
Related
None of the tkinter Scales I've made show tickmarks.
I tried pasting other people's code into my editor and same result, no ticks. The example is utterly simple so I couldn't think of anything to try except different values for the tickinterval option. I'm using tkinter 8.6 with python 3.5. Thanks for any assistance.
import tkinter as tk
root = tk.Tk()
flt = tk.Scale(
root,
label="No Ticks",
from_=50.0,
to=200.0,
length=900,
orient="horizontal",
resolution=25,
tickinterval=50.0)
flt.grid()
root.mainloop()
There are no error messages and everything else seems to work.
The option tickinterval does not refer to tick marks but to the numbers displayed along the Scale.
Once this was pointed out by Bryan Oakley in the comments, I was able to glean the following information from running simple examples, which I had not found in the docs. Basically, the resolution option and the tickinterval option values need to be considered together for both to work as desired.
tickinterval
Using the default value of zero, the only number shown will be the one which names the position of the slider. Otherwise the tickinterval will be the distance apart of numbers marking positions on the Scale. To be sure tickintervals will be displayed as desired, this should be set to an even multiple of resolution e.g. if resolution = 100, tickinterval should be 200
or 300 etc. If resolution is set to 0 or -1, tickinterval will display at any increment desired.
I'm trying to add a Tk.Scale widget to my application, but I have a problem with setting non-integer value to the resolution parameter. If I pass an integer value to Scale constructor, it works correctly, but with any non-integer value (say 0.1) my scale widget does not move. It appears at the right place and looks just fine, but doesn't respond to my attempts to move it.
Here is my code related to the creation of scale widget:
self.sliderValue = Tk.DoubleVar()
self.slider = Tk.Scale(self.frame,
from_=float(self.lowerValue.get()),
to=float(self.upperValue.get()),
orient=Tk.HORIZONTAL,
length=180,
variable=self.sliderValue,
resolution=0.1, # Here is the problem
command=self.sliderMoved)
The problem is I can not reproduce this issue outside of my application. In other words, if I create just a simple window with one scale widget, it works with any resolution values. So it seems that the problem is hidden somewhere outside of this constructor call, but I can not figure out where. May be someone had the same problem and can advise me what should I check.
Addition:
May be it is important: in standalone (working) case the value above the slider is in "1.0" format (with the dot as the separator), and in my broken application it is "1,0" format (with the comma as the separator). May by some kind of type/format mismatch is happening here.
Addition 2:
Here is minimal example:
import Tkinter as Tk
from pylab import *
# cla() # if you uncomment these two lines,
# clf() # scale will break for non-int resolutions
root = Tk.Tk()
var = Tk.DoubleVar()
scale = Tk.Scale(root, from_=6.0, to=8.5, variable = var,
resolution=0.1, orient=Tk.HORIZONTAL)
scale.grid(column=0, row=0, columnspan=3)
root.mainloop()
I've just updated to Ubuntu 16.04 and it seems that this problem does not appears anymore (Python 2.7.11+).
Currently I'm using this snippet of code which seems pretty easy:
label = ttk.Label(mainframe)
image1 = PhotoImage(file='my_image.gif')
label['image'] = image1
label.grid(column=1, row=0)
However, if I edit the size of my_image.gif in photoshop, then run it again, the image gets stretched to the same size, and this seems to continue no matter how small I make the base image. This seems to suggest to me that the PhotoImage or something above it enforces a default size or specific minimum size. I cannot find any documentation to suggest that this is the case.
From here I found the help(PhotoImage) suggestion which I used. When in the python interpreter I run the help(PhotoImage) command and I found this:
height(self)
Return the height of the image.
type(self)
Return the type of the imgage, e.g. "photo" or "bitmap".
width(self)
Return the width of the image.
But it doesn't seem to provide me with an image sizing of any type either.
After searching all over and seeing no reference at all, i'm beginning to suspect that using images in a Label is for a specific purpose and I'm approaching this all wrong. All i'm trying to do is place a logo at the top of the window, but I want the logo to be limited in size so it doesn't take over the whole window.
Also of note is this question which seems to be lacking an answer but I too am curious if there is some documentation on it. Maybe I'm missing something obvious but I did check the python documentation and the http://www.tkdocs.com site for more information.
Apparently I made an error, but I have no clue what it was. In the end this was this code that did it for me:
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("ImageTest")
label = ttk.Label(root)
image1 = PhotoImage(file='my_image.gif')
label['image'] = image1
label.grid(column=1, row=0)
root.mainloop()
It's all working now as expected.
I've been tinkering around with Python lately and wanted to make a GUI that reads from a CSV and displays it correctly.
CSV build up:
name,description,image location
steven,some guy,/res/pic/steven.gif
the first two entries should be put in text labels, and the last entry should be used as an image.
In my code I got as far as inserting the picture, which worked. But as soon as I also embedded the text label, I think the application runs into an infinity loop.
If I delete the Image from the code, the text label works and vice versa.
from Tkinter import *
from PIL import *
import os
import csv
#Functions
def insertImage(guiName,picture,x,y):
#This is the Image label insertion, delete it and Text label works
img = PhotoImage(file=entryList[picture][2])
preview = Label(guiName, image=img)
preview.img = img
preview.grid(row=x,column=y)
#This is the Text label insertion, delete it and Image Label works
Name = StringVar()
labelName = Label(mainGUI, textvariable=Name, justify=LEFT)
Name.set(entryList[picture][2])
labelName.pack()
global mainGUI
mainGUI = Tk()
mainGUI.geometry("500x500")
mainGUI.title('Index')
reader = csv.reader(open("res/test.csv", "rb"))
entryList = []
for row in reader:
entryList.append( row )
#insertImage(mainGUI,entryList[1][2],1,1)
insertImage(mainGUI,1,1,1)
#insertImage(mainGUI,2,2,1)
mainGUI.mainloop()
Does anyone have an idea what the problem might be?
The problem is that you are using grid() and pack() to position widgets within the same master widget (mainGUI). That won't work, because by default both of those geometry managers attempt to manage the size of the parent widget and end up fighting over the size (which blocks the GUI from ever appearing as a side effect).
The very latest version of Tk (the lib underneath Tkinter) will throw an error if you try to do this (finally!) but your best bet is to just use one geometry manager per parent widget. (There are some subtleties with disabling geometry propagation which can make this work, and “parent” can be a touch tricky in a few situations, but the key issue is that you're doing the wrong thing in the first place.)
Also, a single label can contain both an image and some text; see the compound option (which enables this and controls the relative placement rules).
I have a label sitting on a frame which is updated periodically to show the status of the application. Periodically, the name of the item being processed will not fit into the window, and with the way I currently have the label configured the window expands to accomidate the label.
Ideally, I'd like way to smartly truncate the text on the label (and then expand if someone expands the window). Is there an easy way to accomplish this?
Practically speaking, how can I just stop the window to expanding based on changes to text in the label?
Edit:
This is an aproximation of the code I'm working on that is not exhibiting the desired behavior (there is a link at the bottom to the actual code file):
r = tk.Tk()
statusFrame = tk.Frame(r, relief=tk.SUNKEN, borderwidth=2)
statusFrame.pack(anchor=tk.SW, fill=tk.X, side=tk.BOTTOM)
statusVar = tk.StringVar()
statusVar.set("String")
tk.Label(statusFrame, textvariable=statusVar).pack(side=tk.LEFT)
statusVar.set("this is a long text, window size should remain the same")
Actual code available here.
The answer depends very much on the way you currently have configured the widget.
For example, I can get the desired functionality as such:
>>> import Tkinter as tk
>>> r=tk.Tk()
>>> r.title('hello')
''
>>> l= tk.Label(r, name='lbl', width=20, text='reduce the window width')
>>> l.pack(fill=tk.BOTH) # or tk.X, depends; check interactive resizing now
>>> l['text']= "This is a long text, window size should remain the same"
Tell us what you do in your code for a more precise (appropriate for your code) answer.