issue192:python
Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
issue192:python [2023/04/30 07:40] – d52fr | issue192:python [2023/05/04 15:00] (Version actuelle) – andre_domenech | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
- | **Over the years, I've talked about various aspects of the Tkinter toolkit that is a part of Python. | + | **Over the years, I've talked about various aspects of the Tkinter toolkit that is a part of Python. Tkinter is a wrapper to the Tk/ttk toolkit that is a part of Tcl. For the most part Tkinter has kept up with the updates of Tk/ttk. |
- | Using the Tkinter toolkit provides almost anything you would need to create a GUI for your Python programs. | + | Using the Tkinter toolkit provides almost anything you would need to create a GUI for your Python programs. I say almost because there are a few things missing, like a really good spreadsheet widget and a terminal widget. There are third party widgets that will, with a fair amount of work, will do the job, but those things that are missing from the " |
Anyway, rather than dwelling on the missing parts, we should celebrate what is there. | Anyway, rather than dwelling on the missing parts, we should celebrate what is there. | ||
- | In my mind, there are two widgets that are extra useful because of the large number of things that can be done with them. The first is the Canvas widget. | + | In my mind, there are two widgets that are extra useful because of the large number of things that can be done with them. The first is the Canvas widget. Not only can the Canvas widget draw lines, arcs, text and other things, it can also hold images and can be a container for other widgets. The other is the Text widget, which is the subject of this month' |
- | **Anyone who is used to creating GUIs knows that there are two " | + | Au fil des ans, j'ai parlé de divers aspects de la boîte à outils Tkinter qui fait partie de Python. Tkinter est un wrapper de la boîte à outils Tk/ttk qui fait partie de Tcl. Pour l' |
+ | |||
+ | L' | ||
+ | |||
+ | Quoi qu'il en soit, plutôt que de s' | ||
+ | |||
+ | Selon moi, deux widgets sont particulièrement utiles en raison du grand nombre de choses que l'on peut faire avec eux. Le premier est le widget Canvas. Il permet non seulement de dessiner des lignes, des arcs, du texte et d' | ||
+ | |||
+ | **Anyone who is used to creating GUIs knows that there are two " | ||
Tk Text Widget | Tk Text Widget | ||
Not only can the Text widget handle simple text display and entry, there is a lot more that it can do. | Not only can the Text widget handle simple text display and entry, there is a lot more that it can do. | ||
- | • | + | • Mix text with different fonts, colors and backgrounds. |
- | • | + | • Embed images along with the text. |
- | • | + | • The Text widget can contain invisible mark objects. |
- | • | + | • Handle special display handling through a process called tags. |
- | • | + | • Bind events to a tagged region. |
- | • | + | • Embed any of the Tk widgets within a “window”. This includes a Tk Frame that contains other widgets. |
- | In order to help show some of these features, I threw together a small demo. You can get the source code from my repository (see the end of the article). | + | In order to help show some of these features, I threw together a small demo. You can get the source code from my repository (see the end of the article). |
The image shown left is what the demo looks like when run.** | The image shown left is what the demo looks like when run.** | ||
- | **You can see many of the features “in action” in the image. | + | Toute personne habituée à créer des interfaces graphiques sait qu'il existe deux widgets « normaux » qui prennent en charge plusieurs lignes de texte : le widget Texte et le widget Message, qui font tous deux partie du jeu de widgets « standard » de Tk. Ces deux widgets permettent d' |
+ | |||
+ | Widget Tk Texte | ||
+ | |||
+ | Le widget Texte peut non seulement gérer l' | ||
+ | ••Mélanger du texte avec différentes polices, couleurs et arrière-plans. | ||
+ | ••Intégrer des images au texte. | ||
+ | ••Le widget Texte peut contenir des objets de marquage invisibles. | ||
+ | ••Gérer des affichages spéciaux par le biais d'un processus appelé « balises ». | ||
+ | ••Lier des événements à une zone étiquetée. | ||
+ | ••Intégrer n' | ||
+ | |||
+ | Afin de présenter certaines de ces fonctionnalités, | ||
+ | |||
+ | L' | ||
+ | |||
+ | |||
+ | **You can see many of the features “in action” in the image. At the bottom of the form, you can see location indicators, the left showing the Line and Column position of the cursor and on the right is the selection start and end positions. | ||
- | You can also see the use of tags in the Text widget. | + | You can also see the use of tags in the Text widget. There is a tag for Bold, Italic, Bold and Italic, Red foreground, Blue foreground and Green foregrounds. |
Indexes | Indexes | ||
- | Before we can get to the code, there are some basics that need to be understood. | + | Before we can get to the code, there are some basics that need to be understood. The first is the use of indices which specifies the position of the content in the Text widget window. The index is a string which can be in many different forms. |
+ | |||
+ | There are other index options, but they are rarely used. ** | ||
+ | |||
+ | L' | ||
+ | |||
+ | Vous pouvez également voir l' | ||
+ | |||
+ | Index | ||
+ | |||
+ | Avant d' | ||
+ | |||
+ | Il existe d' | ||
- | There are other index options, but they are rarely used. ** | ||
**Tags | **Tags | ||
- | In my opinion, Tags are the most useful feature of the Text widget. | + | In my opinion, Tags are the most useful feature of the Text widget. However, if your tag is to include a font, you must define the font before you define the tag. To define a font, you need to import the font module from tkinter. |
from tkinter import font | from tkinter import font | ||
- | Once you’ve done this, you can start to define the font. However, there are a few rules that need to be followed. | + | Once you’ve done this, you can start to define the font. However, there are a few rules that need to be followed. The most important rule is that if the font name (family) has a space, it must be enclosed not only in quotes, but also in curly brackets. If the font name is a single word, like “Arial”, |
+ | |||
+ | Balises | ||
+ | |||
+ | À mon avis, les balises sont la fonction la plus utile du widget Texte. Cependant, si votre balise doit inclure une police, vous devez définir la police avant de définir la balise. Pour définir une police, vous devez importer le module font de tkinter. | ||
+ | |||
+ | from tkinter import font | ||
+ | |||
+ | Une fois que vous avez fait cela, vous pouvez commencer à définir la police. Cependant, quelques règles doivent être respectées. La règle la plus importante est que si le nom de la police (famille) contient un espace, il doit être placé non seulement entre guillemets, mais aussi entre crochets. Si le nom de la police est en un seul mot, comme « Arial », il suffit de le mettre entre guillemets. L' | ||
- | **Once you have your font(s) defined, then you can start to define your tag(s). | + | **Once you have your font(s) defined, then you can start to define your tag(s). Of course, there is a caveat. There are MANY options available to a tag. The font is just one of the 19 options available. You can find the list of options at https:// |
Basically, the syntax is something like this… | Basically, the syntax is something like this… | ||
Ligne 48: | Ligne 93: | ||
.tag_config(tagname, | .tag_config(tagname, | ||
- | Knowing which of the 19 options to use to create your tag takes experimentation. | + | Knowing which of the 19 options to use to create your tag takes experimentation. There are just too many things you can do. One of the neat things that you can set is the relief option. This, like most Tk widgets, is the 3-D effect that will be used to display the tagged text. The choices are “flat”, “raised”, |
+ | |||
+ | Une fois que vous avez défini votre (vos) police(s), vous pouvez commencer à définir votre (vos) balise(s). Bien sûr, il y a une mise en garde. Il existe de NOMBREUSES options pour une balise. La police n'est qu'une des 19 options disponibles. Vous trouverez la liste des options à l' | ||
+ | |||
+ | En gros, la syntaxe est à peu près la suivante : | ||
+ | |||
+ | .tag_config(tagname, | ||
+ | |||
+ | Pour savoir laquelle des 19 options utiliser pour créer votre balise, il faut expérimenter. Il y a tout simplement trop de choses que vous pouvez faire. L'une des choses intéressantes que vous pouvez définir est l' | ||
**Marks | **Marks | ||
- | Marks are invisible objects that are positioned BETWEEN character positions that move with the text. There are a couple of Tk defined marks (INSERT and CURRENT) and any number of user-defined marks that can be created. | + | Marks are invisible objects that are positioned BETWEEN character positions that move with the text. There are a couple of Tk defined marks (INSERT and CURRENT) and any number of user-defined marks that can be created. From my testing, they aren’t really that useful outside of the two Tk defined marks. You will see me use marks later in the code.** |
+ | |||
+ | Marques | ||
+ | |||
+ | Les marques sont des objets invisibles placés ENTRE les positions des caractères qui se déplacent avec le texte. Il existe deux marques définies par Tk (INSERT et CURRENT) et un grand nombre de marques définies par l' | ||
**Images | **Images | ||
- | The (in my mind) second most useful thing that the Text widget can do is embed images amongst the text. It can be at the beginning of a sentence or paragraph, at the end of a sentence or paragraph or smack dab in the middle of a sentence. | + | The (in my mind) second most useful thing that the Text widget can do is embed images amongst the text. It can be at the beginning of a sentence or paragraph, at the end of a sentence or paragraph or smack dab in the middle of a sentence. |
- | In order to use images in your Text widget, you must remember that the images have to be of the formats that Tkinter natively supports (.xbm, .gif, .pgm, .ppm or .png). | + | In order to use images in your Text widget, you must remember that the images have to be of the formats that Tkinter natively supports (.xbm, .gif, .pgm, .ppm or .png). If you want to support .jpg files, you can, but you need to use the Pillow library. |
Similar to tags, you need to use the .image_create() method, which has the syntax of | Similar to tags, you need to use the .image_create() method, which has the syntax of | ||
Ligne 65: | Ligne 123: | ||
In the code, I decided to use the least number of options.** | In the code, I decided to use the least number of options.** | ||
+ | |||
+ | Images | ||
+ | |||
+ | La deuxième chose la plus utile (à mon avis) que peut faire le widget Texte est d' | ||
+ | |||
+ | Afin d' | ||
+ | |||
+ | Comme pour les balises, vous devez utiliser la méthode .image_create(), | ||
+ | |||
+ | .image_create(index, | ||
+ | |||
+ | Dans le code, j'ai décidé d' | ||
+ | |||
**The Code | **The Code | ||
- | Finally, we can get started with the code. I chose to use PAGE 7.6 to create the GUI for me. There are many reasons for this, but the biggest one is that PAGE provides not only the Text widget but a ScrolledText widget that already has the scroll bars provided. | + | Finally, we can get started with the code. I chose to use PAGE 7.6 to create the GUI for me. There are many reasons for this, but the biggest one is that PAGE provides not only the Text widget but a ScrolledText widget that already has the scroll bars provided. |
- | When I designed the GUI, I used the ScrolledText widget just as it comes “out of the box” with only one attribute changed from the default. | + | When I designed the GUI, I used the ScrolledText widget just as it comes “out of the box” with only one attribute changed from the default. That was to set the “wrap” attribute to “word”, which I do 94% of the time. Once I had the GUI created, I started working on the code in the support module. First I needed to add to the import section (shown above). |
I needed to include the font module from tkinter as well as the messagebox (just in case) and then the filedialog set, so the user can import a text file. | I needed to include the font module from tkinter as well as the messagebox (just in case) and then the filedialog set, so the user can import a text file. | ||
- | Next, I needed to add a startup module to get things going before the GUI is presented to the user. I set the bindings for the ScrolledText widget, which includes a keystroke event, a Button-1 event and a Button-3 event for the context menu. ** | + | Next, I needed to add a startup module to get things going before the GUI is presented to the user. I set the bindings for the ScrolledText widget, which includes a keystroke event, a Button-1 event and a Button-3 event for the context menu. ** |
- | **It also calls a function | + | Le code |
- | You can see that there are three font focused tags and three color focused tags. The Context menu will allow the user to set the font tags and color tags. | + | Enfin, nous pouvons commencer avec le code. J'ai choisi d' |
- | The next function I created was the Keypress callback (shown bottom right). | + | Lorsque j'ai conçu l' |
- | **Since the context menu is used to insert the tags (both color and font), they are very similar code wise. Here is the function to make a selection of text to be bold (next page, top right). | + | Je devais inclure le module de police de tkinter ainsi que la boîte de message |
- | We need to use the .tag_add in order to set a tag and it really needs to be a selection group of text. You can see in the function that you need to include the tag name as well as index1 and index2. | + | Ensuite, j'ai eu besoin d' |
- | To turn the bold off (let’s assume you wanted to use italics instead or in addition), you can simply use the tag_remove method (shown middle right). | + | **It also calls a function (top right) that creates the fonts and tags before the Text widget is used. This is not required, but it’s much easier to do early on if you know what fonts and tags you want to use. Since this is just a demo I wanted to keep it simple. Here is the code for that. |
+ | |||
+ | You can see that there are three font focused tags and three color focused tags. The Context menu will allow the user to set the font tags and color tags. | ||
+ | |||
+ | The next function I created was the Keypress callback (shown bottom right). I use this to track the INSERT index. I basically query the INSERT index each time a keyboard key is released (better to keep key bounce from sending false signals). It comes in as a “line.column” message. I use the string .find method looking for the period. Then I check the tag_ranges method to see if there are characters that are selected as a “group”. Remember that if you try to use the SEL_FIRST and SEL_LAST indexes and nothing is selected, you will get an error. To avoid that, I call the tag_ranges method to get a tuple containing the First and Last values. If there is nothing selected, the returned value will be an empty tuple. So by checking the returned value to see if the length is greater than 0, I can safely see if and what the selection is. At the end of the function, I push the information to the two Label widgets at the bottom of the form.** | ||
+ | |||
+ | Il appelle également une fonction (en haut à droite) qui crée les polices et les balises avant que le widget Texte ne soit utilisé. Ce n'est pas obligatoire, | ||
+ | |||
+ | Vous pouvez voir qu'il y a trois balises axées sur la police et trois balises axées sur la couleur. Le menu contextuel permet à l' | ||
+ | |||
+ | La fonction suivante que j'ai créée est le rappel Keypress (en bas à droite). Je l' | ||
+ | |||
+ | |||
+ | **Since the context menu is used to insert the tags (both color and font), they are very similar code wise. Here is the function to make a selection of text to be bold (next page, top right). | ||
+ | |||
+ | We need to use the .tag_add in order to set a tag and it really needs to be a selection group of text. You can see in the function that you need to include the tag name as well as index1 and index2. | ||
+ | |||
+ | |||
+ | To turn the bold off (let’s assume you wanted to use italics instead or in addition), you can simply use the tag_remove method (shown middle right). Just like the .tag_add method, you need to include the tagname, the index1 and index2 positions. | ||
There is a .tag_delete method, but if you call that, it will completely remove ALL tags of that type AND will delete the definition as well, so you can’t use it again until the program is restarted or the tag is added again. | There is a .tag_delete method, but if you call that, it will completely remove ALL tags of that type AND will delete the definition as well, so you can’t use it again until the program is restarted or the tag is added again. | ||
- | One of the things that you might want to do is programmatically move the insertion cursor. | + | One of the things that you might want to do is programmatically move the insertion cursor. I included two simple functions that will show how to do that. The on_btnGoToTop and on_btnGotoBottom functions handle this (right).** |
- | **There are only two lines that are needed to accomplish this task. First, we call the .yview(index) method which scrolls the Text window to the index position. Then we call the .mark_set(INSERT,index) to actually move the insertion cursor (bottom right). | + | Comme le menu contextuel est utilisé pour insérer les balises |
+ | Nous devons utiliser .tag_add pour définir une balise et il doit s'agir d'un groupe de texte sélectionné. Vous pouvez voir dans la fonction que vous devez inclure le nom de la balise ainsi que l' | ||
- | There is a method called .see(index) that does something similar, but depending on the distance that needs to be scrolled, the position set with index, might be at the top, bottom or even in the middle of the Text window. | + | Pour désactiver le gras (supposons que vous souhaitiez utiliser l' |
- | Next, here is the function that will insert an image (next page, top right). | + | Il existe une méthode .tag_delete, mais si vous l' |
- | Once we have the filename of the image file, we play some games with the filename. | + | L'une des choses que vous pourriez vouloir faire est de déplacer le curseur d' |
+ | |||
+ | |||
+ | **There are only two lines that are needed to accomplish this task. First, we call the .yview(index) method which scrolls the Text window to the index position. Then we call the .mark_set(INSERT, | ||
+ | |||
+ | |||
+ | There is a method called .see(index) that does something similar, but depending on the distance that needs to be scrolled, the position set with index, might be at the top, bottom or even in the middle of the Text window. I find the .yview() method much better to use. | ||
+ | |||
+ | Next, here is the function that will insert an image (next page, top right). First, like loading a file, we need to use the file dialog askopenfilename to get the name of the image we wish to use. | ||
+ | |||
+ | Once we have the filename of the image file, we play some games with the filename. We also need to create a global copy of the file object so that Python’s garbage collection doesn’t get rid of it before it can actually be seen. The method to insert the image has the following syntax… | ||
.image_create(index, | .image_create(index, | ||
Ligne 106: | Ligne 206: | ||
The align, padx and pady attributes are optional.** | The align, padx and pady attributes are optional.** | ||
- | **So the image_name is simply a string that is associated with the image itself. I chose to use the filename without the extension or path for this (shown bottom left). | + | Seules deux lignes sont nécessaires pour accomplir cette tâche. Tout d' |
- | Finally, here is the function that loads a text file into the Text widget. You can see that the first part of the function is almost identical to the one we used to get the image filename | + | Il existe une méthode appelée |
- | Now, we clear the text widget (assuming there was a filename chosen) by using the .delete(index1, | + | Ensuite, voici la fonction qui insère une image (page suivante, en haut à droite). Tout d' |
+ | |||
+ | Une fois que nous avons le nom du fichier image, nous jouons avec le nom du fichier. Nous devons également créer une copie globale de l' | ||
+ | |||
+ | .image_create(index, | ||
+ | |||
+ | Les attributs align, padx et pady sont facultatifs. | ||
+ | |||
+ | |||
+ | **So the image_name is simply a string that is associated with the image itself. I chose to use the filename without the extension or path for this (shown bottom left). | ||
+ | |||
+ | Finally, here is the function that loads a text file into the Text widget. You can see that the first part of the function is almost identical to the one we used to get the image filename (shown below). | ||
+ | |||
+ | Now, we clear the text widget (assuming there was a filename chosen) by using the .delete(index1, | ||
Finally, we call .focus_set() to return focus to the Text widget.** | Finally, we call .focus_set() to return focus to the Text widget.** | ||
+ | |||
+ | Le nom de l' | ||
+ | |||
+ | Enfin, voici la fonction qui charge un fichier texte dans le widget Text. Vous pouvez constater que la première partie de la fonction est presque identique à celle que nous avons utilisée pour obtenir le nom de fichier de l' | ||
+ | |||
+ | Ensuite, nous effaçons le widget texte (en supposant qu'un nom de fichier ait été choisi) en utilisant la méthode .delete(index1, | ||
+ | |||
+ | Enfin, nous appelons la méthode .focus_set() pour redonner le focus au widget Texte. | ||
+ | |||
**Conclusion | **Conclusion | ||
- | The biggest downside of Tags is that there can be more than one tag applied to a block of text at any given time. In fact, it is possible that every tag that has been defined can be applied to any given block of text. | + | The biggest downside of Tags is that there can be more than one tag applied to a block of text at any given time. In fact, it is possible that every tag that has been defined can be applied to any given block of text. |
- | This can be a problem, because when there are multiple tags for any given block, the tag that was most recently created is the one that takes control and will be shown. | + | This can be a problem, because when there are multiple tags for any given block, the tag that was most recently created is the one that takes control and will be shown. You can use the .tag_raise() and the .tag_lower methods like this… |
.tag_raise(tagname, | .tag_raise(tagname, | ||
Ligne 130: | Ligne 252: | ||
Which will return a tuple of the tag names that are associated with that text block.** | Which will return a tuple of the tag names that are associated with that text block.** | ||
- | **There are many other features that the Text widget provides like search, edit undo and edit redo and more. However, I wanted to try to keep the demo and article down to a reasonable length. | + | Conclusion |
- | Seriously, I could do half a book just on the Text widget. | + | Le principal inconvénient des balises est qu'il peut y avoir plus d'une balise appliquée à un bloc de texte à un moment donné. En fait, il est possible que chaque balise définie soit appliquée à un bloc de texte donné. |
+ | |||
+ | Cela peut poser un problème, car lorsqu' | ||
+ | |||
+ | .tag_raise(tagname, | ||
+ | |||
+ | Pour « activer » une balise différente dans la pile, vous devez savoir laquelle et combien de balises sont définies pour ce bloc de texte. | ||
+ | |||
+ | Pour savoir quelles balises sont définies pour un bloc de texte, vous pouvez utiliser la fonction : | ||
+ | |||
+ | .tag_names(index) | ||
+ | |||
+ | qui renverra un tuple des noms de balises associés à ce bloc de texte. | ||
+ | |||
+ | |||
+ | **There are many other features that the Text widget provides like search, edit undo and edit redo and more. However, I wanted to try to keep the demo and article down to a reasonable length. | ||
+ | |||
+ | Seriously, I could do half a book just on the Text widget. Here are the links again for the two resources to learn more. | ||
https:// | https:// | ||
Ligne 138: | Ligne 277: | ||
https:// | https:// | ||
- | I sincerely hope that I’ve been able to give you a new appreciation for the humble Text widget. | + | I sincerely hope that I’ve been able to give you a new appreciation for the humble Text widget. The best way to learn more about it is to create a sample program and play with all the available options. |
As I normally do, I’ve placed the source code into a repository on Github at https:// | As I normally do, I’ve placed the source code into a repository on Github at https:// | ||
Until next time, as always; stay safe, healthy, positive and creative!** | Until next time, as always; stay safe, healthy, positive and creative!** | ||
+ | |||
+ | Le widget Texte offre de nombreuses autres fonctionnalités, | ||
+ | |||
+ | Sérieusement, | ||
+ | |||
+ | https:// | ||
+ | |||
+ | https:// | ||
+ | |||
+ | J' | ||
+ | |||
+ | Comme je le fais habituellement, | ||
+ | |||
+ | Jusqu' | ||
+ |
issue192/python.1682833211.txt.gz · Dernière modification : 2023/04/30 07:40 de d52fr