IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Lazarus Pascal Discussion :

Un Bitmap rempli par code ne s'affiche pas sur TImage mais s'écrit bien dans un fichier


Sujet :

Lazarus Pascal

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 130
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 130
    Par défaut Un Bitmap rempli par code ne s'affiche pas sur TImage mais s'écrit bien dans un fichier
    Yes, it's me again, avec encore un truc de malade, mais alors comme ça, je n'avais jamais vu...

    Dans un programme trouvé chez efg, il est question de remplir un TBitmap (qui a comme petit nom BitmapHS, "HS" parce que "HSV", chez efg on fait dans le trifouillage de couleurs) avec des données, puis de le faire afficher dans un TImage.

    Rien d'anormal et j'en vois certains qui se demandent qu'est-ce que j'ai bien encore pu prendre ce midi...
    Attendez, ne partez pas, c'est là que ça devient rigolo : entre l'appel à la fonction (à qui on passe les paramètres qui vont bien) et l'instruction suivante qui consiste à afficher les données, si j'insère un BitmapHS.SaveToFile('bmptest.BMP'); , hé bien, selon certains paramètres (que je maîtrise, genre PixelFormat à 24 ou 32 bits, déclarés bien en amont) le fichier contient un magnifique cercle coloré :
    Nom : test.jpg
