mardi 14 octobre 2014

Excel: comment afficher dans une case le libellé de sa colonne avec le format A, B, ...AA, AB, ...

Voici un petit exercice pour se dégourdir l'esprit:
comment afficher dans une case, le libellé de la colonne de cette case, avec le format A, B, C, ...., Z, AA, AB, .....
J'ai eu besoin de cette fonction pour réaliser l'inventaire des colonnes d'un tableau. En d'autre terme, j'avais besoin de faire correspondre à chaque libellé de colonne, son libellé de colonne Excel.
Malheureusement, la fonction "=colonne()" sans argument est parfaite pour obtenir le n° d'indice de la colonne (à partir de 1), mais pas pour obtenir l'équivalent du format traditionnel, à savoir A, B, C, etc....

Pour cela, j'ai choisi de traduire le numéro d'indice de la colonne en base 26 (car il y a 26 lettres dans notre alphabet, de A à Z). Par simplicité, l'opération se fait en deux temps. Sur une première case, je récupère le numéro d'indice, c'est dire le résultat de la fonction "=COLONNE( )". Ci dessous, on peut voir que j'obtiens 3 pour la colonne C, 4 pour la colonne D, etc...
Ensuite, sur la case juste en dessous de la première contenant le n° d'indice de la colonne, j'utilise cette formule:

=SI(C1 < 27;CAR(64+C1);CAR(ENT((C1-1)/26)+64) & CAR(MOD(C1-1;26)+65))

Explications:
  • 65 est le code ASCII de la lettre majuscule "A".
  • MOD( ), la fonction qui donne le reste de la division entière (cad modulo).
  • ENT( ), la fonction qui donne la partie entière d'une division.
  • CAR( ), la fonction qui renvoie le caractère d'un code ASCII: CAR(65)='A'
Remarque importante:
Cette fonction n'est valable que pour le valeurs d'indice de 1 à 26*26 (cad 676). Pour les colonnes au delà de 676, je vous laisse libre de trouver soit une autre formule, soit la même en ajoutant un étage supplémentaire de "=SI( C1 < 677 ; ..... )" .

En résumé, voici les deux formules pour les 676 premières colonnes.
Formule en C1: =COLONNE( )
Formule en C2: =SI(C1 < 27;CAR(64+C1);CAR(ENT((C1-1)/26)+64) & CAR(MOD(C1-1;26)+65))

A votre bon cœur pour trouver une formule plus élégante, car il faut bien l'admettre, celle que je propose étant plutôt rustique.

vendredi 28 mars 2014

Paramétrer un lecteur code barre Sumikon (de chez Pearl)

Acheter un lecteur code barre a toujours été une idée que j'ai repoussé à cause du prix. Heureusement, les prix de ces lecteurs se sont démocratisés. J'ai acheté le mien pour 39€.


Malheureusement, il n'a pas voulu fonctionner, loi de Murphy oblige. J'ai perdu pas mal de temps pour y arriver. Le symptôme était simple: à chaque fois que je scannais un code barre de livre ou de CD (constitué de 13 digits), j'obtenais à la place une série de lettres.

J'ai donc fait une demande au support de mon vendeur, sans succès: celui-ci m'enjoignait de paramétrer mon lecteur code barre en majuscule, ce qui n'a eu aucun effet positif, mis à part récupérer la même série de lettres mais cette fois en majuscules.

Ma méthode pour trouver le bon paramétrage fut d'essayer systématiquement tous les codes de paramétrages imprimés dans le livret "mode d'emploi". Voici la méthode:

