Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Einträge nicht nur aus Listbox entfernen (https://www.delphipraxis.net/154137-eintraege-nicht-nur-aus-listbox-entfernen.html)

jawo3 29. Aug 2010 15:04

Einträge nicht nur aus Listbox entfernen
 
Hallo,
ich habe vor einigen Tagen schon mal eine Frage zu meinem derzeitigen Programm gestellt und ihr konntet mir schnell und kompetent weiterhelfen. Leider bin ich jetzt auf ein neues Problem gestoßen, dass wieder damit zusammenhängt, dass ich mich noch nicht so gut mit Zeigern auskenne, was sich hoffentlich bald ändern wird.

Es geht erneut um das "Vokabel-Programm" in dem Wörter abgespeichert werden sollen und diese dann in einer ListBox ausgegeben werden. Ich arbeite gerade daran, dass Wörter innerhalb der ListBox mit der Maus markiert werden, und nach Klick auf einen Button aus der ListBox entfernt werden. Das funktioniert soweit auch sehr gut. Das Problem ist nur, dass die Wörter nicht aus meiner Zeigerstruktur entfernt werden, sondern nur aus der ListBox. Das heißt, wenn ich den "Einträge Anzeigen" Button drücke, erscheinen alle EInträge erneut in meiner ListBox, inklusive derjenigen, die eigentlich schon hätten gelöscht werden sollen.

Ich weiß leider nicht sorecht, wie ich das Problem beheben kann. Vielleicht könnt ihr mir ja ein bisschen auf die Sprünge helfen, dass wäre sehr nett.

Hier mal das Programm. Die Stelle, an der ich gerade arbeite, habe ich mit einem Kommentar-Block versehen:

Delphi-Quellcode:
unit Vokabeln;

interface

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

type
    TForm1 = class(TForm)
      Label1: TLabel;
      EditEintragen: TEdit;
      ListBoxAnzeige: TListBox;
      ButtonEintragen: TButton;
      ButtonEntfernen: TButton;
      ButtonAnzeigen: TButton;
      RadioButtonLIFO: TRadioButton;
      RadioButtonFIFO: TRadioButton;
      ButtonLeeren: TButton;
      ButtonSpeichern: TBitBtn;
      ButtonLaden: TBitBtn;
      ButtonBeenden: TBitBtn;
      ButtonMarkieren: TButton;
      procedure ButtonBeendenClick(Sender: TObject);
      procedure ButtonEintragenClick(Sender: TObject);
      procedure ButtonEntfernenClick(Sender: TObject);
      procedure ButtonSpeichernClick(Sender: TObject);
      procedure ButtonLadenClick(Sender: TObject);
      procedure ButtonAnzeigenClick(Sender: TObject);
      procedure FormActivate(Sender: TObject);
      procedure EditEintragenKeyPress(Sender: TObject; var Key: Char);
      procedure ButtonLeerenClick(Sender: TObject);
      procedure SpeicherFreigeben;
      procedure ListBoxAnzeigeKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
      procedure RadioButtonFIFOClick(Sender: TObject);
      procedure RadioButtonLIFOClick(Sender: TObject);
    procedure ButtonMarkierenClick(Sender: TObject);
    end;
    Zeiger = ^Element;    //Definition eines Zeigertyps
    tInhalt = string[15];
    Element = record
                naechster: Zeiger;
                Inhalt: tInhalt;
              end;

const Datenpfad='Vokabeln.dta';            //Hier wird die Datenbank gespeichert

var
  Form1: TForm1;
  Wurzel, z : Zeiger;                      //nötig um Liste aufzubauen
  f: file of tInhalt;                      //nötig für Speicher-/Ladevorgang

function Kontrolle:Boolean;

implementation

{$R *.dfm}

procedure TForm1.FormActivate(Sender: TObject);  //Bei Programm-Start
begin
EditEintragen.SetFocus;      //Fokus auf Eintragen-Textfeld setzen
Wurzel:=nil;  //Wurzel markiert erstes greifbares Element und wird zunächst "geerdet"
end;

function Kontrolle;  //Test auf gängigste IO-Fehler
begin
  result := false;
  case IOResult of
     0: result := true;
     2: begin showmessage ('Datei nicht vorhanden.' +#13+ 'Datei wird angelegt');
          rewrite(f);
          result := true;
        end;
     3: showmessage ('Ungueltiger Dateiname/Pfad');
     5: showmessage ('Dateizugriff verweigert.');
    21: showmessage ('Laufwerk nicht bereit!');
  end;
end;

procedure TForm1.EditEintragenKeyPress(Sender: TObject; var Key: Char);  //Eintragen über Enter Taste
begin
if (Key=#13) and (length(EditEintragen.Text)<>0) then
  begin
      Key:=#0;
      ButtonEintragenClick(Sender);    //Wenn "Enter" gedrückt wird dann eintragen
      ButtonAnzeigenClick(Sender);     //Neue Liste anzeigen
      EditEintragen.SetFocus;          //Fokus auf Textfeld setzen
  end;
end;

procedure TForm1.ButtonEintragenClick(Sender: TObject);   //Vokabeln eintragen
begin
if length(EditEintragen.Text)<>0 then    //Wenn Textfeld nicht leer ist
begin
    New(z);                             //Erzeugen eines neuen Listenelements
    z^.Inhalt:= EditEintragen.Text;     //Record wird befüllt
    z^.naechster:=Wurzel;               //Zeiger "naechster" wird bisheriger Wurzelwert zugewiesen
    Wurzel:=z;                          //Zeiger Wurzel wird auf z "verbogen"
    EditEintragen.Text:='';             //Textfeld wieder leeren
    ButtonAnzeigenClick(Sender);        //Neue Liste anzeigen
    EditEintragen.SetFocus;             //Fokus auf Textfeld setzen
end;
end;

procedure TForm1.RadioButtonFIFOClick(Sender: TObject);
begin
ButtonAnzeigenClick(Sender);     //Neue Liste anzeigen
end;

procedure TForm1.RadioButtonLIFOClick(Sender: TObject);
begin
ButtonAnzeigenClick(Sender);     //Neue Liste anzeigen
end;

procedure TForm1.ButtonAnzeigenClick(Sender: TObject);   //Prozedur zum Anzeigen der Vokabelliste
begin
if RadioButtonFIFO.Checked then                //Wenn FIFO-Modus aktiviert...
begin
  ListBoxAnzeige.Items.Clear;                  //Listbox wird zunächst geleert...
  z:=Wurzel;
  while z<>nil do                              //...und mit neuer Liste befüllt
    begin
    ListBoxAnzeige.Items.Insert(0,z^.Inhalt);
    z:=z^.naechster;
    end;
end
else if RadioButtonLIFO.Checked then           //Wenn LIFO-Modus aktiviert...
begin
  ListBoxAnzeige.Items.Clear;                  //Listbox wird zunächst geleert...
  z:=Wurzel;
  while z<>nil do                              //...und mit neuer Liste befüllt
    begin
    ListBoxAnzeige.Items.Add(z^.Inhalt);
    z:=z^.naechster;
    end;
end;
end;

procedure TForm1.ButtonLeerenClick(Sender: TObject);  //Listbox wird geleert
begin
ListBoxAnzeige.Items.Clear;
end;

procedure TForm1.ListBoxAnzeigeKeyDown(Sender: TObject; var Key: Word;  //Entfernen mit Hilfe der "Delete" Taste
  Shift: TShiftState);
begin
if (Key=VK_DELETE) then ButtonEntfernenClick(Sender);  //Entfernen-Button klicken
end;

procedure TForm1.ButtonMarkierenClick(Sender: TObject);  //Prozedur markiert alle Einträge der Listbox
var min, max: integer;
begin
max:=ListBoxAnzeige.Count;
for min:=1 to max do ListBoxAnzeige.Selected[min-1]:=true;
end;

procedure TForm1.ButtonEntfernenClick(Sender: TObject);   //Button entfernt markierte Einträge aus der Liste
var ii : integer;
    letzter : integer;
begin
if ListBoxAnzeige.Count<>0 then
begin
  with ListBoxAnzeige do
  begin
    for ii := -1 + Items.Count downto 0 do
    if Selected[ii] then
    begin
      Items.Delete(ii);
      letzter:=ii;
    end;
  end;
  if ListBoxAnzeige.Count<=letzter then dec(letzter);    //Eintrag an der Stelle der letzten Löschung wird markiert
  ListBoxAnzeige.Selected[letzter]:=true;

//-------------------------------------------------------------------------------------
//----------------------->Schleife, die Änderungen in die Zeigerstruktur übernimmt
//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
end;
end;

procedure TForm1.SpeicherFreigeben;     // Speicher für den Zeiger wird freigegeben
var DelPointer : Zeiger;
begin
  while Wurzel <> nil do begin
    DelPointer:=Wurzel;
    Wurzel:=Wurzel^.naechster;
    dispose(DelPointer);
  end;
  Wurzel:=nil;
end;

procedure TForm1.ButtonSpeichernClick(Sender: TObject); //Vokabeldatenbank speichern
var RunPointer : Zeiger;
begin
  Assignfile(f, Datenpfad);
  try
    rewrite(f);
    RunPointer:=Wurzel;
    while RunPointer <> nil do
    begin
      write(f, RunPointer^.Inhalt);
      RunPointer:=RunPointer^.naechster;
    end;
    showmessage('Vokabel-Verzeichnis erfolgreich gespeichert'); //Erfolgsmeldung ausgeben
  finally
    closefile(f);
  end;
end;

procedure TForm1.ButtonLadenClick(Sender: TObject); //Vokabeldatenbank laden
var NewPointer, OldPointer : Zeiger;
begin
  SpeicherFreigeben;
  Assignfile (f, Datenpfad);
  try
    reset(f);
    OldPointer:=nil;
    while not eof(f) do //Auslesen bis Ende der Datei erreicht wird
    begin
      new(NewPointer);
      read(f, NewPointer^.Inhalt);
      NewPointer^.naechster:=nil;
      if OldPointer <> nil then
        OldPointer^.naechster:=NewPointer;
      if Wurzel = nil then
        Wurzel:=NewPointer;
      OldPointer:=NewPointer;
    end;
    ButtonAnzeigenClick(Sender);     //Geladene Liste anzeigen
    showmessage('Datenbank erfolgreich geladen'); //Erfolgsmeldung ausgeben
  finally
    closefile(f);
  end;
end;

procedure TForm1.ButtonBeendenClick(Sender: TObject);  //Programm beenden
begin
  close;
end;

end.
Vielen Dank im Voraus
jawo3

DeddyH 29. Aug 2010 15:46

AW: Einträge nicht nur aus Listbox entfernen
 
Eine Frage vorweg: handelt es sich um eine Hausaufgabe, oder wieso verwendest Du eine einfach verkettete Liste? Da es sich ja eh nur um Strings handelt, könntest Du sonst genausogut eine TStringlist verwenden, das wäre um Längen einfacher. Der Vollständigkeit halber aber hier die Vorgehensweise:
- Durchiterieren der Liste
- wenn Nachfolgeelement das gesuchte ist, dessen Nachfolger merken (1)
- Zeiger auf das Nachfolgeelement merken (2)
- Nachfolger des aktuellen Elements auf gemerkten (1) setzen
- gemerkten Zeiger (2) freigeben

Schau einmal in der Tutorials-Sparte, IIRC gibt es da auch ein Tut dazu, das das Ganze detaillierter beschreibt.

jawo3 30. Aug 2010 15:09

AW: Einträge nicht nur aus Listbox entfernen
 
Hi,
danke für die Antwort. Ja, die einfach verkettete Liste war eine Vorgabe.
Ich werde mal versuchen, das von dir Beschriebene umzusetzen.

Ich melde mich dann nachher nochmal.

Gruß
jawo3

DeddyH 30. Aug 2010 15:28

AW: Einträge nicht nur aus Listbox entfernen
 
Ich würde es übrigens andersherum machen: zuerst aus der verketteten Liste löschen und dann die Listbox komplett neu aus dieser Liste füllen, dann sieht man auch, ob alles funktioniert hat. Wenn es sich nicht um allzuviele Einträge handelt und man BeginUpdate/EndUpdate beim Befüllen der ListBox verwendet, sollte das auch ausreichend performant sein.

Luckie 30. Aug 2010 15:39

AW: Einträge nicht nur aus Listbox entfernen
 
Guck mal hier: http://www.michael-puff.de/Programmi...orials/Listen/

jawo3 30. Aug 2010 15:43

AW: Einträge nicht nur aus Listbox entfernen
 
Ich schau mir das mal an danke...

jawo3 30. Aug 2010 15:56

AW: Einträge nicht nur aus Listbox entfernen
 
Ich habe mir das jetzt so gedacht für den Entfernen-Button, aber leider funktionier das nicht.
Ich erhalte die Fehlermeldung: Invalid Pointer Operation.

Hier der Quelltext zum Entfernen Button:
Delphi-Quellcode:
procedure TForm1.ButtonEntfernenClick(Sender: TObject);   //Button entfernt markierte Einträge aus der Liste
var ii: integer;
    letzter : integer;
begin
  if ListBoxAnzeige.Count<>0 then
  begin
  with ListBoxAnzeige do
      begin
        for ii := -1 + Items.Count downto 0 do
        if Selected[ii] then
        begin
          z:=Wurzel;
            while z<>nil do                              //Schleife, die Änderung in die Zeigerstruktur übernimmt
              begin
                z:=z^.naechster;
                z^.naechster:=z^.naechster.naechster;
                Dispose(z);
              end;
          Items.Delete(ii);
          letzter:=ii;
        end;
      if ListBoxAnzeige.Count<=letzter then dec(letzter);    //Eintrag an der Stelle der letzten Löschung wird markiert
      ListBoxAnzeige.Selected[letzter]:=true;
      end;
  end;
end;
Vielen Dank im Voraus
jawo3

DeddyH 30. Aug 2010 16:00

AW: Einträge nicht nur aus Listbox entfernen
 
Du willst innerhalb der For-Schleife die komplette verkettete Liste bis auf die Wurzel freigeben?

jawo3 30. Aug 2010 16:04

AW: Einträge nicht nur aus Listbox entfernen
 
Eigentlich nicht:oops:

Ich muss also noch einschränken und abgleichen, ob das markierte Element dem aktuellen Zeiger entspricht?

jawo3 30. Aug 2010 16:08

AW: Einträge nicht nur aus Listbox entfernen
 
Dieser Versuch ist leider auch kläglich gescheitert:

Delphi-Quellcode:
procedure TForm1.ButtonEntfernenClick(Sender: TObject);   //Button entfernt markierte Einträge aus der Liste
var ii: integer;
    letzter : integer;
begin
  if ListBoxAnzeige.Count<>0 then
  begin
  with ListBoxAnzeige do
      begin
        for ii := -1 + Items.Count downto 0 do
        if Selected[ii] then
        begin
          z:=Wurzel;
            while z<>nil do                              //Schleife, die Änderung in die Zeigerstruktur übernimmt
              begin
                z:=z^.naechster;
                if ListBoxAnzeige.Items[ii]=z^.Inhalt then
                begin
                  z^.naechster:=z^.naechster.naechster;
                  Dispose(z);
                end;
              end;
          Items.Delete(ii);
          letzter:=ii;
        end;
      if ListBoxAnzeige.Count<=letzter then dec(letzter);    //Eintrag an der Stelle der letzten Löschung wird markiert
      ListBoxAnzeige.Selected[letzter]:=true;
      end;
  end;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:40 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz