TStringList erreur

Résolu
ronoobresil Messages postés 7 Date d'inscription samedi 12 avril 2008 Statut Membre Dernière intervention 15 avril 2008 - 12 avril 2008 à 03:18
ronoobresil Messages postés 7 Date d'inscription samedi 12 avril 2008 Statut Membre Dernière intervention 15 avril 2008 - 12 avril 2008 à 16:27
Bonjour,

Je suis débutant sous Delphi...Ça fait pas mal de temps que j'avais pas fait de programmation
Et, bien évidemment comme tout bon débutant, j'ai un problème que je n'arrive pas à résoudre depuis quelques jours...J'ai pas mal cherché dans l'aide, sur le net, mais je commence à être à court d'idées...
J'espere que ma difficulté vous sautera aux yeux.
Je cherche à developper une petite application, sans prétention, pour ouvrir un fichier texte, stocker ses valeurs et les modifier, (puis plus tard sauver dans un autre fichier)

type
  TForm1 = class (TForm)
    Label1: TLabel;
    SpeedButton1: TSpeedButton;
    Edit1: TEdit;
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure SpeedButton1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);


  private
    { Private declarations }
  public
    { Public declarations }
  end;


var
  Form1: TForm1;
  tex:TstringList;
  filename,filepath : string;
  a:integer;
  b:string;


implementation


{$R *.dfm}

Function effacerentete(tex:TStringList;nl:integer):TStringList;
var premiercar,temp:string;
    i,j,nbre,err:integer;
    F:TStringList;
begin
    F:=TstringList.Create;
    j:=1;
    for i:=1 to nl do
    begin
      temp:=tex[i];
      premiercar:=copy(temp,1,1);
      Val(premiercar,nbre,err);
      if (err=0) then    //si premier caractere est un nomnbre
        begin
        F[j]:=Tex[i];  //rempli le TstrinList F avec les lignes correspondantes
        j:=j+1;
        end;
    end;
    Result:=F; //renvoie F comme resultat
    F.Free
end;


procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
     tex:=TstringList.Create;  // initialise tex
     with OpenDialog1 do
        begin
        if Execute then
          begin
          fileName := OpenDialog1.FileName;
          Edit1.Text:=filename;
          tex.LoadFromFile(filename); //rempli tex
          Label1.Caption:=tex[1]  //affiche la premiere ligne pour verifier le contenu
          end;
        end;
    end;


procedure TForm1.Button1Click(Sender: TObject);
begin
a:=tex.Count;   //determine le nombre de lignes
tex:=effacerentete(tex,a);   //efface les lignes commençant par autre chose que des chiffres
Label1.Caption:=tex[1];  //affiche la premiere ligne (verification)
tex.Free  //libere tex
end;


end.

Deux choses:-tout marche jusqu'à tex:=effacerentete(tex,a); ...La ça coince... Il n'a pas l'air de rentrer dans la focntion, plante avant.
                     -si je place