- Ouvrir un éditeur de texte pour afficher chaque test de lecture d'un code barre (un livre par exemple, et toujours le même évidement).
- A chaque test, je scanne  "Paramétrages d'usine".
- Je scanne"Démarrer réglages"
- Je scanne alors un paramètre (un à la fois dans un premier temps, et l'un après l'autre)
- Je scanne"Arrêter réglages"
- Je teste à nouveau (dans l'éditeur de texte)
- Si j'obtiens encore des lettres, je recommence avec un autre paramétrage (sans oublier "Paramètres d'usine")

Voici donc la solution qui m'a permis de résoudre mon soucis:
  • je scanne  "Paramétrages d'usine".
  • Je scanne"Démarrer réglages"
  • Ensuite paramétrage "Francais" page 48 de mon livret mode d'emploi.
    Ce paramétrage est dans la catégorie "réglages de base", sous rubrique "réglage de la langue".
  • Pour finaliser, paramétrage du caractère de fin de lecture: "CR"
    (au lieu de "CR-LF")
  • Puis "Arrêter réglages"
  • Penser à scanner la fonction "Enregistrer réglages" à la fin, sous peine de devoir recommencer ce paramétrage lors du prochain branchement du code barre.

Et depuis, ce lecteur de code barre est un véritable plaisir. Je regrette d'avoir attendu si longtemps, tant le gain de temps est significatif. Je signale que j'utilise ce code barre sous lubuntu (linux) sans aucun soucis. Je vais pouvoir travailler dorénavant sur la saisie de mes collections de livres, CD, DVD et autres.

vendredi 21 mars 2014

Sudoku: aide à la résolution sous Libre Office Calc (plutôt qu'Excel)

Une des choses qui caractérise un véritable geek, c'est sa manière de résoudre des problèmes simples à l'aide de solutions complexes.
C'est pour cela que je me suis donné comme objectif de résoudre un Sudoku, à l'aide d'un tableur (Libre Office Calc plutôt qu'Excel). Avec une contrainte (sinon c'est pas drôle): ne pas utiliser le langage de programmation du tableur. C'est donc à l'aide des fonctions natives du tableur (exemple RechercheV), et de la mise en forme conditionnelle (Exemple, colorer en rouge les doublons d'une grille).
Et voilà le résultat, après une bonne journée de travail (avec l'age on apprécie prendre son temps). J'ai surtout dû réapprendre à utiliser Libre Office Calc.


Le fichier est réalisé avec Libre Office Calc (v4.1.5.3). Il contient 3 onglets:
  1. Onglet "grille"=> à remplir uniquement avec la grille de départ
  2. Onglet "vérification" =>C'est cette grille qu'il faut remplir et qui permet en temps réel de vérifier l'absence de doublons
  3. Onglet "possibilités" => cet onglet permet de 'tricher' en affichant les cases faciles à remplir

Il doit rester quelques bugs, mais globalement il fonctionne. Il reste encore quelques cases inutiles (suite à des essais itératifs), mais l'essentiel est opérationnel. Je vous entend déjà dire qu'en C ou en PHP, on aurait pu le faire plus simplement. Mais parfois, c'est justement dans l’adversité que l'on trouve du plaisir.
A noter que ce fichier n'est pas compatible Excel (il pourrait l'être à peu de frais). Mais je préfère des outils pérennes dans leur forme et leur ergonomie, contrairement à Microsoft qui tous les 3 ou 4 ans révolutionne les deux sans aucune justification, mettant dans la panade des millions d'utilisateurs. Ce fichier Suduko sera ma petite contribution pour tenter de désintoxiquer les utilisateurs de MS Office.

Fichier pour résoudre un Suduko (à télécharger)
Règles du Sudoku

mercredi 1 janvier 2014

Xlib, C magnifique (avec l'exemple de WM_NAME)

Et oui, je suis membre de la petite minorité de personne aimant programmer directement en X11 avec Xlib. Je ne suis pas un foudre de programmation, mais plutôt un dilettante de la programmation C. Le fait d'utiliser Xlib directement est pour moi comparable à faire un Sudoku: C'est long, parfois ennuyeux, toujours sources d'erreur, magnifiquement vain, mais tellement distrayant. On peut ainsi passer une journée entière pour parvenir simplement à afficher une simple fenêtre à l'écran avec Xlib. Pour résumer, Xlib est une API (liste de fonctions) permettant de programmer pour X Windows et dont la dernière version est la version nommée X11.

Xlib est pour distrayante, car elle oblige à devoir passer un temps fou sur la toile pour glaner quelques infos ou tutoriels, car contrairement aux librairies graphiques plus évoluées (exemple GTK, Xt, Qt), on doit lire des pages et des pages de sites ou de documentation avant de comprendre le début d'une explication pour les choses les plus simples.

Prenons l'exemple par exemple d'une fonction permettant de déterminer le nom d'une fenêtre X (au sens X11 évidement). Cette simple fonctionnalité est déjà toute une histoire, car on doit s'intéresser à un élément périphérique à X11: le Window Manager (WM pour les initiés ou pour les amis les plus proches). Le WM est le chef d'orchestre des fenêtres dans X11. Il possède évidement des privilèges spécifiques lui permettant d’exécuter les tâches qui lui sont dévouées, comme par exemple gérer la barre de titres et différentes "décorations" associées à une fenêtre (cette fois au sens du WM).

Dans mon cas personnel, j'utilise le WM le plus simple, celui qui est inclus à Lubuntu: OpenBox. Normalement, l'usage des nom des fenêtres (ceux qui apparaissent par exemple dans le gestionnaire de taches par exemple), n'est pas tributaire de votre WM. En théorie, l'exemple suivant devrait fonctionner quelques soit votre WM.

Donc voici le résultat de mes recherches: une fonction C permettant de récupérer les noms de chaque fenêtre actives dans X:

/*----------------------------------------------
 * Fonction récupérant le nom d'une fenêtre
 * retour=0 si problème
 * sinon retour=1
 * Le nom_fentre est un buffer fourni par l'appelant
 * dont la longueur est spécifié en argument
 * --------------------------------------------*/
int X11vb_recuperer_nom_fenetre( Display * d, Window w, char * nom_fenetre, int nb_c_nom_fenetre)
{
char **liste;
int i=0;
XTextProperty text_property;

if (nb_c_nom_fenetre<1 class="Apple-tab-span" span="" style="white-space: pre;">
return 0; nom_fenetre[0]=0;

//---- récupération de la property texte WMName
if(!XGetWMName (d, w, &text_property))
{
return 0;
}
if (!XTextPropertyToStringList( &text_property, &liste, &i))
{
printf("XStringListToTextProperty - out of memory\n");
return 0;
}
if (!i)
{
printf("XTextPropertyToStringList=>liste=0\n");
return 0;
}
if (!*liste)
{
printf("XTextPropertyToStringList=>liste[0]=vide\n");
return 0;
}
//------ copie du résultat
strncpy(nom_fenetre, *liste, nb_c_nom_fenetre);
nom_fenetre[nb_c_nom_fenetre-1]=0;
XFreeStringList(liste);
return 1;
}

Pour l'utiliser, voici un source additionnel pour par exemple lister les fenêtres qui possède un nom (et oui, toutes les fenêtre n'ont pas de nom, et pourtant nullement orpheline).

#include
#include
#include
#include
#include
#include



int X11vb_recuperer_nom_fenetre( Display * d, Window w, char * nom_fenetre, int nb_c_nom_fenetre);

// ERROR HANDLER, GENERIC
static int ErrorHandler (Display *display, XErrorEvent *error)
{
   //printf ("\r\n error! \r\n");
   return 0;
}
// END ERROR HANDLER



void ListerWindows (Display *display, Window window, int niveau, char * filtre)
{
static int nb_w=0;
Window parent;
Window root;
Window *enfant;
XWindowAttributes windowattr; 
int nb_enfant=0;
int i=0, h=0, l=0, x=0, y=0;
char nom_fenetre[40]; //---le nom de la fenêtre affiché sera limité à 39 caract.
   
if (filtre) if (!*filtre) filtre=NULL;

//-----récupérer le nom de la fenêtre
if (!X11vb_recuperer_nom_fenetre(display, window, nom_fenetre, sizeof(nom_fenetre)))
*nom_fenetre=0; ;
//---- attributs de la fenêtre
if (XGetWindowAttributes(display, window,   &windowattr) == 0)
printf("failed to get window attributes");
else
{
x= windowattr.x;
y= windowattr.y;
l= windowattr.width;
h= windowattr.height;
}
// les enfants de cette fenêtre----
if (!XQueryTree (display, window, &root, &parent, &enfant, &nb_enfant))
nb_enfant=0;
if (*nom_fenetre)
{
if (!filtre || strstr(nom_fenetre, filtre)) 
printf ("%03i (niv.=%i; enfant=%i) - window: '%s' (x=%i,y=%i;L=%i,H=%i) w=%i\r\n", ++nb_w, niveau,nb_enfant, nom_fenetre, x,y,l,h,(int)window);
}

for (i=0; i < nb_enfant; i++)
ListerWindows (display, enfant[i], niveau+1, filtre);
   
XFree ((char*) enfant);
}


int main(int argc, char *argv[])
{
   // CONNECT TO THE XSERVER
   Display *display;
   int depth;
   int screen;
   int connection;
   char *filtre=NULL;
   Window rootWindow;
      
   display= XOpenDisplay (NULL);
   screen= DefaultScreen (display);
   depth= DefaultDepth (display, screen);
   connection= ConnectionNumber (display);
   XSetErrorHandler (ErrorHandler);
   
   printf ("Lister X11 window ayant un nom pour le Window Manager (WMName)\r\n");
   printf ("--------------------------------------------------------------\r\n");
   printf ("Display: %s\r\n", XDisplayName((char*)display));
   printf ("Width: %d\r\n", DisplayWidth(display, screen));
   printf ("Height: %d\r\n", DisplayHeight(display, screen));
   printf ("Connection: %d\r\n", connection);
   printf ("Color Depth: %d\r\n", depth);
  
   
if (argc>1)
filtre= argv[1];
if (filtre)
printf("=====>filtre sur le nom des fenêtres contenant:%s\n",filtre);
else
printf ("--en option:\r\n--mettre en argument un filtre sur le nom\r\n");
rootWindow = RootWindow (display, screen);  
ListerWindows (display, rootWindow, 0, filtre);
XCloseDisplay (display);

return 0;
}


Pour ne rien oublier, voici le makefile que j'utilise. Vous pourrez donc le tester en réel sur votre machine linux, si votre gcc (compilateur C) est opérationnel.

liste_w: lister_w.c
gcc -o lister_w lister_w.c -L/usr/X11R6/lib -lX11

On peut remarquer à quel point cet exemple est délicieusement complexe pour une opération aussi élémentaire. Pour être complet sur la question, vous avez un utilitaire permettant globalement de faire la même chose en ligne de commande sous linux: xdotool. Un petit tour sur la page d'aide de cet utilistaire vous permettra d'en comprendre toute la puissance. Il peut par exemple vous permettre d'envoyer des touches 'clavier' vers une X window. xprop et xwinfo sont deux utilitaires qui complète xdotool.

Liens:
Excellente page Wiki sur Xlib
Livre important: Xlib programming manual Volume 1.
Page du source que j'ai adapté et adopté