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
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'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)
Is it possible to apply partial borders (e.g. a border on only the right-hand edge, or on only the top and the bottom) to an element in Python Tkinter?
EDIT: This is the layout I'm trying to achieve - if anyone can see a better way of achieving this than partial borders, please feel free to point it out - I'm not very experienced with Tkinter!
The answer to your question depends on what you mean by "borders". Individual widgets have borders (buttons, etc), and for those you can't change just part of the border.
If instead you're asking about how to layout your widgets so that there are dividing lines between them, you can do this with the padx and pady options of grid and pack. For those you can have different amounts of padding on each edge.
There is no way to this built in to tkinter, but why do you need this behaviour? There is probably a better way to accomplish what you need. See this this resource for more help with your problem.
Is there any way to customize the border color of a Tkinter/ttk widgets or frames?
Yes, you can create your own style and apply it to the widget or configure the attributes of an existing style.
Some documentation and examples are in the official docs, specifically the section about ttk.Style.
Additional information on using styles (for several languages) can be found at tkdocs.com.
Regarding a border on ttk.Frames: in lieu of styles, the best I can think of is to insert a ttk.Frame within a ttk.Frame. The outer frame would use a standard "background" property with the border color of choice, and a padding equal to the desired border thickness. The inner frame then obscures the middle, so you have a line only around the edges. Works, but seems a little bit hacky (and a bit less wieldy if you're creating many widgets/borders).
I've searched quite a bit and haven't found or figured out a way to use a style to change a ttk.Frame's border color. Using something like style.configure( 'SeletectedItem.TFrame', highlightcolor='#78F', highlightthickness=2 ) or style.configure( 'SeletectedItem.TFrame', highlightbackground='#78F', highlightcolor='#78F', highlightthickness=2, borderwidth=2 ) (config options that work on a regular Tk.Frame) doesn't seem to do anything. With style.layout() I find just [('Frame.border', {'sticky': 'nswe'})], and from style.element_options('TFrame.border') there is just ('-relief',). I don't know if I'm using the wrong option names or syntax (or what options are available for .configure() for different widget classes), or if this just isn't possible with styles. I'm interested if anyone has extra info or knows if this can be done.
I want to put a Canvas with an image in my window, and then I want to pack widgets on top of it, so the Canvas acts as a background.
Is it possible to have two states for the pack manager: one for one set of widgets and another for another set?
The answer to your specific question is no. You can't have two states or otherwise use pack two different ways in the same parent.
However, what I think you want to accomplish is simple. Use the built-in features of the canvas to create an image item that is part of the canvas, then pack things into the canvas as if it were a frame.
You can accomplish a similar thing by creating a label widget with an image, then pack your other widgets into the label.
One advantage to using a canvas is you can easily tile an image to fill the whole canvas with a repeating background image so as the window grows the image will continue to fill the window (of course you can just use a sufficiently large original image...)
I believe that Bryan's answer is probably the best general solution. However, you may also want to look at the place geometry manager. The place geometry manager lets you specify the exact size and position of the widget... which can get tedious quickly, but will get the job done.
... turned out to be unworkable because I wanted to add labels and more canvases to it, but I can't find any way to make their backgrounds transparent
If it is acceptable to load an additional extension, take a look at Tkzinc. From the web site,
Tkzinc (historically called Zinc) widget is very similar to the Tk Canvas in that they both support structured graphics. Like the Canvas, Tkzinc implements items used to display graphical entities. Those items can be manipulated and bindings can be associated with them to implement interaction behaviors. But unlike the Canvas, Tkzinc can structure the items in a hierarchy, has support for scaling and rotation, clipping can be set for sub-trees of the item hierarchy, supports muti-contour curves. It also provides advanced rendering with the help of OpenGL, such as color gradient, antialiasing, transparencies and a triangles item.
I'm currently using it on a tcl project and am quite pleased with the results. Extensions for tcl, perl, and python are available.
Not without swapping widget trees in and out, which I don't think can be done cleanly with Tk. Other toolkits can do this a little more elegantly.
COM/VB/MFC can do this with an ActiveX control - you can hide/show multiple ActiveX controls in the same region. Any of the containers will let you do this by changing the child around. If you're doing a windows-specific program you may be able to accomplish it this way.
QT will also let you do this in a similar manner.
GTK is slightly harder.