Affichages : 685
Taille : 10,6 Ko
    (oui oui, ce fichier a été créé par code, sinus, cosinus, scanline, toussa toussa...)

    La question c'est : pourquoi je n'ai rien dans mon TImage ? Des fois j'ai une image blanche, des fois noire, des fois grise en fonction de certains paramètres, mais ce rainbow circle, makkache bono...

    J'ai essayé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ImageHS.Canvas.Draw(0, 0, BitmapHS); // original
    ImageHS.Picture.Assign(BitmapHS);
    ImageHS.Picture.Graphic := BitmapHS; 
    BitmapHS.Canvas.StretchDraw(rect, ImageHS.Picture.Graphic );
    et je n'ai jamais vu ce cercle qui est présent dans le BitmapHS.

    Je récapitule : dans une proc j'appelle une fonction en lui passant des paramètres.
    Au retour (si j'ai bien choisi ma configuration) je crée un fichier impeccable à partir du bitmap et ensuite je le fais afficher dans le Timage.
    Sauf que l'affichage est à la rue...
    Et àmha ça ne peut pas être un problème dans le bitmap puisque le fichier est bon...

    Une dernière info à tomber par terre : dans le zip il y avait un .exe créé avec D3 (200 ko, une misère, une honte, même ), qui... fonctionne parfaitement sous XP
    À ceux qui supposeraient que je me suis foutu dedans avec mon scanline, je rappelle que le scanline a généré la magnifique image 10 lignes plus haut !

    Si quelqu'un a une idée, ou veut des précisions, qu'il n'hésite pas car là, je suis sec, moi...

  2. #2
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 931
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 931
    Billets dans le blog
    6
    Par défaut
    Et que donne un ImageHS.Picture.LoadFromFile('bmptest.BMP'); ?

    Ecrire sur le Canvas du TImage n'est pas censé fonctionner en dehors de son OnPaint :
    Citation Envoyé par freepascal.org
    Note : À l'intérieur de Image1.OnPaint Image1.Canvas pointe vers l'aire visible volatile. En dehors de Image1.OnPaint l'Image1.Canvas pointe vers Image1.Picture.Bitmap.Canvas.
    J'aurais parié sur ImageHS.Picture.Assign(BitmapHS); Il faudrait que je passe aux tests.
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  3. #3
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 130
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 130
    Par défaut
    Bonsoir, Yves,

    et bravo !
    Citation Envoyé par tourlourou Voir le message
    Et que donne un ImageHS.Picture.LoadFromFile('bmptest.BMP'); ?
    D'après toi ?
    Ben une très jolie image de cercle arc-en-ciel, lol !

    Citation Envoyé par tourlourou Voir le message
    J'aurais parié sur ImageHS.Picture.Assign(BitmapHS); Il faudrait que je passe aux tests.
    Qu'est-ce que tu veux dire par "J'aurais parié sur... " ? Que cette instruction était la solution ?

    Citation Envoyé par tourlourou Voir le message
    En fait, ce qui m'a mis sur la piste c'est ce qui précède, "n'est pas censé fonctionner en dehors de... " J'ai suivi le lien, j'y ai d'abord trouvé
    Note : À l'intérieur de Image1.OnPaint Image1.Canvas pointe vers l'aire visible volatile. En dehors de Image1.OnPaint [ce qui est mon cas] l'Image1.Canvas pointe vers Image1.Picture.Bitmap.Canvas.
    mais je n'ai pas été fichu d'utiliser Image1.Picture.Bitmap.Canvas ; par contre, en remontant un peu sur la page, j'ai retrouvé quelque chose que j'avais déjà utilisé il y a longtemps sans noter en gros en gras et au fer rouge cette histoire de peinture en dehors du OnPaint, bref, en remontant un peu sur la page, disais-je, j'ai (re-)trouvé ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        BitmapHS.SaveToStream(memstream);
        memstream.Position:=0;
        ImageHS.Picture.Bitmap.LoadFromStream(memstream);
    Et voilà

    On peut continuer à discuter, mais d'ores et déjà je peux cocher ,

    PS :qui a dit que l'informatique c'était simple ?

  4. #4
    Membre Expert

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Par défaut
    Si je peux me permettre de petites précisions sur le Canvas, Bitmap... d'un TImage :

    Un TImage utilise en interne un bitmap qui lui sert de "mémorisation" de ce qu'il doit afficher sur son propre Canvas.

    Lorsqu'on assigne une image à la propriété Picture, ce bitmap est automatiquement créé si l'on utilise une des 3 méthodes :
    • Evidemment, en assignant dans l'EDI
    • Image1.Picture.Loadfromfile('fichier.bmp')
    • Image1.Picture.Assign(monbitmap)


    Si on n'assigne pas d'image à la propriété Picture, le bitmap interne est automatiquement créé dès que l'on dessine sur le Canvas du TImage. (Image1.Canvas.Ellipse...). Le bitmap est créé à la taille actuelle du TIMage.

    Si on n'assigne pas d'image à la propriété Picture, le code suivant ne peut pas marcher :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Image1.Picture.Bitmap.Canvas.Draw(0,0,bmp);
    Et pour cause, car Picture ne contient pas encore de bitmap.

    Par contre, ceci marche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Image1.Canvas.Draw(0,0,bmp);
    L'utilisation du Canvas de TImage entraine création du bitmap interne. Si mes souvenirs sont bons, lorsque le Canvas de TImage est modifié, il y a appel à la fonction PictureChanged (qui actualise le bitmap).

    On peut donc aussi dessiner sur le Canvas de l'image et ce dessin sera repris lors du SaveToFile de TPicture.Graphic
    Mais ceci n'est valable que si on est en dehors de l'événement OnPaint du TImage. Tout ce qui est dessiné dans cet événement n'affecte pas le bitmap interne ! On parle "d'aire volatile".

    Cordialement
    Thierry

    PS: Veuillez excuser mon ton peut-être un peu professoral.

    EDIT : voir post de correction

  5. #5
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 130
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 130
    Par défaut
    Citation Envoyé par ThWilliam Voir le message
    Si je peux me permettre de petites précisions sur le Canvas, Bitmap... d'un TImage :
    You're welcome !

    Citation Envoyé par ThWilliam Voir le message
    Par contre, ceci marche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Image1.Canvas.Draw(0,0,bmp);
    L'utilisation du Canvas de TImage entraine création du bitmap interne. Si mes souvenirs sont bons, lorsque le Canvas de TImage est modifié, il y a appel à la fonction PictureChanged (qui actualise le bitmap).
    Et pourtant...
    Comme dit dans le post d'origine, c'est bien l'instruction que j'ai trouvée dans le code d'efg, et heureusement qu'il y avait aussi l'exe dans le zip, pour constater que son outil fonctionne encore sous XP et sous Seven ! Redoutables, ces exe's compilés avec D3
    En fait, je pense à des histoires de cross-compilations chatouilleuses, avec des implémentations parfois un poil différentes au niveau du code machine. C'est possible, ça ?

    Citation Envoyé par ThWilliam Voir le message
    PS: Veuillez excuser mon ton peut-être un peu professoral.
    C'est toujours un plaisir de lire des posts bien écrits et qui expliquent bien les choses ; tu reviens quand tu veux avec "ton ton professoral", moi ça m'va

  6. #6
    Rédacteur

    Avatar de gvasseur58
    Homme Profil pro
    Cultivateur de code (bio)
    Inscrit en
    Février 2013
    Messages
    1 436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Cultivateur de code (bio)
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2013
    Messages : 1 436
    Billets dans le blog
    84
    Par défaut
    Citation Envoyé par ThWilliam Voir le message
    Lorsqu'on assigne une image à la propriété Picture, ce bitmap est automatiquement créé si l'on utilise une des 3 méthodes :
    • Evidemment, en assignant dans l'EDI
    • Image1.Picture.Loadfromfile('fichier.bmp')
    • Image1.Picture.Assign(monbitmap)
    Bravo pour l'explication très claire et largement juste. Cependant, le mécanisme est un peu plus subtil : il suffit de donner une dimension au bitmap pour qu'il soit parfaitement exploitable. [Il se peut que le bitmap soit bien créé par défaut (sinon une exception serait déclenchée lorsqu'on tenterait de dessiner dedans), mais qu'il ait des dimensions nulles. Point à vérifier...]

    Nom : 2016-05-18_170025.png
Affichages : 536
Taille : 45,7 Ko

    Ainsi, on place deux images sur une fiche :

    • la première, initialisée depuis l'EDI par une image au choix, servira de source du bitmap ;
    • la seconde est vierge.


    On ajoute trois boutons :

    • le premier tente d'exécuter le code fautif qui consiste à dessiner dans un bitmap aux dimensions nulles : rien ne s'affichera [situation déjà décrite] ;
    • le second initialise les dimensions du bitmap aux valeurs voulues et le bitmap apparaît [pas besoin d'utiliser une des trois méthodes directement] ;
    • le troisième fixe les dimensions à 0 et le bitmap disparaît...


    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
    type
     
      { TForm1 }
     
      TForm1 = class(TForm)
        btnSimpleDraw: TButton;
        btnWithSize: TButton;
        btnClear: TButton;
        imgTo: TImage;
        imgFrom: TImage;
        procedure btnSimpleDrawClick(Sender: TObject);
        procedure btnWithSizeClick(Sender: TObject);
        procedure btnClearClick(Sender: TObject);
      private
        { private declarations }
      public
        { public declarations }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.lfm}
     
    { TForm1 }
     
    procedure TForm1.btnSimpleDrawClick(Sender: TObject);
    // *** ne fonctionne pas => TPicture vide ! ***
    begin
      imgTo.Picture.Bitmap.Canvas.Draw(0,0,imgFrom.Picture.Bitmap);
    end;
     
    procedure TForm1.btnWithSizeClick(Sender: TObject);
    // *** OK : TPicture dimensionné avant le dessin ***
    begin
      imgTo.Picture.Bitmap.SetSize(imgFrom.Width, imgFrom.Height);
      imgTo.Picture.Bitmap.Canvas.Draw(0,0,imgFrom.Picture.Bitmap);
    end;
     
    procedure TForm1.btnClearClick(Sender: TObject);
    // *** taille nulle => pas de dessin ! ***
    begin
      imgTo.Picture.Bitmap.SetSize(0,0);
    end;


    Citation Envoyé par ThWilliam Voir le message
    PS: Veuillez excuser mon ton peut-être un peu professoral.
    Ce n'est pas encore une insulte
    Accès à mon site et à mon blog. Actualités, cours et ressources Delphi, Lazarus et Pascal.
    Pensez à la balise - Quelqu'un vous a aidé ou vous appréciez une intervention ? Pensez au

  7. #7
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 130
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 130
    Par défaut
    Citation Envoyé par gvasseur58 Voir le message
    Bravo pour l'explication très claire et largement juste. Cependant, le mécanisme est un peu plus subtil : il suffit de donner une dimension au bitmap pour qu'il soit parfaitement exploitable. [Il se peut que le bitmap soit bien créé par défaut (sinon une exception serait déclenchée lorsqu'on tenterait de dessiner dedans), mais qu'il ait des dimensions nulles. Point à vérifier...]
    C'est bien, on fait des révisions avec TP, c'est toujours utile, je trouve

    J'ai vérifié le point dont tu parles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      with imgTo.Picture.Bitmap do
        ShowMessage(IntToStr(Width) + '--' + IntToStr(Height)); // -->  0--0
    end;
    et pas de message d'erreur.

  8. #8
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 130
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 130
    Par défaut
    Bonjour Gilles,

    je constate que toi aussi tu t'accroches, c'est bien, mais je ne sais pas où on va...

    J'ai bien lu ton test, je l'ai mis en œuvre, rien à signaler.
    Alors je me suis dit que j'allais le mettre en application dans la vraie vie et j'ai donc repris le projet qui m'a servi à dessiner ces trois magnifiques images visibles dans le post précédant le tien.

    Je me suis attaqué à l'image1, la plus facile, et ça donne ça (code complet) :
    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
    procedure TForm1.Button1Click(Sender: TObject);
    VAR
      BitmapHS      :  TBitmap;
    BEGIN
      BitmapHS := CreateCarre(image1.Width); // assume square
      try
        // AFFICHAGE
    // dessous mis en commentaire suite post Gilles
        //Image1.Canvas.Draw(0, 0, BitmapHS); 
    // test ajouté après le résultat magnifique de la ligne d'affichage, histoire de pas mourir idiot --> 200-200
        ShowMessage(inttostr(bitmaphs.Width)+'--'+inttostr(bitmaphs.Height));
    // nouvelle ligne suite post Gilles --> img 200x200 mais toute blanche
        image1.Canvas.Rectangle(0,0,BitmapHS.Width,BitmapHS.Height);
      finally
        BitmapHS.Free;
      end;
    end;
    Pour tout avoir sous les yeux, je rajoute le code (complet aussi) de la fonction appelée :
    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
    function CreateCarre(size: integer):TBitmap;
    var
      i,j           :  INTEGER;
      row           :  pRGBQuad;
      LineWidth     :  Integer;
      ScanLine      :  PByte;
    begin
      RESULT:=TBitmap.Create;
      RESULT.SetSize(size, size);
      RESULT.PixelFormat := pf32bit;
     
      LineWidth := RESULT.RawImage.Description.BytesPerLine;
      FOR i := 0 TO RESULT.Width-1 DO
      BEGIN
        ScanLine  := RESULT.RawImage.Data; // première ligne
        FOR j := 0 TO RESULT.Height-1 DO
        BEGIN
          row := pRGBQuad(Scanline);
          WITH row[i] DO
          BEGIN
        	rgbRed   := i;
        	rgbGreen := j;
        	rgbBlue  := i+j;
        	if RESULT.PixelFormat = pf32bit then rgbReserved := 192;
          END;
          Inc(ScanLine, LineWidth); // ligne(s) suivante(s)
        END; // for j
      END;  // for i
    end;
    Nom : test_gilles.png
Affichages : 536
Taille : 38,4 Ko

    À partir de là, tu te doutes bien que même pas j'essaye de voir ce que ça pourrait donner avec les cercles car, je confirme, il me suffit de commenter "ta" ligne et décommenter celle avec Draw pour retrouver mon joli carré plein de couleurs...

    Si quelqu'un veut refaire à l'arrache, une fiche un bouton une TImage 200x200 et zou.

    EDIT : un truc auquel je viens de penser, histoire d'avoir une autre certitude : après la ligne qui affiche cette image blanche, j'ai rajouté BitmapHS.SaveToFile('testgilles.bmp'); et quand j'ouvre le fichier j'ai une image colorée, et donc mon bitmap de travail est bon, ouf !

  9. #9
    Rédacteur

    Avatar de gvasseur58
    Homme Profil pro
    Cultivateur de code (bio)
    Inscrit en
    Février 2013
    Messages
    1 436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Cultivateur de code (bio)
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2013
    Messages : 1 436
    Billets dans le blog
    84
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Bonjour Gilles,

    je constate que toi aussi tu t'accroches, c'est bien, mais je ne sais pas où on va...
    Re-bonjour Jipété,

    Oui, je m'accroche, car j'ai envie de mieux maîtriser ces zinzins graphiques .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    // nouvelle ligne suite post Gilles --> img 200x200 mais toute blanche
        image1.Canvas.Rectangle(0,0,BitmapHS.Width,BitmapHS.Height);
    Là, tu n'as pas été attentif : comment obtenir autre chose qu'un rectangle blanc puisque tu demandes avec Rectangle de dessiner un rectangle sur le TCanvas ? Par défaut, ce rectangle est plein et blanc, ce que tu obtiens
    Dans le post précédent, je proposais une solution du type Image1.Canvas.Draw(0, 0, BitmapHS) (en fait Image1.Canvas.KelkeChoz): il faut écrire sur le premier TCanvas volatile qui se charge de tout. C'est dans ton exemple l'écriture qui fonctionne, non ?

    @+
    Accès à mon site et à mon blog. Actualités, cours et ressources Delphi, Lazarus et Pascal.
    Pensez à la balise - Quelqu'un vous a aidé ou vous appréciez une intervention ? Pensez au

  10. #10
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 130
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 130
    Par défaut
    Mouais, j'ai dû me faire des nœuds dans le cerveau, mes pauvres neurones sont soumis à rude épreuve, tu vas voir...
    Citation Envoyé par gvasseur58 Voir le message
    Dans le post précédent, je proposais une solution du type Image1.Canvas.Draw(0, 0, BitmapHS) (en fait Image1.Canvas.KelkeChoz): il faut écrire sur le premier TCanvas volatile qui se charge de tout. C'est dans ton exemple l'écriture qui fonctionne, non ?
    Tu dis que dans mon exemple c'est l'écriture qui fonctionne, alors pour essayer d'y voir encore plus clair, j'ai décidé d'uniformiser au maximum le contenu des trois boutons qui, pour afficher le bitmap calculé dans leurs fonctions respectives, font appel à une procédure d'affichage commune, qui va utiliser les options du RadioGroup.
    Allez hop, un bout de code :
    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
    procedure TForm1.Affiche(src: TBitmap; dst: TImage);
    var
      memstream: TMemoryStream;
    begin
      case rdg.ItemIndex of
        0:   dst.Canvas.Draw(0, 0, src);
        1: begin
             dst.Picture.Graphic := src;
             if ckbxRePaint.Checked then dst.Repaint;
           end;
        2: begin
             memstream := TMemoryStream.create;
             src.SaveToStream(memstream);
             memstream.Position:=0;
             dst.Picture.Bitmap.LoadFromStream(memstream);
             memstream.Free;
           end;
      end;
      //src.SaveToFile('testgilles.bmp');
    end;
    Et le code d'un seul bouton (les 3 sont pareils, à l'appel de la fonction de dessin près :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    procedure TForm1.Button1Click(Sender: TObject);
    VAR
      BitmapHS:  TBitmap;
    BEGIN
      image1.Picture := nil;
      // il n'y a que cet appel qui change d'un bouton à l'autre : nom de la fonction, passage de params...
      BitmapHS := CreateCarre(image1.Width); // assume square
      try
        Affiche(BitmapHS, Image1); // et ici le nom de la cible change, aussi
      finally
        BitmapHS.Free;
      end;
    end;
    Et les trois fonctions de dessin commencent de la même manière toutes les trois (sauf les 3 dernières lignes, absentes dans la fonction du bouton1 qui n'a pas besoin de background) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      RESULT:=TBitmap.Create;
      RESULT.SetSize(size, size);
      RESULT.PixelFormat := pf32bit;
     
      // Fill with background color
      RESULT.Canvas.Brush.Color := BackgroundColor;
      if bFillRect then RESULT.Canvas.FillRect(RESULT.Canvas.ClipRect);
    J'ai bon jusque là ?

    Parce que je ne mets pas de copie d'écran pour les tests avec l'option 1 du RadioGroup des méthodes d'affichage car, circulez, y a rien à voir ! Même le Image1.Canvas.Draw(0, 0, BitmapHS); qui fonctionnait jusqu'à présent est maintenant à la rue... Passons...

    Ensuite, l'option 2, Picture.Graphic :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    dst.Picture.Graphic := src;
    if ckbxRePaint.Checked then dst.Repaint;
    Déjà l'option RePaint ne sert à rien (déjà signalé, je crois) ; c'est toi qui a écrit ça hier soir :
    Si tu veux écrire dans le canevas de stockage puis l'afficher, tu dois forcer l'affichage avec Repaint :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Image5.Picture.Graphic := ecran;
    Image5.Repaint;
    Regarde la copie d'écran (réduite), c'est phacochère, euh, qu'est-ce que je raconte, là, c'est pas coché je veux dire ! (le pétage de plomb se rapproche) :

    Nom : picture_graphic_ss_chk.jpg
Affichages : 521
Taille : 19,6 Ko Le gag, là, c'est que l'activation de FillRect fait totalement disparaître l'image 2 ; déjà que l'image 3 n'y met pas du sien...

    Enfin, l'option 3 avec le TMemoryStream, et là on gagne deux copies d'écran because FillRect change la donne :
    Nom : memorystream_ss_fillrect.jpg
Affichages : 471
Taille : 22,1 Ko
    Un coup c'est bon à gauche et mauvais à droite (ci-dessus), un coup c'est l'inverse (ci-dessous) :
    Nom : memorystream_avec_fillrect.jpg
Affichages : 497
Taille : 18,1 Ko

    Bon, je vais aller faire un tour en vélo, je crois...

  11. #11
    Membre Expert

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Par défaut
    Bonjour JP et Gilles,

    il n'y a pas que vous deux qui vous accrochez... et je suis content d'entendre parler de "zinzins graphiques".
    J'ai parfois (souvent ?) trouvé qu'en informatique : pourquoi faire simple quand on peut faire compliqué ??? La preuve : ces bitmap, canvas, rawimage...
    Je suis (pré)occupé par la fonction CreateCircle (dans "projet4comparer").
    Je n'arrive pas à comprendre pourquoi le Canvas.FillRect du bitmap contrarie le traitement ultérieur du Scanline. J'ai fait plein de manips avec des beginupdate, endupdate, bitmap temporaire pour le background...
    Rien n'y fait. Ce n'est pas propre au FillRect, c'est dès qu'on touche au Canvas : Result.canvas.Pixels[0,0]:= clblue !!! et paf.
    Si je me souviens, je n'avais pas ce problème avec Delphi.
    Je ne suis pas assez compétent pour expliquer le pourquoi.

    Cela dit, on peut se passer aisément du Canvas si on veut avoir l'extérieur du cercle coloré.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    IF dSquared <= RadiusSquared
          THEN BEGIN
             // ...
          END // if dSquared
          else Row[i]:= RGBToRGBQuad(128,128,128,255); //128 à trouver d'après backgroundcolor
    Quant-à l'affichage dans le TImage, la meilleure solution dans ce programme est d'assigner le bitmap à Picture.

    J'ai toujours été titillé par la ligne : Inc(ScanLine, LineWidth);
    Cette ligne est dans boucle : FOR i := RESULT.Width-1 DOWNTO 0 DO...
    Aucune raison de passer à la ligne suivante.
    Un Inc(Row) : ok, mais comme tu utilises le pointeur Row "indicé", ce n'est pas à faire.
    Donc, ligne à supprimer.

    Cordialement
    Thierry

  12. #12
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 130
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 130
    Par défaut
    Bonjour,

    je reviens sur ça, parce qu'après vous avoir lu, et après avoir fait des manips, je voudrais partager avec vous le résultat d'un petit test -- le partager parce que tout seul, c'est vraiment trop lourd à porter.
    Qu'on en juge :
    dans une procédure quelconque de la fiche principale d'un petit programme, il y a l'appel à une fonction qui va construire toute une image dans un bitmap qu'elle va se créer, donc en gros ça ressemble à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    VAR
      BitmapHS     :  TBitmap;
    BEGIN
      BitmapHS := la_fonction(param1, param2, etc);
    Ensuite, le but de la manip c'est de faire afficher à l'utilisateur les résultats de cette construction, et donc, après l'appel de la fonction, tout ce que je m'amuse à faire c'est de commenter / décommenter des lignes dans le bout de code qui suit de manière à n'avoir qu'une seule fonctionnalité à la fois, et je vous laisse lire les commentaires rajoutés à la suite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ImageHS.Canvas.Draw(0, 0, BitmapHS); // --> image toute noire
     
    ImageHS.Picture.Graphic := BitmapHS; // --> image vide
     
    BitmapHS.SaveToStream(memstream);
    memstream.Position:=0;
    ImageHS.Picture.Bitmap.LoadFromStream(memstream); // --> cercle coloré
    Et moi je me demande (et je vais peut-être dire une énorme bêtise, mais pour l'instant je n'ai pas d'autre explication) si ces 3 résultats vraiment différents alors qu'ils ne devraient pas, si j'ai bien compris le film, ne seraient pas liés au fait qu'au lieu de trafiquer le bitmap dans la procédure, tout se joue dans une fonction planquée dans un module à grands coups de RESULT.paramètres, RESULT représentant bien entendu le bitmap.

    Si jamais tout le monde répond "oui bien sûr c'est ça", attention, je rétorque aussitôt que l'exe fourni pour Windows fonctionne très bien sous Windows ! (maintenant, il y a peut-être un écart de code entre le fichier source et le fichier binaire ?)
    Voilà voilà voilà...


    Et quand on aura trouvé la solution à cette douloureuse question, je vous parlerai du pourquoi du comment en fonction des paramètres passés j'ai le cercle coloré ou (ou exclusif !) d'autres graphiques qui s'affichent : vous verrez, c'est pas triste non plus parce que, que les graphiques calculés foirent en fonction des paramètres passés, je veux bien l'admettre, mais que ça fasse disparaître le cercle coloré où ils n'interviennent pas, là j'ai du mal...
    En résumé j'ai soit image noire, soit image vide, soit graphiques, soit cercle coloré quand je devrais avoir graphiques sur cercle coloré !

    Et les graphiques, puisqu'on en parle, c'est juste le dessin d'un cercle gris concentrique au coloré avec un rayon variable, et le dessin du rayon au max : pas de quoi fouetter un chat...
    Nom : cercletgraphics.png
Affichages : 519
Taille : 22,1 Ko Bon, l'image est toute moche (réduction de taille à l'arrache), mais vous voyez le principe.

  13. #13
    Rédacteur

    Avatar de gvasseur58
    Homme Profil pro
    Cultivateur de code (bio)
    Inscrit en
    Février 2013
    Messages
    1 436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Cultivateur de code (bio)
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2013
    Messages : 1 436
    Billets dans le blog
    84
    Par défaut
    Citation Envoyé par Jipété Voir le message
    dans une procédure quelconque de la fiche principale d'un petit programme, il y a l'appel à une fonction qui va construire toute une image dans un bitmap qu'elle va se créer, donc en gros ça ressemble à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    VAR
      BitmapHS     :  TBitmap;
    BEGIN
      BitmapHS := la_fonction(param1, param2, etc);
    Je pressens que le problème est justement dans cette fonction "quelconque". Elle peut construire toutes les images qu'elle veut, il est indispensable de créer un buffer sur lequel on dessine AVANT de le transférer sur le canevas de la fenêtre. Pire : les lignes que tu produis montrent que tu mélanges les canevas sans vergogne .

    Les résultats que tu obtiens ne sont pas vraiment surprenants : soit tu exploites un bitmap vide (dimensions nulles), soit tu affectes à une zone volatile, soit tu obtiens ce qui est recherché, car tu te sers de la zone qui contient vraiment le bitmap du cercle coloré.

    Il faut se souvenir qu'il y a DEUX zones dans une TImage (contrairement à une TPaintbox qui n'a qu'un canevas volatile).

    Il y a tout d'abord le TCanvas qui contient l'image volatile visible et redessinée à chaque appel de l'événement OnPaint. C'est celui auquel tu accèdes par exemple dans :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    BitmapHS.SaveToStream(memstream);
    Il y a ensuite TImage.Picture.Bitmap.Canvas qui contient l'image persistante. Ce canevas est indépendant de l'image affichée (qui peut être tronquée, étirée...). C'est ce que tu utilises ici :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     
    ImageHS.Picture.Bitmap.LoadFromStream(memstream);
    On se rend parfaitement compte de l'existence des deux canevas quand une image est tronquée parce que trop grande pour la zone d'affichage. Un coup de Stretched := True, et hop l'image est ajustée Mais pour être ajustée, il fallait bien qu'elle fût () stockée quelque part, non ?

    En gros, si l'on mélange les canevas volatiles et persistants, on croit obtenir des aberrations

    Pour résumer :
    TImage.Canvas = pointe vers la zone d'affichage volatile dans OnPaint et enclenche le dessin vers l'autre bitmap en dehors de ce gestionnaire d'événement ;
    TImage.Picture.Bitmap.Canvas = canevas persistant, stocke l'image réelle sur laquelle on travaille.
    Accès à mon site et à mon blog. Actualités, cours et ressources Delphi, Lazarus et Pascal.
    Pensez à la balise - Quelqu'un vous a aidé ou vous appréciez une intervention ? Pensez au

  14. #14
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 130
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 130
    Par défaut
    Merci pour tes explications.

    Je relève ça, quand même :
    Citation Envoyé par gvasseur58 Voir le message
    Je pressens que le problème est justement dans cette fonction "quelconque". Elle peut construire toutes les images qu'elle veut, il est indispensable de créer un buffer sur lequel on dessine AVANT de le transférer sur le canevas de la fenêtre. Pire : les lignes que tu produis montrent que tu mélanges les canevas sans vergogne .
    car je n'ai rien écrit de tout ce fourbi, j'essaye juste de l'adapter...

    Voici donc une copie d'écran de la procédure absolument pas retouchée (quand je récupère des trucs, je me crée un dossier "source" et cette image a été prise depuis le .pas original :
    Nom : proc_hsv.png
Affichages : 601
Taille : 19,2 Ko

    Là on est dans le .pas principal, il n'y a que 3 lignes car tout le boulot est fait par la fonction CreateHueSaturationCircle(params...) planquée dans un autre module.

    Mais les grands esprits se rencontrent : Je pressens que le problème est justement dans cette fonction "quelconque". Lis la suite, écrite il y a dix minutes :

    il est pas d'heure et ça faisait deux ou trois jours que j'étais là-dessus (bon, pas à plein temps non plus, mais pas loin), je suis vanné mais j'ai gagné : je ne sais pas si c'est Lazarus ou FreePascal qui met sa pagaille, mais malheureusement j'avais raison : le bitmap n'est pas (ou mal) renvoyé par la fonction
    C'est fou, non ?

    Car le code de la fonction, rapatrié dans une procédure en y remplaçant seulement RESULT par BitmapHS fait que ça fonctionne et que l'objet Timage reçoit bien (enfin, à condition d'utiliser la combine du Tmemorystream) les données à afficher. Grande victoire ! :
    Nom : rainbowcircle.png
Affichages : 651
Taille : 23,3 Ko

    Le seul souci qui me reste, c'est que le jaune est à 9 h quand il devrait être entre 1 et 2 h, et quand il sera là le rouge devra être à 3 h : je suis encore un peu loin du compte, de ce côté-là, mais au moins je vois quelque chose !

    Deux bouts de code avec les commentaires qui vont bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    //  BitmapHS.PixelFormat := pf24bit; // extérieur du cercle est noir :-(
      BitmapHS.PixelFormat := pf32bit;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        // Fill with background color
        BitmapHS.Canvas.Brush.Color := BackGroundColor;
    //  BitmapHS.Canvas.FillRect(BitmapHS.Canvas.ClipRect); // à commenter sinon image pas visible, même dans la procédure...
    Alors, oui, je tire à boulets rouges sur nos outils, mais j'ai écrit ça après avoir dépatouillé mes misères et avant de lire ton post, et je rappelle que l'exe fourni dans le zip fonctionne...
    Je ne sais pas si j'aurai le courage de redémarrer mon vieux portable w95 avec D3 pour aller vérifier de quoi il retourne.

  15. #15
    Rédacteur

    Avatar de gvasseur58
    Homme Profil pro
    Cultivateur de code (bio)
    Inscrit en
    Février 2013
    Messages
    1 436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Cultivateur de code (bio)
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2013
    Messages : 1 436
    Billets dans le blog
    84
    Par défaut
    Bonjour Jipété,

    Tu es courageux et opiniâtre , et tes expériences font qu'on apprend, révise et par conséquent progresse : alors, continue .

    Citation Envoyé par Jipété Voir le message
    malheureusement j'avais raison : le bitmap n'est pas (ou mal) renvoyé par la fonction
    C'est fou, non ?
    C'est fou, mais peut-être un peu faux aussi . Il est trop tôt pour je teste, mais il reste le problème de l'affectation sans préparation du résultat de ta fonction à un Bitmap non créé (et ça me gêne un peu).
    Ce qui me renforce dans mon inquiétude, c'est ce que tu écris ensuite :

    Citation Envoyé par Jipété Voir le message
    Car le code de la fonction, rapatrié dans une procédure en y remplaçant seulement RESULT par BitmapHS fait que ça fonctionne
    Il se pourrait bien que ta fonction initialise en interne correctement le Bitmap. A vérifier (promis, je vais garder un peu de temps dans la journée pour me pencher sur le problème).

    En revanche, je te rejoins entièrement quand tu soupçonnes Free Pascal / Lazarus de ne pas être tout à fait des clones de Delphi : l'implémentation des outils graphiques n'est forcément pas la même (questions de copyright et de portabilité) et ça se sent dans les programmes qui sortent des affichages triviaux. Ainsi, inutile de dépoussiérer un vieux PC : le programme d'origine (j'ai toujours admiré le site efg) est compilable en l'état par la version d'évaluation de Delphi Berlin .
    Accès à mon site et à mon blog. Actualités, cours et ressources Delphi, Lazarus et Pascal.
    Pensez à la balise - Quelqu'un vous a aidé ou vous appréciez une intervention ? Pensez au

  16. #16
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 130
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 130
    Par défaut
    Bonjour Gilles,

    et merci pour tes compliments, ils me vont droit au cœur et me font chaud à l'âme
    Citation Envoyé par gvasseur58 Voir le message
    Tu es courageux et opiniâtre , et tes expériences font qu'on apprend, révise et par conséquent progresse : alors, continue .
    Citation Envoyé par gvasseur58 Voir le message
    C'est fou, mais peut-être un peu faux aussi . Il est trop tôt pour je teste, mais il reste le problème de l'affectation sans préparation du résultat de ta fonction à un Bitmap non créé (et ça me gêne un peu).
    J'ai une piste : lors de la conversion du projet Delphi en projet Lazarus, j'ai oublié l'arrivée de {$MODE Delphi} en tête des unités, ligne qui n'existe pas quand je fais Projet / Nouveau projet... C'est ce truc qui m'a rendu fou, copier/coller un même code d'un projet à un autre et avoir un rendu différent , et m'y a fait passer un temps considérable, d'autant plus que dans l'unité principale du projet converti j'ai remplacé cette directive par {$mode objfpc}{$H+}, remplacement non fait dans les autres unités...
    Et comme l'une de ces unités embarque la fonction de dessin du cercle, ceci explique peut-être (sans doute ?) cela.
    Pas le temps de le confirmer par d'autres tests.
    Enfin bon, je vois le bout du tunnel.

    Alors pour vous remercier de votre patience à tous, et du temps que certains ont passé avec moi, d'abord une jolie image (réduite de moitié) :
    Nom : maquette.jpg
Affichages : 545
Taille : 31,3 Ko On comparera avec le cercle de l'exe original : Nom : cercletgraphics.png
Affichages : 502
Taille : 22,1 Ko -- Vue, la différence de position du rouge (et des autres) par rapport au jaune ? J'ai encore du pain sur la planche...

    Ensuite, en pseudo code les points les plus intéressants ; les commentaires en anglais sont d'origine -- noter le jonglage entre for i... for j et for j... for i avec l'imbrication des row[i] row [j] : une poule n'y retrouverait pas ses poussins, surtout avec les boutons 3 et 4 :
    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
    // bouton 1 WH:
      FOR i := 0 TO BitmapHS.Width-1 DO BEGIN
        FOR j := 0 TO BitmapHS.Height-1 DO BEGIN
          row := pRGBQuad(Scanline);
          WITH row[i] DO
     
    // bouton 2 HW:
      FOR j := 0 TO BitmapHS.Height-1 DO BEGIN
        FOR i := 0 TO BitmapHS.Width-1 DO BEGIN
          row := pRGBQuad(Scanline);
          WITH row[j] DO
     
    // bouton 3 WH:
      FOR i := 0 TO BitmapHS.Width-1 DO BEGIN
        FOR j := 0 TO BitmapHS.Height-1 DO BEGIN
          row := pRGBQuad(BitmapHS.Scanline[Image3.Width - 1 - i]);// [] va de 199 à 0
          WITH row[j] DO
     
    // bouton 4 HW:
      FOR j := 0 TO BitmapHS.Height-1 DO BEGIN
        FOR i := 0 TO BitmapHS.Width-1 DO BEGIN
          row := pRGBQuad(BitmapHS.Scanline[Image4.Width - 1 - j]);// [] va de 199 à 0
          WITH row[i] DO
     
    // bouton 5 (appel fonction) :
              // Shift 90 degrees so H=0 (red) occurs along "X" axis
    //          H := H + 90; // le jaune est à 9 h, pas bon
              H := H + 210; 
     
    // FormActivate (tout dans la procédure) :
              // Shift 90 degrees so H=0 (red) occurs along "X" axis
              H := H + 90; // le jaune est à 9 h, pas bon
    Et enfin, pour les plus courageux et/ou curieux, le zip qui permet de jouer avec cette maquette (que j'ai testé avant de le mettre en téléchargement) :
    testscanline.zip
    ch'suis pas là c't'aprème.

  17. #17
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 130
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 130
    Par défaut
    Bonsoir les copains,

    un peu désabusé/désespéré, le jp, ce soir : je voulais vous parler de trucs et de machins, après vous avoir lu et avoir fait des tests (Thierry, l'histoire du Inc(Scanline) remonte à longtemps, j'avoue n'avoir jamais trop creusé, ce que je sais c'est qu'il y a un long article chez efg, dommage qu'il ne fournisse pas l'aspirine, j'ai commenté la ligne sans voir de changements ; Gilles, l'histoire du Begin/EndUpdate [en plus ça ne s'invente pas, un truc pareil ! Mais c'est documenté nulle part] rajoute de la misère à la catastrophe), j'ai eu une illumination : j'ai pris tel quel (sans en changer une virgule) le code dégradé par l'ajout des Begin/EndUpdate, j'ai démarré une machine virtuelle sous XP et j'ai joué avec les options du RadioGroup et les 3 boutons d'images.

    Assez de discours, place à l'image, en haut Linux en bas XP :
    Nom : compar_debian_xp.jpg
Affichages : 659
Taille : 51,6 Ko

    Deux mots de commentaires : je rappelle qu'avec la mise en place de la gestion de l'affichage à partir d'une fonction, la manière Image.Canvas.Draw(0,0,Bitmap) ne fonctionne plus (alors que quand on regarde chez efg tout est écrit comme ça...), mais aussi que sous Linux la manière avec Picture.Graphic affiche vide quand il y a qqchse sous XP (l'image noire doit être liée au Begin/EndUpdate), mais surtout, surtout, avez-vous noté la différence de rendu des couleurs dans le carré ?
    Bon sang, mais c'est le même code qui tourne !
    Oups, ça y est, je pète les plombs... Mais comment font les autres pour faire du multi-plateforme qui fonctionne ?

    EDIT : j'ai trouvé pourquoi sous Linux l'option que je viens de barrer ci-dessus ne fonctionnait pas : je suis retombé sur le vieux bug du RadioGroup qui affiche un rond de sélection dans le premier item, même quand dans l'IDE c'est marqué ItemIndex = -1... Oui, j'avais oublié de le forcer (ou oublié le bug, on en a déjà parlé ici il y a longtemps).
    Bon, ça c'est réglé, ouf ! Le moral revient

Discussions similaires

  1. [Débutant] Exécuter une requete par code et l'afficher
    Par adelcrb dans le forum C#
    Réponses: 14
    Dernier message: 12/09/2013, 13h58
  2. Accéder aux colonnes d'un GridView rempli par code
    Par lamouche42 dans le forum ASP.NET
    Réponses: 4
    Dernier message: 29/04/2013, 12h10
  3. Pourquoi ce code ne m'affiche pas la bonne valeur ?
    Par Mr. X dans le forum Débuter
    Réponses: 20
    Dernier message: 19/09/2008, 09h48
  4. GUI Java par netbeans - ne s'affiche pas
    Par G_angel dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 31/01/2007, 11h38
  5. <li> ne s'affiche pas sur IE mais s'affiche sur FF
    Par pierrot10 dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 05/12/2006, 16h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo