I'm using a Gtk.Label within a tooltip to display text. The text is usually rather short, but does occasionally become very long, in which case the label expands horizontally to fill the entire screen width, which results in a ridiculously wide tooltip. Is there a way to force the label's text into more lines?
I had two ideas:
1) set the label's maximum width. Gtk doesn't seem to support this.
2) set the label's maximum line length. Gtk doesn't seem to support this either.
Which means I'm fresh out of ideas. Is there any way to do this?
Use gtk.Label.set_line_wrap combined with gtk.Label.set_max_width_chars.
Example:
label.set_line_wrap(True)
label.set_max_width_chars(20)
Related
I'm attempting to adapt martineau's excellent answer on how to use tkinter to highlight and select an area of an image with a mouse. My goal is to modify the code to support huge images, such as 10000x6000 pixels or more!
This is my first attempt at using tkinter, and it's much more challenging than expected.
The three options which I've considered and experimented with are:
Load the image, then scale the image to the size available in the window before placing it on the canvas. This in turn requires that I know the scale factor, so I can reverse the scaling when operating on the original image.
Add scrollbars to the side/button on the visible part of the image in the canvas. (My preferred option).
Don't add scrollbars, but use the cursor keys to scroll the visible part of the image in the canvas.
I've tried to do all of them, but ran into various kinds of trouble:
I used root.state('zoomed') to maximize the window, then placed a button to top of the window using tk.Button(...).pack(fill=tk.X) before placing the canvas as in the linked code using self.canvas = tk.Canvas(...). At this time I discovered two issues: It turns out that I can't maximize the canvas to the remaining space in the window using self.canvas.pack(fill=tk.BOTH) (it only expands the width). Another more crucial issue was that I could not read the actual width/height value that the canvas was expanded to, (or get there available space in the window before placing the canvas), and without these values, I can't calculate the scaling factor. :-(
I tried to follow various methods of adding scrollbars to the packed canvas but they all, with one exception, required to use the grid method and I quickly found that pack and grid methods were conflicting methods. After several attempts at rewriting the code to use the grid method, I gave up. The place method seemed promising, except that it will require me to size the canvas manually and then place the scrollbars at calculated offsets to the canvas... and all of this required that I have the same values that were needed to calculate the scaling factor above. :-(
I didn't get very far with this, as it seems I can't get (keyboard?) binds to work at all (On windows with Python 3.10.6). Shouldn't something like self.canvas.bind("<Right>", lambda event: print("Ping")) followed by self.canvas.focus_set() (perhaps with root instead of the canvas) work?
I'm sure I'm overlooking something basic, but after a few evenings looking at this I've gotten nowhere. :-(
I hope some of you can provide help and/or pointers allowing me to get further.
Ohh, for completeness, I'm trying to hack together a small tool that does the following:
On startup requests and load an image file. (Adding a button to perform the load/re-load is nice to have, but not strictly needed. )
Display the image file and allow an area of the image to be selected with the mouse.
Perform some software analysis on the selected part of the image when a button is pressed.
I am new to Tkinter and still learning. My desktop resolution is 1366x768 and I am developing for an environment which is 2048x768. Right now I am setting the window resolution by detecting it like this -
w = main_container.winfo_screenwidth()
h = main_container.winfo_screenheight()
main_container.geometry(str(w) + "x" + str(h))
Now I have several screens and I cannot use grid on each and every screen. Like I have a Login Screen in which I have a Frame like this-
self.frame_background = tk.Frame(self.frame_parent, bg='#ffffff')
self.frame_background.pack(fill='both', expand=True, padx=100,
pady=100)
This is just an example of one widget. Since values for padx and pady are fixed with 100, if I am running my application on a 640x480 resolution device, the layout gets too stretched and almost nothing is visible inside this frame.
How can I set these padx and pady and other width and height values dynamically according to the screen size and resolutions?
Now I have several screens and I cannot use grid on each and every screen.
Why can't you? There's nothing preventing you from using grid on every screen. Though, it's actually quite common to mix and match pack and grid in different frames, and arguably a best practice.
Like I have a Login Screen in which I have a Label like this...
The code following that statement doesn't have a Label, so it's hard to know what you are trying to do.
if I am running my application on a 640x480...
First you say you have a desktop resolution of 1366x768, then say you are targeting 2048x768, and are now asking about 640x480. That's a pretty wide range of values. If you have to support something as low as 640x480 you definitely should not be hard-coding padding to such huge values. Typically padding is never more than one or two. Tkinter apps can be made to accommodate that wide range of screen sizes, but that relies on not hard-coding the size of widgets and padding as much as possible.
How can I set these padx and pady and other width and height values dynamically according to the screen size and resolutions?
Generally speaking, you shouldn't do that. The general rule of thumb with tkinter is that you make the widgets the smallest size they need to be and let the geometry managers worry about stretching or shrinking them to fit the available space. There are a few exceptions to that rule, but in general, that rule works quite well.
Unfortunately, geometry management questions are hard to answer without knowing more about what you're trying to do. For example, we need to know why you think you need padding of 100 pixels. That seems highly unusual. Plus, we need to know what else is in your frame, what your frame is in, and so on.
My advice is to remove the padding, or set them to very small values. Then, make sure you use all of the geometry manager options that are available to you, such as fill and expand with pack, and sticky and others for grid.
I've been working on a project where I use Separators and I've just can't find out how I make them thicker!
this is the code for it I've got at the moment:
tkinter.ttk.Separator(master, orient=VERTICAL).grid(column=1, row=1, rowspan=4, sticky='ns')
so how do I make the Separator thicker/wider?
ps. The code is only a small part of my project
The ttk separator widget isn't designed to be modified in that way. Part of the point of the themed (ttk) widgets is that they adhere to a common theme and thus can't be customized.
You can use a an empty frame widget, which allows you to set the width, height, border style, color, etc.
Even though it apparently goes against the "theme" of tkinter, as pointed out by Bryan, I wanted to do this too.
The solution I found is simply stack multiple separators. If you're using grid geometry manager, you'll need to provide extra rows or columns to fit as many separators as necessary. For me, three separators did the trick, and aesthetically, I didn't find it offensive in any way:
ttk.Separator(master=root,orient='vertical').grid(row=0,column=11,rowspan=2,sticky='ns')
ttk.Separator(master=root,orient='vertical').grid(row=0,column=12,rowspan=2,sticky='ns')
ttk.Separator(master=root,orient='vertical').grid(row=0,column=13,rowspan=2,sticky='ns')
But as Bryan suggests, you can use an empty Frame widget. Example code for that can be found here:
https://stackoverflow.com/a/68179426/7759839
I am trying to achieve the following effect using a Tkinter python app:
The user can define a finite number of list elements, aka categories.
I then would like to present these categories next to each other, based on the following approach:
l=Label(self.body,text='Category: ')
l.pack(side=Left)
for i in range(0,len(self.categories)):
l=Label(self.body,text=self.category[i])
l.pack(side=LEFT)
self.body.pack(fill=BOTH)
Of course, this does not work. Is there an elegant way to "wrap" a whole label at the widget borders?
Thanks!
You have to know the size of the frame you are using to pack the labels into, and the width of the label. You can set the width parameter for the label, but it uses a size that depends on the font used i.e. the same "width=" results in different label widths for different font sizes. So it can not be done with the code you posted. Link to label parameters http://effbot.org/tkinterbook/label.htm
I'm writing an e-book reader in Python + wxPython, and I'd like to find out how many lines of text can be displayed in a given RichTextCtrl with the current formatting without scrolling.
I thought of using and dividing the control's height by RichTextCtrl.GetFont().GetPixelSize(), but it appears that the pixel size parameter of wx.Font is only specified on Windows and GTK. In addition, this won't cover any additional vertical spacing between lines/paragraphs.
I could of course get the font size in points, attempt to get the display's resolution in ppi, and do it that way, but 1) the line spacing problem still remains and 2) this is far too low a level of abstraction for something like this.
Is there a sane way of doing this?
EDIT: The objective is, to divide the ebook up into pages, so the scrolling unit is a whole page, as opposed to a line.
Source code of PageDown method suggest that there is not a sane way to do this...
Here is my insane proposition (which breaks widget content, caret, displayed position...) which scroll one page and measure how long this scroll is...
def GetLineHeight(rtc):
tallString = "\n".join([str(i) for i in xrange(200)])
rtc.SetValue(tallString)
rtc.SetInsertionPoint(0)
rtc.PageDown()
pos = rtc.GetInsertionPoint()
end = tallString.find("\n",pos)
lineHeight=int(tallString[pos:end])
return lineHeight
Did you try calling the GetNumberOfLines() method? According to Robin Dunn, that should work, although it doesn't take wrapped lines into account.