Programmation d'IHM - Remodelage de l'éditeur exemple

From OFSET Wiki

Jump to: navigation, search

Contents

[edit] Motivations

La première version de l'éditeur se compose de la classe unique, MUIDSimpleEditor1, qui comporte les informations concenant le fichier en cours d'édition (son nom et son contenu). La construction de l'IHM constitue la majeur partie des méthodes de cette classe. La deuxième version intègre un menu et une barre de boutons supplémentaires. Au fur et à mesure que l'IHM s'enrichit, sa construction est plus complexes et devient gênante dans la classe du modèle.

Pour bien assurer la séparation entre modèle et vue, aucune référence de morph n'est stocké dans un MUIDSimpleEditor1. Cependant, pour certaines fonctionalités ou pour amméliorer l'ergonomie, on peut avoir besoin de récupérer la référence d'un morph pour lui envoyer directement un message.

[edit] Reconception

La première mise en oeuvre est donc revue avec tout d'abord la nouvelle classe MUIDSimpleEditor2 simplifiée au maximum : elle ne contient que les accesseurs pour le nom et le contenu du fichier en cours d'édition :

Object subclass: #MUIDSimpleEditor2
	instanceVariableNames: 'filename fileContents'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'MUIDoc'

Pour assurer une séparation plus claire entre le modèle et ses vues, stocker la référence des morphs utilisés pour l'IHM et permettre d'établir un protocole de mise à jour spécifique entre le modèle et ses vues, la nouvelle classe MUIDSimpleEditor2UI est introduite. Fonctionnellement, elle établit le lien entre le modèles et les morphs utilisés pour l'IHM. Elle stocke les références des morphs dans un dictionaire (variable d'instance morphsIndex) et le modèle (l'instance de MUIDSimpleEditor2) :

Object subclass: #MUIDSimpleEditor2UI
	instanceVariableNames: 'model morphsIndex'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'MUIDoc'

Le lien entre une instance de MUIDSimpleEditor2 et une vue MUIDSimpleEditor2UI est établi par l'envoi du message openOn: à la vue, l'argument passé est le modèle :

MUIDSimpleEditor2>>open
	^ MUIDSimpleEditor2UI new openOn: self

MUIDSimpleEditor2UI>>openOn: aSimpleEditor 
	model := aSimpleEditor.
	model addDependent: self.
	^ self buildMainWindow openInWorld

On observe que la construction de l'IHM est maintenant de la responsabilité de la classe MUIDSimpleEditor2UI (buildMainWindow).

[edit] Protocole de mise à jour entre modèle et vue(s)

L'orqu'une vue est ouverte sur le modèle, la vue est déclarée dépendante du modèle. Ainsi, la ou les vues peuvent être informées des changement effectués dans le modèle. Voici les accesseurs du modèle :

MUIDSimpleEditor2>>fileContents: aStringOrText 
	fileContents := aStringOrText asString.
	self changed: #fileContents

MUIDSimpleEditor2>>filename: aString 
	filename := aString.
	self changed: #filename

L'envoi du message #changed: a pour conséquence l'envoi de #update: aux objets dépendants de sorte qu'il puissent éventuellement se mettre à jour à leur tour.

Par construction, les morphs constituant l'IHM sont déclarés dépendants d'une instance de MUIDSimpleEditor2UI et non du modèle, instance de MUIDSimpleEditor2. Voici par exemple la construction du PluggableTextMorph pour l'édition du contenu du fichier :

MUIDSimpleEditor2UI>>contentsMorph
	| tm |
	tm := PluggableTextMorph
				on: self "<-- le modèle pour le PluggableTextMorph est le MUIDSimpleEditor2UI"
				text: #fileContents
				accept: #setFileContents:
				readSelection: nil
				menu: #fileContentsMenu:shifted:.
	tm menuTitleSelector: #fileContentsMenuTitle.
	^ tm

Les morphs ne sont donc pas directement informés des modifications du modèle. Il faut implanter un relais au sein de la classe MUIDSimpleEditor2UI avec la mise en oeuvre d'une méthode update: :

MUIDSimpleEditor2UI>>update: aSymbol 
	aSymbol = #filename
		ifTrue: ["permet de changer le titre de la fenetre"
			self setNewFilename: self filename].
	self changed: #relabel.
	self changed: #saveBtnLabel.
	"si le fichier est en lecture seule, le bouton est <<grise>>"
	self changed: aSymbol
MUIDSimpleEditor2-dependances.png

La figure ci-contre montre le fonctionnement du protocole de mise à jour des vues à partir du modèle :

  • un MUIDSimpleEditor2UI est déclaré dépendant d'un MUIDSimpleEditor2;
  • les morphs qui constituent l'IHM sont dépendants de leur MUIDSimpleEditor2UI;
  • en cas de changement d'état du MUIDSimpleEditor2, le message #changed: est envoyé au MUIDSimpleEditor2 ce qui a pour conséquence l'envoi de #update: aux MUIDSimpleEditor2UI dépendants;
  • l'exécution de la méthode MUIDSimpleEditor2UI>>#update: provoque l'envoi de #changed: au receveur; en conséquence, tous les morphs dépendants reçoivent le message #update:.

[edit] Construction de l'IHM

La différence avec la première version est l'ajout d'un menu et d'une barre de boutons icônes. Pour gérer les cadres, on utilise des AlignmentMorph. Suivant le besoin, ils sont créés avec la méthode AlignmentMorph class>>newRow ou AlignmentMorph class>>newColumn pour, respectivement, une ligne ou une colonne de morphs.

On remarquera que les morphs (boutons et le PluggableTextMorph) sont stockés dans un dictionaire local (variable d'instance morphsIndex) de façon à pouvoir les retrouver ultérieurement par leur nom et leur envoyer des messages. Le stockage d'un morph est effectué par la méthode MUIDSimpleEditor2UI>>declareMorph:named: et la récupération d'un morph est effectué par la méthode MUIDSimpleEditor2UI>>morphNamed:.

[edit] Amméliorations de l'ergonomie

Les ammélioration suivantes sont implantées dans la mise en oeuvre (MUIDoc.st) :

  • l'ouverture d'un fichier, par le menu ou via le bouton, s'effectue à l'aide d'un dialogue standard;
  • lorsqu'un fichier non modifiable est ouvert, le bouton de sauvegarde est grisé (il devient inactif) et l'option sauver du menu Fichier n'est pas disponible;
  • si l'utilisateur tente de charger un fichier ou de fermer la fenêtre alors que la zone de texte est modifiée, alors il y a demande de confirmation pour l'abandon de l'édition;

La mise en oeuvre de tout ça n'est pas détaillée ici mais je peux ajouter des explications en cas de besoin (alain.plantec(AT)univ-brest.fr).

Personal tools