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

Langage Delphi Discussion :

Ecran d'attente chargement


Sujet :

Langage Delphi

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Architecte
    Inscrit en
    Octobre 2005
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Architecte
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2005
    Messages : 13
    Points : 8
    Points
    8
    Par défaut Ecran d'attente chargement
    Bonjour

    je ne sais pas trop où placer cette discussion.

    Je cherche à placer un écran d'attente de chargement dans certaine de mes procédures.

    Pour cela, j'ai pensé faire une sorte de SplashScreen dans une classe à part dérivé de TThread.

    Voila le code de mon SplasScreen (image gif animée transparente).
    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
     
    unit SplashForm;
     
    interface
     
    uses
       Winapi.Windows,
       Winapi.Messages,
       System.SysUtils,
       System.Variants,
       System.Classes,
       Vcl.Graphics,
       Vcl.Controls,
       Vcl.Forms,
       GIFImg,
       Vcl.Dialogs,
       Vcl.ExtCtrls;
     
    type
     
       TMyFormSplashThread = class(TThread)
          protected
             procedure Execute; override;
     
          public
             constructor Create(CreateSuspended: Boolean);
             procedure DoTerminate; override;
       end;
     
     
       TFormSplash = class(TForm)
          ConteneurTImage: TImage;
          procedure FormClose(Sender: TObject; var Action: TCloseAction);
     
          private
             procedure Execute;
     
       end;
     
    var
       FormSplash: TFormSplash;
       MyFormSplashThread: TMyFormSplashThread;
     
    implementation
     
    {$R *.dfm}
     
     
    { MyThread }
     
    constructor TMyFormSplashThread.Create(CreateSuspended: Boolean);
    begin
       inherited Create(CreateSuspended);
     
       // Détruire à la sortie
       FreeOnTerminate := True;
     
       // Détermination de la priorité du thread
       Priority := tpHighest;
     
       FormSplash := TFormSplash.Create(Application);
     
       // Si le thread est en attente, le démarrer
       if CreateSuspended then
          Resume;
    end;
     
    procedure TMyFormSplashThread.DoTerminate;
    begin
       if Assigned(FormSplash) then begin
          FormSplash.CloseModal;
          FormSplash.Release;
          FormSplash.Free;
       end;
     
       inherited;
    end;
     
     
    procedure TMyFormSplashThread.Execute;
    begin
       FormSplash.Execute;
     
      //Boucler tant que l'utilisateur n'a pas demandé de stopper
       while not Terminated do begin
          Synchronize(Application.ProcessMessages);
    //      Synchronize(FormSplash.Refresh);
       end;
     
    end;
     
     
    { TFormSplash }
     
    procedure TFormSplash.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
       Action := caFree;
    end;
     
    procedure TFormSplash.Execute;
    var
       FullForm, Spinner: HRGN; // Declaration des HRGN
       ImageGIF: TGIFImage;
    begin
     
       FullForm := CreateRectRgn(0, 0, width, height); // R1 englobe toute la form
     
       Spinner := CreateEllipticRgn(10, 10, 210, 210); // l'exterieur du spinner
       CombineRgn(FullForm, FullForm, Spinner, RGN_AND);
       DeleteObject(Spinner);
     
       Spinner := CreateEllipticRgn(33, 33, 190, 190); // l'interieur du spinner
       CombineRgn(FullForm, FullForm, Spinner, RGN_XOR);
       DeleteObject(Spinner);
     
       SetWindowRgn(handle, FullForm, true); // Applique le tout à la form
     
       // je charge mon image animée GIF
       ImageGIF := TGIFImage.Create;
       ImageGIF.Animate := true;
       ImageGIF.LoadFromFile('Spinner220.gif');
       ConteneurTImage.Picture.Assign(ImageGIF);
     
       // et j'affiche ma form
       ShowModal;
       Refresh;
     
    end;
     
     
    end.
    Ensuite, j'appelle mon Thread depuis les procédures visées :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
       try
          self.Enabled := false;
          Splash := TMyFormSplashThread.Create(True);
     
          ............... le code me procédure ....................
     
       finally
          if assigned(Splash) then begin
             Splash.DoTerminate;
          end;
          self.Enabled := true;
       end;
    Je ne suis pas sur que cela soit très académique mais ça marche à peu près.

    Pouvez-vous me donner votre avis sur cette méthode ?
    Et si vous avez de meilleures idées, je suis preneur.

    Merci de vos remarques.

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 693
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 693
    Points : 13 128
    Points
    13 128
    Par défaut
    Appeler la VCL depuis un thread secondaire est déconseillé. C'est l'inverse qu'il faut faire : le Splash dans la tâche principale et le traitement dans la secondaire.

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Et sans thread

    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
    var
      Splash : TForm;
      try
        self.Enabled := false;
        Splash := TFormSplash.Create(nil);
        try
          Splash.Show();  
          Splash.Refresh(); // Force le dessin, plus radical : Application.ProcessMessages();    
     
          ............... le code me procédure ....................
          calcul 1
          Application.ProcessMessages();    // Pour une animation, je ne connais pas mieux
          OU
          ProgressBar.StepBy(1); 
          ProgressBar.Refresh(); // juste le dessin de la barre
     
          calcul 2
          Application.ProcessMessages();    // Pour une animation, je ne connais pas mieux
          OU
          ProgressBar.StepBy(1); 
          ProgressBar.Refresh(); // juste le dessin de la barre
     
          calcul 3...
     
     
       finally
          Splash.Free();
          self.Enabled := true;
       end;
    Pour ma part, mes traitements long contiennent un OnProgress
    Si j'ai besoin, j'attache un gestionnaire à ce OnProgress pour justement faire patientez l'utilisateur !
    Souvent une ProgressBar
    Si le nombre d'étape n'est pas prédéterminé, je fais avancé la progressbar toutes les 50 ms, une fois au Max, retour à zéro
    Et si c'est vraiment long, une animation est aussi là

    Dans le TModulexxxCalculator.Run cela appele un DoProgress ou DoProgressFlighty
    DoProgress c'est pour la cinquantaine d'étape pré-déterminé
    DoProgressFlighty c'est pour les procédures justement lancé en thread et dont je n'ai pas la maitrise du temps d'éxécution (du bon gros SQL tout simplement)

    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
     
    //------------------------------------------------------------------------------
    constructor TModulexxxCalculForm.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
     
      FCalculator := TModulexxxCalculator.Create();
      FCalculator.OnConfirmation := CalculatorConfirmationEventHandler;
      FCalculator.OnProgress := CalculatorProgress;
      FCalculator.OnProgressFlighty := CalculatorProgressFlighty;
    end;
     
    //------------------------------------------------------------------------------
    class procedure TModulexxxCalculForm.Execute();
    begin
      with Self.Create(nil) do
      try
        if TModulexxxCalculParamsForm.Execute(FCalculator) then
        begin
          PageControlCalcul.ActivePage := tsCalculRunning;
          tsCalculRunning.TabVisible := True;
          tsCalculxxx.TabVisible := False;
          tsCalculyyy.TabVisible := False;
     
          Show();
          Refresh(); // Vu que Run va bloquer, le dessin n'est pas fait !
          FCalculator.Run();
     
          Hide();
          tsCalculRunning.TabVisible := False;
          tsCalculxxx.TabVisible := True;
          tsCalculyyy.TabVisible := True;
          ShowModal();
        end;
      finally
        Free();
      end;
    end;
     
    //------------------------------------------------------------------------------
    procedure TModulexxxCalculForm.CalculatorProgress(Calculator: TModulexxxCalculator);
    begin
      if ProgressBarStep.Max <> FCalculator.StepCount then
        ProgressBarStep.Max := FCalculator.StepCount;
      ProgressBarStep.Position := FCalculator.StepIndex + 1;
      ProgressBarStep.Refresh();
     
      aniStep.Visible := False;
      aniStep.Active := False;
     
      ProgressBarStepFlighty.Position := 0;
      ProgressBarStepFlighty.Refresh();
      FTickChangeStep := GetTickCount();
      FTickFlighty := FTickChangeStep;
     
      lblStep.Caption := FCalculator.StepCaption;
      lblStep.Refresh();
    end;
     
    //------------------------------------------------------------------------------
    procedure TModulexxxCalculForm.CalculatorProgressFlighty(Calculator: TModulexxxCalculator);
    begin
      // La progression à la volée (Flighty) n'est pas prédéterminé, on donne juste l'illusion de traitement
      // On ne simule cette progression qu'à un interval régulier pour avoir une fausse progression fluide
      if (GetTickCount() - FTickFlighty) > PROGRESS_FLIGTHY_TICK_DELAY then
      begin
        if ProgressBarStepFlighty.Position >= ProgressBarStepFlighty.Max then
          ProgressBarStepFlighty.Position := 0
        else
          ProgressBarStepFlighty.StepBy(1);
        ProgressBarStepFlighty.Refresh();
        FTickFlighty := GetTickCount();
     
        // Au bout d'une seconde on affiche l'animation pour les opérations longues
        if not aniStep.Visible and (FTickFlighty - FTickChangeStep > 1000) then
          ActiveAniStep();
      end;
    end;
     
    //------------------------------------------------------------------------------
    procedure TModulexxxCalculForm.ActiveAniStep();
    begin
      aniStep.ActiveThemedTabSheetTransparence();
      aniStep.Visible := True;
      aniStep.Active := True;
    end;
    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
    //------------------------------------------------------------------------------
    procedure TModulexxxCalculator.FillCalcul();
    begin
      FillCalculCoefficientMultiplicateur();
      FillCalculCoefficientMultiplicateurSpecial();
      CheckCalculCoefficientMultiplicateur();
     
      FillCache(); // ~6 étapes réparties dans 2 fonctions 
      Fillxxx(); // ~20 étapes réparties dans 8 fonctions
      Fillyyy(); // ~30 étapes réparties dans 10 fonctions
    end;
     
    //------------------------------------------------------------------------------
    procedure TModulexxxCalculator.FillCache();
    begin
      DoProgress(Ord(csFillCache));
     
      FillCachexxx();
      FillCacheyyy();
    end;
     
    //------------------------------------------------------------------------------
    procedure TModulexxCalculator.FillCacheyyy();
    const
      SQL_...
    begin
    {$IFDEF DEBUG}
      if not FxxxGroupeMode and not DoConfirmation('FillCacheyyy ?') then
        Exit;
    {$ENDIF DEBUG}
     
      ExecSQL(SQL_DELETE_CACHE_yyy); // TRUNCATE TEMPORARY TABLE - Hors transaction !
      if not TModulexxx.Instance.DBConnection.InTransaction then
        TModulexxx.Instance.DBConnection.BeginTransaction();
     
      ExecSQL(Ord(csFillCacheyyy), SQL_INSERT_CACHE_yyy,
        ['pDateEnd', 'pCalculID'],
        [DateOf(FDateEnd), FCalculID], True);
     
      ExecSQL(Ord(csFillCacheyyyFilter), SQL_DELETE_CONTEXTE_WITHOUT_yyy,
        ['pCalculID'], [FCalculID], True);
     
      ExecSQL(Ord(csFillCacheyyyDoublon), SQL_UPDATE_INTO_CACHE_yyy_DOUBLON,
        [], [], True);
    end;
     
    //------------------------------------------------------------------------------
    procedure TModulexxxCalculator.ExecSQL(AStepIndex: Integer; const ASQLText: string; const AParamNames: array of string; const AParamValues: array of Variant; AProgressFlightyMode: Boolean = False);
    var
      I: Integer;
    begin
      DoProgress(Ord(AStepIndex));
     
      with TSLTDBQuery.Create(TModulexxx.Instance.DBConnection) do
      try
        SQLText := ASQLText;
        try
          Assert(Length(AParamNames) = Length(AParamValues), 'Length(AParamNames) <> Length(AParamValues)');
          Assert(Length(AParamNames) = ParamCount, 'Length(AParamNames) <> Query.ParamCount');
     
          for I := Low(AParamNames) to High(AParamNames) do
            ParamByName(AParamNames[I]).Value := AParamValues[I];
     
          NonBlocking := AProgressFlightyMode;
     
          // Lancement du SQL
          ExecSQL();
     
          if AProgressFlightyMode then
          begin
            while Executing do // Dans TSLTDBQuery.Executing il y a un ProcessMessages car cela utilise Devart ODAC qui je pense utilise un PostMessage (je n'en ai pas le code) pour notifier le thread principal que la Query est fini, pour MyDAC c'est différent, je l'ai codé via TThread avec un TMyConnection isolé et un event, pour ADO via TThread et Event aussi ...
            begin
              DoProgressFlighty();
              Sleep(1);
            end;
          end;
     
        except
          on E: Exception do
          begin
            TModulexxx.Instance.LogException(ExceptClass(E.ClassType), E.Message);
            raise EModulexxxCalculatorError.CreateFmt(GetErrorFmtFromStep(AStepIndex), [STEPS[TModulexxxCalculatorStep(AStepIndex)]]);
          end;
        end;
      finally
        Free();
      end;
    end;

    Il suffit de faire un Show simple non modal
    de lancer le traitement et d'ajouter si c'est une boucle, un ProgressBar.Refresh
    A l'extrème, un Application.ProcessMessages();

    une fois fini, Hide de la fenêtre
    OnCloseQuery renvoi False pour éviter que l'on ferme la patience


    Si c'est pas une boucle mais une fonction longue genre un SQL ou une fonction d'une lib que tu ne peux pas modifier
    C'est bien le SQL ou cette fonction qu'il faut mettre en Thread (attention, mieux vaut aussi utiliser une connexion dédiée)


    Faire un Thread qui fait en boucle des Synchronize(Application.ProcessMessages) revient à ne pas faire de thread !
    Tu consommes 100% du CPU (d'un core)
    Et comme le Synchronize attend que l'application soit inoccupé, si tu as un traitement encours, le Synchronize va bloquer le thread !
    Images attachées Images attachées  
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  4. #4
    Futur Membre du Club
    Homme Profil pro
    Architecte
    Inscrit en
    Octobre 2005
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Architecte
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2005
    Messages : 13
    Points : 8
    Points
    8
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Appeler la VCL depuis un thread secondaire est déconseillé. C'est l'inverse qu'il faut faire : le Splash dans la tâche principale et le traitement dans la secondaire.
    Est-ce que tu peux m'expliquer pourquoi ?

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    C'est lié au message Windows comme WM_PAINT (et un tas d'autres)
    Tu auras ainsi le thread principal qui pourra solliciter le même objet que le thread secondaire en même temps pour un code qui n'est pas prévu pour supporter cela !
    Il peut y avoir ainsi des EOSError 1400 ou des EAccessViolation ...

    C'est une restriction technique de la VCL, elle n'est pas très bien connu par les débutants et difficile a expliquer car moi même, je suis pas bien sûr de la comprendre pleinement !
    Lorsque l'on utilise l'assistant pour créer un thread, il y a un commentaire à ce sujet, je ne l'ai pas fait depuis Delphi 5 puisque souvent j'ajoute un thread dans une unité déjà existante

    A lire Utilisation du thread VCL principal
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Futur Membre du Club
    Homme Profil pro
    Architecte
    Inscrit en
    Octobre 2005
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Architecte
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2005
    Messages : 13
    Points : 8
    Points
    8
    Par défaut
    Est-ce qu'appeler ma form avec mon GIF animé depuis mon application mais avec Show (non un ShowModal pour eviter de bloquer les traitements) serait la solution ?

    Je voudrais que mon application reste inaccessible par l'utilisateur pendant le traitement.
    Solution : MyForm qui appelle le traitement (en parallèle mon GIF animé) MyForm.enabled := false ?

    Et plus de thread

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    C'est exactement ce que je fais

    Ma fenêtre de patience, je lui colle juste un OnCanClose qui retourne false tant que le calcul tourne
    Je ne touche pas au Enabled car il n'y a rien à cliquer

    Il n'y a pas de bouton, rien que TLabel, TProgress et TAnimation pendant ce temps mes calculs tournent
    une fois fini, je cache la fenêtre et l'affiche en ShowModal

    tout cela est dans le code fourni et dans l'image de la réponse précédente


    Citation Envoyé par philippe.vernhes Voir le message
    Et plus de thread
    Cela ça dépend !
    Si c'est des calculs en Delphi, des boucles, pas de soucis
    Si c'est des calculs externe via une DLL ou du SQL, j'utilise un thread pour lancer CES calculs mais il n'y a pas depuis ce thread d'interaction avec l'IHM
    Comme tu ne nous donne aucune indication sur la nature des taches longues, difficile de répondre !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

Discussions similaires

  1. [Écran] Les ecrans tactils, attention même les multitouch ne sont pas comme surface
    Par CUCARACHA dans le forum Périphériques
    Réponses: 0
    Dernier message: 21/11/2009, 14h45
  2. message attente chargement fichier swf
    Par nicoach dans le forum Dreamweaver
    Réponses: 2
    Dernier message: 28/05/2009, 18h26
  3. fenetre d'attente 'chargement en cours'
    Par sebhm dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 15/05/2009, 17h35
  4. Attente chargement d'Acrobat Reader
    Par jproto dans le forum Langage
    Réponses: 2
    Dernier message: 18/06/2008, 16h30
  5. fenetre sans bords pour attente chargement page
    Par k4eve dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 30/11/2004, 10h17

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