grouping elements in tkinter - python

Is there a way to group elements in tkinter under single ID?
For example, if I want an 'S' with a line striking through it. Is there a way to store both the line and the character under the same id?
Alternatively, is there a way to create a costume (simple) shapes for tkinter?
Edit:
I wish to do this on a canvas widget

Tkinter Canvas objects do allow you to create "simple" objects (anything you can draw using canvas items. Then you can group your objects together using tags.

If you are specifically asking for text with an overstrike, you can create a custom font that has the overstrike attribute set.
In a more general sense, you cannot have one id shared between two objects on the canvas, but you can have two objects share the same tag, and tags can be used just about anywhere an id can be used (ie: for changing colors, coordinates, deleting, etc)

Related

How to make multiple Fonts in one string, python, tkinter

In Tkinter, I would like to have different fonts in one Label.
So, the practical case is this: I have a Text Widget and in the text widget there is a bunch of Labels, each containing three lines: Title, Duration - Channel, and Description.
I would like to make the Title stand out by making it bold. Can this be done? So far I didn't find information that helped me out, and in the past I encountered the issue and didn't manage to find a solution.
I would prefer not to have 3 labels, because I have nice borders around the label. It would really complicate things.
Of course, I don't mind a bit of complication if it is necesary, but if it is unnecesary, then that would be nice. It seems like it should be normal functionality, like some tags or so.
You can't use more than one font in a label. If you need multiple fonts you'll have to use a Canvas or a Text widget, or combine multiple labels inside a frame. Arguably, the simplest solution will be a three line text widget.

Create and align non-rectangular widgets together with PyQt6

I need to create a widget/layout, which will contain a number of non-rectangular, clickable widgets that are well aligned together so that they create a whole (picture below).
Each of theses widgets needs to be clickable and have a hover option. I thought of using QAbstractButton or QPushButton class and overriding it's paintEvent to draw it with a particular size and shape, but I don't know if this is a optimal solution. I also have no idea how I could then align these widgets together so that there are no empty spaces between them. I thought of using some absolute position of a parent Window and manually adjust child widgets position based on that.

Adding a vertical bar or other marker to tkinter Text widgets at a particular column

My intention is to add a vertical bar to IDLE to indicate preferred line length at column 80.
I have tried to find a configuration option for the Text tkinter widget that would allow this but have found nothing.
I was hoping it would be a simple configuration option so I could just add a another item the text_options dictionary within EditorWindow.py found within Python\Lib\idlelib.
I am not sure how styles/themes work but do they have the capability to change the background colour of only 1 column in a Text widget?
Outline of possible solution:
Create a 1-pixel wide Frame, with a contrasting background color, as a child of the Text.
Use .place() to position the Frame at an appropriate horizontal coordinate.
Possible issues:
I don't see any easy way to get the coordinate for a particular column. Text.bbox("1.80") looks promising, but doesn't work unless there actually are 80 characters in the line already. You may have to insert a dummy 80-character line at first, call update_idletasks to get the Text to calculate positions, call bbox to get the coordinates, then delete the dummy text. Repeat whenever the display font is changed.
The line would necessarily appear on top of any text or selection region, which isn't quite the visual appearance I'd expect for a feature like this.

Tkinter form with multi-line labels?

I'm building a generic, data-driven Tkinter form. Each row has a label on the left and an input field on the right. With simple test data, it works to use a Label for the label text -- but when the desired label text is longer than the Label field, it simply truncates.
Once the form has been built, I won't need to vary the label text dynamically: the text will be known at construction time. But I don't know the universe of possible label strings. I want the form to accommodate longer label text by word-wrapping the label to multiple lines, expanding vertically. This should of course expand the row in which the label is embedded.
Per Create resizable/multiline Tkinter/ttk Labels with word wrap, I presume I should use a Text widget for word wrapping and disable it as an input field. But I don't know how to constrain it horizontally (to engage the word wrapping) while expanding it to exact size vertically.
In other words, the processing sequence should go something like this:
Determine the overall width of the parent.
Allocate the width of the Text field relative to the parent. (I imagine I would use grid_columnconfigure(weight=), but am happy to entertain suggestions.)
Word-wrap the Text contents to fit its width.
Vertically expand the Text block to display all lines.
Propagate the vertical size outward to the parent.
This may have a straightforward answer that would become apparent once I better understand the workings of Tkinter geometry managers in general and Grid in particular. I've read http://effbot.org/tkinterbook/grid.htm and http://effbot.org/tkinterbook/pack.htm without yet having a big "Aha!" moment. I'd be grateful for reference material that addresses this kind of issue as well.
Thanks for any help!
You are looking for the Message widget:
The Message widget is a variant of the Label, designed to display multiline messages. The message widget can wrap text, and adjust its width to maintain a given aspect ratio.
If you want fancy things like multiple fonts, you'll need to move to a Text widget. If you just want a longer version of a Label, though, Message is a good choice.

How to clear Tkinter Canvas?

When I draw a shape using:
canvas.create_rectangle(10, 10, 50, 50, color="green")
Does Tkinter keep track of the fact that it was created?
In a simple game I'm making, my code has one Frame create a bunch of rectangles, and then draw a big black rectangle to clear the screen, and then draw another set of updated rectangles, and so on.
Am I creating thousands of rectangle objects in memory?
I know you can assign the code above to a variable, but if I don't do that and just draw directly to the canvas, does it stay in memory, or does it just draw the pixels, like in the HTML5 canvas?
Every canvas item is an object that Tkinter keeps track of. If you are clearing the screen by just drawing a black rectangle, then you effectively have created a memory leak -- eventually your program will crash due to the millions of items that have been drawn.
To clear a canvas, use the delete method. Give it the special parameter "all" to delete all items on the canvas (the string "all"" is a special tag that represents all items on the canvas):
canvas.delete("all")
If you want to delete only certain items on the canvas (such as foreground objects, while leaving the background objects on the display) you can assign tags to each item. Then, instead of "all", you could supply the name of a tag.
If you're creating a game, you probably don't need to delete and recreate items. For example, if you have an object that is moving across the screen, you can use the move or coords method to move the item.
Items drawn to the canvas are persistent. create_rectangle returns an item id that you need to keep track of. If you don't remove old items your program will eventually slow down.
From Fredrik Lundh's An Introduction to Tkinter:
Note that items added to the canvas are kept until you remove them. If
you want to change the drawing, you can either use methods like
coords, itemconfig, and move to modify the items, or use delete to
remove them.
Yes, I believe you are creating thousands of objects. If you're looking for an easy way to delete a bunch of them at once, use canvas tags described here. This lets you perform the same operation (such as deletion) on a large number of objects.

Categories