STR(a,b);
Label1.Caption:=b;
avant l'appel de la fonction effacerentete Label1n'affiche pas la valeur de b (meme si je mets un sleep(2000) juste après. Mais l'affiche si je supprime l'appel de la focntion...

Je suppose que c'est la même cause.. Merci pour tout,

6 réponses

cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
12 avril 2008 à 10:02
Je te laisse deviner où est ton erreur :
Function effacerentete(tex:TStringList;nl:integer):TStringList;
var premiercar,temp:string;
    i,j,nbre,err:integer;
    F:TStringList;
begin
    F:= TstringList.Create;
    j:=1;
    for i:=1 to nl do
    begin
      temp:=tex[i];
      premiercar:=copy(temp,1,1);
      Val(premiercar,nbre,err);
      if (err=0) then    //si premier caractere est un nomnbre
        begin
        F[j]:=Tex[i];  //rempli le TstrinList F avec les lignes correspondantes
        j:=j+1;
        end;
    end;
    Result:=F; //renvoie F comme resultat
    F.Free
end;

Si tu libères l'objet retourné, comment veux-tu pouvoir y accéder ensuite si la référence tex est nulle ???
Ce genre de programmation est à proscrire et il faut revenir aux fondamentaux : c'est à l'appelant de détruire les objets qu'il crée et non à l'appelé. Sinon, quand le code devient un tant soit peu complexe, on se fait vite avoir.
Je te propose une autre forme, cette fois sans risque :
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    OpenDialog1: TOpenDialog;
    SpeedButton1: TSpeedButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
var
  tex: TstringList;
  a: integer;
  FileName: TFileName;

procedure EffacerEntete(Tex: TStringList; nl: integer);
var
  i: integer;
  F: TStringList;
begin
  if nl < 0 then
    exit;
  F : = TstringList.Create;
  try
    for i := 1 to nl do
      if length(Tex[i]) > 0 then
      begin
        if Tex[i][1] in ['0'..'9'] then
          F.Append(Tex[i]);
      end;
    Tex.Assign(F);
  finally
    F.Free
  end; {try..finally}
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  a := tex.Count; //determine le nombre de lignes
  effacerentete(tex, a);
  //efface les lignes commençant par autre chose que des chiffres
  Label1.Caption := tex[1]; //affiche la premiere ligne (verification)
  ///////////////// tex.Free NON, non et non !
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  ///////////////// tex := TstringList.Create; // NON !!!
  if OpenDialog1.Execute then
  begin
    fileName := OpenDialog1.FileName;
    Edit1.Text := filename;
    tex.LoadFromFile(filename); //rempli tex
    Label1.Caption := tex[1]
  end;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Tex := TStringList.Create
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Tex.Free;
end;

end.

Tu remarqueras certains commentaires destinés à attirer ton attention sur les risques que tu prends en instanciant un TStringList dans button1click et en le libérant dans speedbutton1click. Il est préférable, vu que ce composant n'a pas de propriétaire, de s'assurer qu'il sera libéré dans tous les cas de figure. Ici, le composant Tex est intsnacié dans le OnCreate de la fiche et libéré dans le OnClose.

May Delphi be with you !
<hr color="#008000" />Pensez à cliquer sur Réponse acceptée lorsque la réponse vous convient.
3
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
12 avril 2008 à 10:04
J'ai oublié de préciser que l'emploi de :
if Tex[i][1] in ['0'..'9'] then
          F.Append(Tex[i]);
est surement moins coûteux en temps de traitement que l'emploi de la fonction VAL.

Bonne journé et  May Delphi be with you !
<hr color="#008000" />Pensez à cliquer sur Réponse acceptée lorsque la réponse vous convient.
3
schnawd Messages postés 20 Date d'inscription mardi 5 octobre 2004 Statut Membre Dernière intervention 12 juillet 2015
12 avril 2008 à 10:11
Bonjour,

Serrait-il possible de savoir la tête que ton fichier aura, et ce que tu veux récupérer dedant.

Sinon pour sauver plus tard les données dans un autre fichier, si l'application se ferme, alors tu perds tout, Donc ans ce cas là tu dois l'enregistrer dans un fichier temporaire, puis le recharger à chaque redémarrage de l'appli.

Sinon au lieu d'utiliser un label, utilise un memo que tu mets en read-only, car si j'ai bien compris b est de type TStringList, donc tu peux te débrouiller à le mettre en TStrings, de façon à faire un
memo.lines := b;

Et puis tu fais ce que tu veux du style de memo, tu peux très bien le faire ressembler à un TCaption.

J'espère avoir bien saisie ton sujet.

$cHn4wD
3
ronoobresil Messages postés 7 Date d'inscription samedi 12 avril 2008 Statut Membre Dernière intervention 15 avril 2008
12 avril 2008 à 15:11
Merci pour la rapidité (et l'efficacité) de la réponse.
Mes fichiers ASCII se présentent sous la forme suivante:
-Une entête avec quelques lignes de texte (programme de création, date, parametres divers) =>à supprimer
-Un tableau de 7 ou 8 colonnes d'entier séparés par des tabulations, dont je ne veux garder que certaines colonnes.

Je desire faire de petites opérations, un tri de ces valeurs et remettre une entête (que le programme pour lequel je fais cette conversion reconnaisse).
Mon but est de formater mon fichier ASCII pour qu'il soit utilisable par une seconde application.(déjà existante).
En tout cas merci, ça me remotive, j'y retourne....

Renaud
3

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
ronoobresil Messages postés 7 Date d'inscription samedi 12 avril 2008 Statut Membre Dernière intervention 15 avril 2008
12 avril 2008 à 16:10
Rebonjour,
La procédure liée au click speedbutton1 ne fonctionne pas jusqu'au bout (plantage avant).

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
  begin
    fileName := OpenDialog1.FileName;
    Edit1.Text := filename;
    tex.LoadFromFile(filename); //la procedure semble planter sur cette ligne  
    Label1.Caption := tex[1]
  end;
end;

Instantanément après de la selection du fichier, ça coupe, avec le message d'erreur suivant:
"Project Project1.exe raised execption class EAccessViolation with message
"Access Violation at address 00454584 in module Project1.exe". Read of address 000000000. Access stopped"

Je tourne depuis une ou deux heures...J'espere que vous pourrez m'éclairer à nouveau. Bonne journée,

Renaud
3
ronoobresil Messages postés 7 Date d'inscription samedi 12 avril 2008 Statut Membre Dernière intervention 15 avril 2008
12 avril 2008 à 16:27
Quel ****** je suis..J'avais associé la procedure de fermeture mais pas celle d'ouverture avec l'objet Form.

Renaud
3
Rejoignez-nous