Bonjour à tous,

Je reviens sur le forum car, dans un petit développement, je bloque depuis plus d'une semaine sur la gestion graphique avec les API Windows. J'ai choisi de développer sous MinGW dans un terminal MinGW/Cygwin. Cependant, les programmes générés fonctionnent aussi dans un terminal Windows.

Le but du développement

Un processus-père jouant le rôle de serveur (Back-end) capture des sorties "stdout" d'un processus-fils (Front-end), codées pour permettre au processus-père de gérer une visualisation graphique. On retrouve exactement le principe donné par les pseudo-terminaux d'UNIX en plus simple !... L'application est résumée par le logigramme ci-dessous :

Nom : Logigramme_apiptgr.png
Affichages : 516
Taille : 116,8 Ko

Comme toute la phase d'encapsulation a été réalisée avec les API Windows, pour en apprendre un peu plus, j'ai décidé de traiter la partie graphique avec ces API. Au départ, j'envisageais plutôt la SDL.

Comme on peut le voir sur le logigramme, l'application n'a besoin que de l'affichage graphique puisque toutes les actions graphiques sont déclenchées par une commande reçue du processus-fils.

Dans le programme source de test qui suit, j'ai repris l'exemple de programmation proposé dans le cours "Developpez.com" "6 - Dessiner" que j'ai adapté pour illustrer mon problème.

Le programme arrive à afficher un texte au tout début du dialogue juste après la création de la fenêtre avec ShowWindow puis UpdateWindow et seulement la première saisie au clavier. Je ne sais pas comment faire ni qu'elle fonction utiliser pour que ce soit répétitif.

J'ai laissé en commentaire quelques essais que j'ai effectués sans succès. Je n'ai pas pu les laisser tous et je ne vois pas comment il faut faire. Je cherchais en particulier le moyen de donner la main à la MainWndProc pour exécuter la case WM_PAINT après chaque lecture du clavier avec SendMessage() par exemple. Mais rien n'y a fait.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <windows.h>

char st[512] = "Bienvenue sur Developpez.com (éèçàùôûîêöïëä) ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;

HANDLE mon_stdout ;                                                // Les trois ...
HANDLE mon_stdin  ;                                                // ... fichiers standard
HANDLE mon_stderr ;                                                // ... du programme

/*==============================================================================================================================

                         Fonction qui dessine le texte dans ST et qui le souligne en dessinant un trait

===============================================================================================================================*/
void dessine(HWND hwnd)
{
  LOGFONT      lf ;
  HFONT        NewFont, OldFont ;
  HDC          hdc ;

  HBRUSH       hbRed, hbGreen, hbrOld ;
  HPEN         hp2px, hpOld ;
  PAINTSTRUCT  ps;

  hdc = BeginPaint(hwnd, &ps) ;

  //*** Tracé d'une chaîne de caractères avec lettres accentuées :
    SetBkMode(hdc, TRANSPARENT) ;                // le fond du texte est transparent

    ZeroMemory(&lf, sizeof(LOGFONT)) ;

    lf.lfHeight         = 30 ;                   // définition de la hauteur des caractères
    lf.lfWidth          = 0  ;                   // largeur moyenne des caractères du texte
    lf.lfEscapement     = 50 ;                   // angle (1/10émes de degré) du vecteur échappement / l'axe des x  (???)
    lf.lfOrientation    = 0  ;                   // angle (1/10émes de degré) du       texte         / l'axe des x
    lf.lfWeight         = FW_BOLD ;              // définition de la graisse des caractères (700 pour FW_BOLD)
    lf.lfItalic         = TRUE ;                 // définition du type de texte : italique
    lf.lfUnderline      = FALSE ;                // soulignement du texte (non anticrénelé comme les caractères !!!!...)
    lf.lfStrikeOut      = FALSE ;                // texte non barré
    lf.lfCharSet        = DEFAULT_CHARSET ;      // jeu de caractères par défaut en fonction de la zone locale
    lf.lfOutPrecision   = OUT_DEFAULT_PRECIS ;   // précision de sortie                                             (???)
    lf.lfClipPrecision  = CLIP_DEFAULT_PRECIS ;  // précision d'écrêtage                                            (???)
    lf.lfQuality        = CLEARTYPE_QUALITY   ;  // qualité d'affichage CLEARTYPE_QUALITY / ANTIALIASED_QUALITY
    lf.lfPitchAndFamily = DEFAULT_PITCH ;        // pitch = la + proche distance entre luminophores (résolution) 
    lstrcpy(lf.lfFaceName,"Times New Roman") ;   // définition du nom de la police de caractères

    NewFont = CreateFontIndirect(&lf) ;          // création de la police
    OldFont = SelectObject(hdc,NewFont) ;        // sélection de la police avec sauvegarde de la précédente
    SetTextColor(hdc, RGB(255,0,0)) ;            // définition de la couleur des caractères (rouge)
    TextOut(hdc, 10, 40, st, lstrlen(st)) ;      // tracé de la chaîne de caractères
    SelectObject(hdc,OldFont) ;                  // restauration de la police précédente
    DeleteObject(NewFont) ;                      // libération de police créée

  //*** tracé du soulignement non anticrénélé par la fonction TextOut :
    hp2px = CreatePen(PS_SOLID, 2, RGB(0,0,255)) ; // création d'un crayon pour ligne continue, épaisseur et couleur
    hpOld = SelectObject(hdc,hp2px) ;              // sélection du crayon avec sauvegarde du crayon précédent
    MoveToEx(hdc, 10, 75, NULL) ;                  // déplacement du crayon en position haute (pas de tracé)
    LineTo(hdc, 545, 30) ;                         // déplacement du crayon en position basse (tracé)
    SelectObject(hdc,hbrOld) ;                     // restauration du crayon précéent
    DeleteObject(hp2px) ;                          // libération du crayon

  EndPaint(hwnd, &ps) ;

  return ;
}

