Chapitre 3 : Plus loin dans les classes
Un article de GuruMed.
Par Corto
Allez, il est temps que notre application ressemble un peu à un player de CD ! Après avoir passé en revue les éléments nécessaires à l'élaboration basique de l'interface, nous passerons à leur mise en place dans le source, en nous basant sur celui du chapitre 2. Ceci fera intervenir les groupes de manière un peu plus poussée.
Sommaire |
Cahier des charges
En regardant sur une platine CD de salon classique, on remarque les éléments suivants :
- les boutons Précédent, Suivant, Jouer, Pause, Arrêter
- le bouton de volume qui peut être représenté par une réglette
- l'affichage du numéro de la piste courante (et éventuellement de la position en minutes et secondes)
- un voyant lumineux indiquant que la lecture est en cours (admettons que ça soit le cas, histoire de réutiliser notre objet de classe Busy :)
Après avoir décidé de ce qui serait présent, il faut agencer tout cela puisque cette décision déterminera l'arborescence des objets : souvenez vous des couples Child / End. On fixera la liste des pistes en premier, c'est à dire en haut et occupant presque toute la largeur. En effet, sur la droite, nous mettrons une glissière verticale, surmontée de l'annotation "Volume". En-dessous, on placera les boutons alignés horizontalement avec au bout un champ de texte (en lecture seule) indiquant la piste courante. Puis tout en bas un objet Busy de faible épaisseur.
Concrètement
On remarque donc que nous avons à faire à 3 groupes horizontaux superposés :
- affichage de la liste des pistes et volume
- boutons et indicateur de la piste courante
- voyant lumineux Busy comme témoin de lecture
Voici comme on dit le pseudo-code équivalent :
Window VGroup HGroup Liste VGroup Label Volume Glissière (Slider) HGroup Bouton Précédent Bouton Suivant BoutonJouer Bouton Pause Bouton Stop Texte avec numéro de piste Busy
J'espère que tout cela est clair et que vous visualisez l'aspect que le player va revêtir. Cette imbrication de groupes horizontaux et verticaux représente une première difficulté. L'autre réside dans les trois nouvelles classes utilisées pour les composants suivants :
- le label qui contient le mot "Volume", son usage est on ne peut plus simple !
- le volume
- la liste des chansons
Le volume utilise la classe builtin Slider dont l'autodoc est très accessible. Ses attributs sont : sa représentation verticale ou horizontale, sa valeur minimum et maximum, sa valeur de départ, ... Pour notre exemple, on a choisi arbitrairement les limites 0 et 100, avec 38 comme valeur initiale. On fixe l'attribut MUIA_Lister_Reverse à TRUE pour obtenir le 0 en bas. Lorsqu'on regarde dans la documentation (ce qu'il faut toujours faire :) on s'aperçoit que la plupart des attributs sont indiqués comme obsolètes. En fait, puisque l'on utilise des valeurs numériques, les attributs recommandés sont les équivalents de la classe builtin Numeric : MUIA_Numeric_Max au lieu de MUIA_Slider_Max, etc. Cela ne change rien dans le fonctionnement mais c'est plus correct au niveau de la conception. Et logique, tout simplement !
Pour visualiser toutes ces nouvelles notions, voici le source (disponible en téléchargement ici) :
/*
* DisKo3.c (08/06/04)
*
*/
#include <stdio.h>
#include <libraries/mui.h>
#include <proto/muimaster.h>
#include <proto/exec.h>
#include <clib/alib_protos.h>
#include <mui/Busy_mcc.h>
#define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
struct Library *MUIMasterBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
#define MUIA_Application_UsedClasses 0x8042e9a7 /* V20 STRPTR * i.. */
static CONST_STRPTR ClassList[] =
{
"Busy.mcc",
NULL
};
void CreateGui()
{
Object *app = NULL;
Object *window = NULL;
Object *bt_play, *bt_stop, *bt_previous, *bt_next, *bt_pause, *bt_eject;
Object *busy;
Object *sl_volume;
Object *lv_pistes;
Object *list;
/* Description de l'interface et de ses propriétés */
app = (Object *)ApplicationObject,
MUIA_Application_Author, "corto@guru-meditation.net",
MUIA_Application_Base, "DISKO",
MUIA_Application_Title, "DisKo - Exemple 3",
MUIA_Application_Version, "$VER: DisKo 1.03 (08/06/04)",
MUIA_Application_Copyright, "Mathias PARNAUDEAU",
MUIA_Application_Description, "Player de CD audio minimaliste",
MUIA_Application_HelpFile, NULL,
MUIA_Application_UsedClasses, ClassList,
SubWindow, window = WindowObject,
MUIA_Window_Title, "DisKo - release 3",
MUIA_Window_ID, MAKE_ID('W', 'I', 'N', '1'),
WindowContents, VGroup,
Child, HGroup,
Child, lv_pistes = ListviewObject,
MUIA_Listview_Input, FALSE,
MUIA_Listview_List, list = ListObject,
ReadListFrame,
MUIA_List_Format, "P=\33r",
End,
End,
Child, VGroup,
Child, Label("Volume"),
Child, sl_volume = SliderObject,
MUIA_Group_Horiz, FALSE,
MUIA_Numeric_Min, 0,
MUIA_Numeric_Max, 100,
MUIA_Numeric_Value, 38,
MUIA_Numeric_Reverse, TRUE,
End,
End,
End,
/* Utilisation d'un groupe horizontal pourvu de boutons */
Child, HGroup,
Child, bt_previous = KeyButton("Précédent", 'p'),
Child, bt_next = KeyButton("Suivant", 'v'),
Child, bt_play = KeyButton("Jouer", 'j'),
Child, bt_pause = KeyButton("Pause", 'a'),
Child, bt_stop = KeyButton("Stopper", 's'),
Child, bt_eject = KeyButton("Ejecter", 'e'),
End,
Child, busy = BusyObject,
MUIA_Busy_Speed, MUIV_Busy_Speed_Off,
End,
End,
End,
End;
/* On fixe quelques valeurs et notifications */
DoMethod(window,
MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
app, 2,
MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
set(bt_stop, MUIA_Disabled, TRUE);
DoMethod(busy, MUIM_Busy_Move, FALSE);
DoMethod(bt_play, MUIM_Notify, MUIA_Pressed, FALSE,
bt_stop, 3, MUIM_Set, MUIA_Disabled, FALSE);
DoMethod(bt_play, MUIM_Notify, MUIA_Pressed, FALSE,
bt_play, 3, MUIM_Set, MUIA_Disabled, TRUE);
DoMethod(bt_stop, MUIM_Notify, MUIA_Pressed, FALSE,
bt_play, 3, MUIM_Set, MUIA_Disabled, FALSE);
DoMethod(bt_stop, MUIM_Notify, MUIA_Pressed, FALSE,
bt_stop, 3, MUIM_Set, MUIA_Disabled, TRUE);
DoMethod(bt_play, MUIM_Notify, MUIA_Pressed, FALSE,
busy, 3, MUIM_Set, MUIA_Busy_Speed, 20);
DoMethod(bt_stop, MUIM_Notify, MUIA_Pressed, FALSE,
busy, 3, MUIM_Set, MUIA_Busy_Speed, MUIV_Busy_Speed_Off);
DoMethod(list, MUIM_List_InsertSingle, "1 - Première piste", MUIV_List_Insert_Bottom);
DoMethod(list, MUIM_List_InsertSingle, "2 - Deuxième piste", MUIV_List_Insert_Bottom);
SetAttrs(window, MUIA_Window_Open, TRUE, TAG_END);
/* Boucle de gestion des évènements, toujours la même */
{
ULONG sigs = 0;
while (DoMethod(app,MUIM_Application_NewInput,&sigs) != MUIV_Application_ReturnID_Quit)
{
if (sigs)
{
sigs = Wait(sigs | SIGBREAKF_CTRL_C);
if (sigs & SIGBREAKF_CTRL_C) break;
}
}
}
set(window, MUIA_Window_Open, FALSE);
/* Libération des ressources et fermeture */
MUI_DisposeObject(app);
}
int main(int argc, char **argv)
{
int res = 0;
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 39L);
if (IntuitionBase){
MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN);
if (MUIMasterBase){
CreateGui();
CloseLibrary(MUIMasterBase);
}else{
printf("Impossible d'ouvrir muimaster.library\n");
res = -1;
}
CloseLibrary((struct Library *)IntuitionBase);
}else{
printf("Impossible d'ouvrir intuition.library V39\n");
res = -2;
}
return res;
}
Sur la liste
En prévision de l'affichage des titres des chansons, un composant de type liste a été ajouté. La construction d'une liste repose en réalité sur deux classes, List et Listview, qui gèrent respectivement la gestion de la liste (manipulation de ses éléments) et sa représentation. La listview ne propose que peu d'options, les efforts devront être portés sur la richesse de la classe List, qui se trouve alors "embarquée" dans la listview.
Il a été choisi d'employer les classes List et Listview d'origine même si de nombreuses applications utilisent les classes NList et NListView, plus complètes et compatibles. Nos besoins n'étant pas très étendus, nous privilégions la simplicité. Nous ne perdrons rien dans les fonctionnalités liées aux listes que nous aborderons. Par contre, attention à ne pas mélanger ces deux groupes ! Leur compatibilité autoriserait une compilation sans soucis mais des surprises (mauvaises !) sont à prévoir dans le comportement de la liste produite.
Le contenu de la liste est géré par un objet List que l'on doit affecté à la Listview via l'attribut MUIA_Listview_List. La List interne contient ses propres attributs comme MUIA_List_Format pour déterminer comment cela sera affiché par la listview : définition de plusieurs colonnes, justification du texte (ici à droite pour que ça soit marquant, avec \33r), ... L'incontournable DoMethod() est utilisée par deux fois avant l'ouverture de la fenêtre pour ajouter une ligne de texte avec MUIM_List_InsertSingle, soit deux lignes au total. On simule ainsi la lecture des titres des pistes d'un hypothétique CD. A noter qu'il est possible d'ajouter plusieurs lignes en même temps avec MUIM_List_Insert.
Notions acquises dans ce chapitre
- conception d'une interface, agencement des groupes
- introduction aux importantes classes List et Listview
