2017-10-06 8 views
0

J'essaye de créer un éditeur de texte qui manipulera un objet semblable à une chaîne. Idéalement, je voudrais sous-classer Text Widget de Tkinter ou un autre module Gui pour me permettre de substituer cet objet personnalisé au lieu d'utiliser des chaînes.Est-il possible d'utiliser un objet personnalisé au lieu de String à l'intérieur d'un widget Tkinter Text (python)?

Je comprends comment créer l'objet lui-même (qui balise simplement chaque mot avec des méta-données), mais pas comment manipuler l'objet rendu en tant que texte tout en conservant ses autres attributs.

Par exemple.
L'éditeur de texte importe un fichier contenant "Hello World". En ouvrant ce texte, les deux mots sont tagués avec des attributs pertinents. (Affiché ci-dessous comme un dictionnaire, mais idéalement un Hello.strContent objet, Hello.index, etc.)

Hello={strContent: "Hello", index: 0, speaker: "Joe", paragraph: 3} 
World={strContent: "World", index: 1, speaker: "Joe", paragraph: 3} 

Maintenant, je suis complètement déconcerté bien comment je pourrais faire ces chaînes comme des objets manipulables, et sous réserve de coupe , copier, coller, supprimer et réorganiser, à l'intérieur d'un texte Text. Je n'aurais pas besoin que le programme me permette de taper de nouveaux mots ou de créer de nouveaux objets, il suffit de manipuler les objets qui ont été initialisés lors de la conversion du fichier que j'ai ouvert.

Toute aide ou direction serait grandement appréciée. Merci.

+0

Y at-il une raison pour laquelle vous ne pouvez pas simplement ajouter le 'strContent' au texte sous forme de chaîne ou même se référer à chaque objet d'un dictionnaire? Comme dans, chaque mot est une clé de dictionnaire où la valeur assignée à cette clé est le dictionnaire que vous avez décrit ci-dessus? –

+0

J'aime l'idée d'utiliser un dictionnaire, mais le texte source contiendra des doublons des mêmes mots. Par exemple, une solution laide rendrait le texte avec un index ajouté au début de chaque mot.
00Et 01here 02is 03a 04sample 05text 06which 07is 08simple.
Maintenant, disons que je modifie ce texte dans notre hypothétique éditeur Gui pour lire:
Acronomic

+0

Pourriez-vous créer une liste alors? Ajoutez chaque objet à une liste dans l'ordre où vous les lisez, puis parcourez la liste et ajoutez chaque objet 'strContent' au widget' text'. –

Répondre

0

je pense que vous pourriez faire quelque chose comme

class myobj: 
    def __init__(self, text): 
     self.strContent=text 
hello = [[myobj("Hello"), myObj("World")], [myobj("Paragraph"), myobj("2")]] 

alors chaque fois que vous devez afficher ce texte, vous l'auriez boucle à travers comme si

printableStr = "" 
for paragraph in hello: 
    for word in paragraph: 
     printableStr += word.strContent + " " 
    printableStr += "\n" 

puis printableStr sera une belle chaîne contenant toutes les informations de bonjour

+0

Cela fonctionne certainement pour afficher le texte, mais je cherche à manipuler le texte après qu'il a été affiché, et chaque mot conserve ses métadonnées.Idéalement, il serait manipulé dans un éditeur de texte comme l'application, mais cela manipule myObjs au lieu de chaînes. – Acronomic

1

Note: cela tente de répondre à la question qui a été posée, mais je suppose que c'est un xy problem. À la fin de cette réponse, je vais donner quelques autres suggestions.


Le widget de texte ne peut pas avoir un objet complexe comme structure de données sous-jacente. Il peut afficher du texte, et il peut avoir des balises associées au texte. Vous pouvez également insérer des images et des widgets, mais je pense que cela n'a rien à voir avec ce que vous demandez. Lors de la lecture des données, vous pouvez construire des étiquettes pour chaque métadonnée et associer ces étiquettes à une plage de texte. Par exemple, le mot "Hello" pourrait avoir les balises "paragraph: 3", "speaker: Joe" et "index: 0". « Le monde serait similaire, sauf qu'il aurait le tag « index: 1 »

Ce serait facile à faire lors de l'affichage d'abord les données Par exemple:.. Si vous allez ensuite dans

data = [{"strContent": "Hello", "index": 0, "speaker": "Joe", "paragraph": 3}, 
     {"strContent": "World", "index": 1, "speaker": "Joe", "paragraph": 3} 
] 

for item in data: 
    tags = (
     "index:%d" % item['index'], 
     "speaker:%s" % item['speaker'], 
     "paragraph:%d" % item['paragraph'] 
    ) 
    self.text.insert("end", item['strContent'], tags) 

et insérer "r" dans le mot "World", il va hériter des balises du texte environnant

Vous pouvez récupérer les données du widget avec la méthode dump, qui retourne un flux de données. self.text.dump("1.0", "end-1c", tag=True, text=True, mark=False) donne cette information:

[ 
('tagon', 'paragraph:3', '1.0'), 
('tagon', 'speaker:Joe', '1.0'), 
('tagon', 'index:0', '1.0'), 
('text', 'Hello', '1.0'), 
('tagoff', 'index:0', '1.5'), 
('tagon', 'index:1', '1.5'), 
('text', 'World', '1.5') 
] 

Le réassemblage de ces données dans votre format d'origine est délicat. Voici une ébauche d'une tentative, bien que je ne sache pas comment il se lèverait dans le monde réel.Il pourrait être possible pour les utilisateurs d'éditer les données de manière à gâcher totalement la structure.

def get_data(self): 
    result = [] 
    meta = {} 
    for item in self.text.dump("1.0", "end-1c", tag=True, text=True, mark=False): 
     if item[0] == "tagon": 
      (name, value) = item[1].split(":") 
      meta[name] = value 

     if item[0] == "tagoff": 
      (name, value) = item[1].split(":") 
      del meta[name] 

     if item[0] == "text": 
      text = item[1] 
      # if this text has the same tags as the previous text, 
      # don't create a new item; instead, append the text to 
      # the previous item 
      if result and all(item in result[-1].items() for item in meta.items()): 
       result[-1]["strContent"] += text 
      else: 
       data = {"strContent": text} 
       data.update(meta) 
       result.append(data) 

    return result 

Ne sachant pas ce que vous essayez d'accomplir en fait, un widget texte pourrait ne pas être la meilleure solution, car il donne à l'utilisateur un peu trop de liberté pour modifier le texte. Par exemple, que se passe-t-il s'ils changent "Hello" en "HelloWorld", puis suppriment l'original "World"? Est-ce qu'ils se retrouvent avec un article "HelloWorld" ou les deux articles "Hello" et "World"? Vous voudrez peut-être envisager d'utiliser soit une toile, où chaque élément de texte est un objet distinct (qui peut également avoir des balises), ou peut-être vous pourriez vouloir utiliser une série de widgets d'entrée afin que les données en une seule fois t saigner dans l'autre.

+0

Merci Bryan. Idéalement, chaque mot devrait se maintenir comme un objet distinct, et le texte ne devrait pas être modifiable. Le mot ne doit être soumis qu'aux opérations: insérer (repositionner), supprimer ou copier (et insérer). Le widget canvas semble être une excellente suggestion, mais je m'inquiète de la facilité d'utilisation pour effectuer les opérations ci-dessus. Le cas d'utilisation impliquerait des transcriptions de plusieurs pages, que je voudrais éditer, avec chaque mot conservant ses étiquettes. Je vais essayer de mettre en œuvre ce que vous avez mentionné. Merci de votre aide. – Acronomic