/*============================================================================================================================

                                   La procédure de traitement des messgaes du système

============================================================================================================================*/
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch (uMsg)
  {
    case WM_PAINT :
        dessine(hwnd) ;
        return 0;

    case WM_DESTROY :                // traitement du click sur la croix blanche sur fond rouge en haut à droite de la fenêtre
        PostQuitMessage(0);
        return 0;

    default :
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
  }
}

/*****************************************************************************************************************************

                                                   Le maillon principal

*****************************************************************************************************************************/
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
  HWND       hwnd ;
  MSG        msg ;
  WNDCLASS   wc ;

  mon_stdout = GetStdHandle(STD_OUTPUT_HANDLE) ;         // On récupère .....
  mon_stdin  = GetStdHandle(STD_INPUT_HANDLE)  ;         //     .... les fichiers
  mon_stderr = GetStdHandle(STD_ERROR_HANDLE)  ;         //           ..... standard du programme

  wc.style         = 0 ;                                 // définit le comportement de la fenêtre
  wc.lpfnWndProc   = MainWndProc ;                       // procédure de traitement des messages du système
  wc.cbClsExtra    = 0 ;                                 // Allocation supplémentaire derrière la structure window-class    (???) 
  wc.cbWndExtra    = 0 ;                                 // allocation supplémentaire derrière la structure window-instance (???)
  wc.hInstance     = hinstance ;                         // définit que la fenêtre appartient au programme ici
  wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION) ;   // icon à utiliser en haut à gauche de la fenêtre (pas d'icon)
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW) ;       // curseur par défaut dans Windows pour cette fenêtre
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1) ;        // définit la couleur du fond de la fenêtre
  wc.lpszMenuName  =  NULL ;                             // pas de menu par défaut
  wc.lpszClassName = "MaWinClass" ;                      // nom attribué à la classe de fenêtre

  if(!RegisterClass(&wc)) return FALSE ;

  hwnd = CreateWindow( "MaWinClass"
                     , "apitest.exe"                     // titre de la fenêtre
                     ,   WS_OVERLAPPEDWINDOW             // -+
                       | WS_VSCROLL                      //  |   les ascenseurs : une partie du dessin peut être cachée
                       | WS_HSCROLL                      // -+
                     , 0, 0                              // position de la fenêtre
                     , 700, 150                          // taille de la fenêtre
                     , NULL
                     , NULL
                     , hinstance
                     , NULL
                     ) ;

  if (!hwnd) return FALSE ;
 /*
  ShowWindow(hwnd, nCmdShow) ;
  UpdateWindow(hwnd) ;
*/ 
  while(1)
  {
    DWORD n ;

//  dessine(hwnd) ;

    ShowWindow(hwnd, nCmdShow) ;
    UpdateWindow(hwnd) ;

    WriteFile(mon_stdout, "? : ", 4         , &n, NULL) ;
    ReadFile (mon_stdin , st    , sizeof(st), &n, NULL) ;                                // On saisie une commande au clavier :
    st[n] = '\0' ;

    PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ;
//  GetMessage(&msg, NULL, 0, 0) ;
    TranslateMessage(&msg) ;
    DispatchMessage(&msg) ;

    if (st[0] == 'q') break ;
  }
/*
  while (GetMessage(&msg, NULL, 0, 0) )
  {
    TranslateMessage(&msg) ;
    DispatchMessage(&msg) ;
  }
*/
  return msg.wParam ;
}
Ma question est donc le suivante, probablement toute simple pour celui qui maîtrise les API :

COMMENT mettre à jour la fenêtre pour que chaque saisie au clavier soit traduite graphiquement ?

Une deuxième petite question

De manière très classique, l'espace graphique d'un dessin peut très bien être plus grand que la surface de visualisation. Je souhaiterais donc dessiner dans une pixelmap parcourue par la fenêtre de visualisation grâce à une fonction de contrôle par scrollbars et/ou souris, d'un pivot et d'une copie partielle de la pixelmap dans celle de la fenêtre.

- Où pourrais-je trouver les outils qu'il faut ?

- Comment faut-il procéder dans la philosophie des API Windows ?


En espérant votre aide.
Bien cordialement

Lou Papet

Un petit P.S. : Je voudrais tout simplement dire à Hiko-seijuro que je n'ai jamais cherché à faire faire mon travail par les autres comme il me l'avait reproché injustement le 22 janvier 2009 en me gratifiant d'une pénalité. Quand je ne sais pas, je suis malheureusement incapable d'inventer. De plus, si, à l'approche des 80 ans, je continue à faire un peu d'informatique qui a été mon métier, c'est pour mon plaisir et ma distraction et.... accessoirement pour prévenir Alzheimer !....