Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   Delphi AutoComplete für TMemo, TRichEdit uvm. (https://www.delphipraxis.net/125828-autocomplete-fuer-tmemo-trichedit-uvm.html)

Woodman 12. Dez 2008 15:53


AutoComplete für TMemo, TRichEdit uvm.
 
Liste der Anhänge anzeigen (Anzahl: 2)
Nachdem ich mir einen "Wolf" gesucht hatte und außer SynEdit nichts passendes gefunden habe (was mir für meine Zwecke etwas zu komplex ist), habe ich mir meine eigene TAutoComplete-Komponente geschrieben.
Ich wollte für eine eigene Anwendung eine AutoComplete-Funktion haben, ähnlich wie sie die Delphi-IDE bietet.

Die Unit "autocomplete" kann für Klassen verwendet werden, die auf TEdit basieren,
wie z.B. TMemo, TRichEdit, TEdit, TLabeledEdit usw.
Die Initialisierung geschieht z.B. folgender Maßen:
Delphi-Quellcode:
AutoComplete1 := TAutoComplete.Create(Form1,'TextDatei',Memo1);
Damit wird die Komponente 'Memo1' um AutoComplete erweitert.
Die Textdatei enthält das für Memo1 wichtige Wörterbuch.

In das Wörterbuch sollten nur Wörter eingetragen werden, die länger als 4 Zeichen sind.
AutoComplete reagiert erst ab 3 Zeichen Eingabe.

Ist für die Edit-Komponente ein Popup-Menu definiert, dann wird dieses um den
Menupunkt "Markierten Text in Wörterbuch übernehmen." erweitert

Wichtig: Durch AutoComlete werden die Ereignisbehandlungen 'OnChange', 'OnKeyDown', 'OnKeyPress' und 'OnContextPopup'überschrieben.
Sollten diese im Hauptprogramm benötigt werden, ist diese Lösung zunächst nicht einsetzbar.

In der ZIP-Datei befindet sich die Unit autocomplete.pas und das passende Testprogramm dazu.

Hier ein Auszug aus dem Testprogramm:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
   AutoComplete1 := TAutoComplete.Create(self,'worte.txt',Memo1);
   AutoComplete2 := TAutoComplete.Create(Form1,'plz.txt',LabeledEdit1);
   AutoComplete3 := TAutoComplete.Create(Form1,'words4.txt',RichEdit1);
   
end;
Wie man sieht, werden hier 3 Komponenten mit 'AutoComplete' erweitert.
Zugegeben: Das Beispiel mit dem LabeledEdit1 kann man auch mit TComboBox realisieren, aber mir ging es ja hauptsächlich um TMemo und eventuell um TRichEdit.
Das Beispiel für TMemo habe ich mit einer Textdatei hinterlegt, wie sie bei mir zum Einsatz kommt(Für ein Dia-Verwaltungsprogramm).
Bei dem LabeledEdit1 habe ich eine Postleitzahlendatei hinterlegt (ohne Gewähr :wink: )
Die RichEdit-Box reagiert vielleicht etwas träge. Das liegt daran, das ich hier versucht habe, TAutoComplete auszureizen: Die dazugehörige Textdatei 'words4.txt' ist über 2MB groß (über 150000 Zeilen).

Falls sich jemand wundert, warum ich RichEdit auf ein Panel gepackt habe und auf das Panel noch ein TabControl und darauf das Memo: Das hatte ganz einfach den Zweck, die Positionsfindung für AutoComplete zu testen, mit einem einfachen "ClientToParent" war es nicht getan...

Im beiliegenden Screenshot kann man das Testprogramm in Aktion sehen.

sx2008 13. Dez 2008 18:41

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Was mir nicht so gut gefällt, ist dass der Owner im Konstruktor mitgegeben werden muss.
Gerade dein Beispiel:
Delphi-Quellcode:
 AutoComplete2 := TAutoComplete.Create(Form1,'plz.txt',LabeledEdit1);
zeigt, dass man damit schwerzufindende Fehler begehen kann.
Folgendes Beispiel zeigt, dass man Formulare auch mit lokalen Variablen erstellen kann.
Delphi-Quellcode:
procedure Test;
var
  x : TForm1;
begin
  x := TForm1.Create(nil);
  x.ShowModal;
  x.Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
  // Fehler: Owner ist Form1 - richtig kann aber nur self sein
  AutoComplete := TAutoComplete.Create(Form1,'plz.txt',LabeledEdit1);
end;
Um dieses Problem aus der Welt zu schaffen, würde ich folgende Änderung vorschlagen:
Delphi-Quellcode:
constructor TAutoComplete.Create(const Edit: TControl; const TxtFile: String);
begin
  Assert(Assigned(Edit));
  Inherited Create(Edit.Owner);      // gleicher Owner, den auch Edit hat
  Parent := Edit.Parent;             // dito *)
Bei der Zeile mit dem *) könnte sich jetzt ein Problem ergeben, weil vorher der Parent das Formular war und jetzt kann es auch eine Groupbox sein.
Dann kann man aber so lange über Parent nach "oben" gehen, bis man auf dem Formular gelandet ist.
Delphi-Quellcode:
var
  tmp : TControl;
begin
  tmp := Edit.Parent;
  while Assigned(tmp.Parent) do tmp := tmp.Parent;
  Parent := tmp;

SirThornberry 13. Dez 2008 19:10

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Die Idee an sich finde ich gut. Was ich nicht so toll finde ist eben die Umsetzung das es eine Datei sein muss und das die Ereignisse dann nicht mehr nutzbar sind.
Auch die minimale Anzahl von Zeichen, finde ich, sollte einstellbar sein.

Insgesamt soll das heißen: Bleib an der Idee dran und versuche es zu verfeiern/verbessern.

Woodman 14. Dez 2008 17:21

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von sx2008
Was mir nicht so gut gefällt, ist dass der Owner im Konstruktor mitgegeben werden muss.
Gerade dein Beispiel:
Delphi-Quellcode:
 AutoComplete2 := TAutoComplete.Create(Form1,'plz.txt',LabeledEdit1);
zeigt, dass man damit schwerzufindende Fehler begehen kann.
Folgendes Beispiel zeigt, dass man Formulare auch mit lokalen Variablen erstellen kann.

Verzeih' einem Anfänger, das ich Dir nicht ganz folgen kann :wall:
Was ist falsch daran, den Owner mit zu geben?
Ich will ja gerade, das die unterste Komponente (Form1) der Owner ist. Gerade in meinem Beispiel, bei dem das TMemo auf einem TPanel und dieses wiederum auf einem TTabControl sitzt ist es wichtig, das als Parent für den TListView (TAutoComplete) die Form ist.
Zitat:

Zitat von sx2008
...
Bei der Zeile mit dem *) könnte sich jetzt ein Problem ergeben, weil vorher der Parent das Formular war und jetzt kann es auch eine Groupbox sein.

Eben, deswegen sorge ich dafür, das der Parent von TAutoComplete immer das Formular ist.

himitsu 14. Dez 2008 17:33

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Wichtig: Durch AutoComlete werden die Ereignisbehandlungen 'OnChange', 'OnKeyDown', 'OnKeyPress' und 'OnContextPopup'überschrieben.
Sollten diese im Hauptprogramm benötigt werden, ist diese Lösung zunächst nicht einsetzbar.
dann überschreib die Eigenschaften doch nicht einfach!

ließ die vorherrigen Werte aus und ruf (falls da schon etwas eingetragen ist) dieses in deiner Klasse auf.

Woodman 14. Dez 2008 17:36

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von SirThornberry
Die Idee an sich finde ich gut.

Danke :-D
Zitat:

Zitat von SirThornberry
Was ich nicht so toll finde ist eben die Umsetzung das es eine Datei sein muss

Könntest Du mir bitte das näher erläutern - ich verstehe jetzt nicht was Du meinst. :oops:
Zitat:

Zitat von SirThornberry
und das die Ereignisse dann nicht mehr nutzbar sind.

Ich könnte natürlich falls eine Eventbehandlung schon besetzt ist, diese mit übernehmen.
Aber: Welche Eventbehandlung führe ich zu erst aus, die vom Hauptprogramm oder die von TAutoComplete? Ober "beißen" sich die beiden Eventbehandlunge gar?
Ich fürcht, das muss jeder individuell beurteilen und in seinem Programm anpassen.
Zitat:

Zitat von SirThornberry
Auch die minimale Anzahl von Zeichen, finde ich, sollte einstellbar sein.

Nun ja, im Programm kannst Du es ja einstellen. :P

Zitat:

Zitat von SirThornberry
Insgesamt soll das heißen: Bleib an der Idee dran und versuche es zu verfeiern/verbessern.

EDIT:
Zitat:

Zitat von himitsu
Zitat:

Wichtig: Durch AutoComlete werden die Ereignisbehandlungen 'OnChange', 'OnKeyDown', 'OnKeyPress' und 'OnContextPopup'überschrieben.
Sollten diese im Hauptprogramm benötigt werden, ist diese Lösung zunächst nicht einsetzbar.
dann überschreib die Eigenschaften doch nicht einfach!

ließ die vorherrigen Werte aus und ruf (falls da schon etwas eingetragen ist) dieses in deiner Klasse auf.

siehe oben.

himitsu 14. Dez 2008 18:54

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Könntest Du mir bitte das näher erläutern - ich verstehe jetzt nicht was Du meinst.
z.B. daß man statt dem Dateinamen auch einfach nur eine StringList, oder einen Stream übergeben kann.

sx2008 15. Dez 2008 01:42

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von Woodman
Verzeih' einem Anfänger, das ich Dir nicht ganz folgen kann :wall:
Was ist falsch daran, den Owner mit zu geben?

Du hast ein Klasse TForm1 und eine globale Variable Form1.
Solange es nur ein Formular dieser Klasse gibt ist alles in Ordnung.
Wenn es aber mehrere Formulare der gleichen Klasse gibt, dann können ja nicht alle in der Variable Form1 gespeichert sein.
Das würde dann bedeuten, dass die Autocomplete Komponente auf das falsche Formular zugreift.
Es könnte sogar sein, dass die Variable Form1 = nil ist.
Man kann sich vorstellen, dass das sehr unangenehm werden kann.

Woodman 15. Dez 2008 08:55

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von himitsu
Zitat:

Könntest Du mir bitte das näher erläutern - ich verstehe jetzt nicht was Du meinst.
z.B. daß man statt dem Dateinamen auch einfach nur eine StringList, oder einen Stream übergeben kann.

Du meinst, das die Keywords erst während des Programmlaufes dynamisch erzeugt werden?
Ich denke, das kann sich jeder selber einbauen, letztendlich wird die Datei in eine StrinList geladen. Dann würde natürlich der Event "OnContextPopup" wieder frei, weil dann markierte Wörter nicht mehr abgespeichert werden können.

SirThornberry 15. Dez 2008 09:06

Re: AutoComplete für TMemo, TRichEdit uvm.
 
der Vorteil eines Streams bzw. einer Stringlist anstelle einer Datei ist das mehrere Komponenten das gleiche AutoComplete verwenden könnten ohne das alles 2 mal im Speicher ist.

[edit=TBx]Da war ein Wort zuviel ;-) Mfg, TBx[/edit]

Woodman 15. Dez 2008 09:13

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von sx2008
Zitat:

Zitat von Woodman
Verzeih' einem Anfänger, das ich Dir nicht ganz folgen kann :wall:
Was ist falsch daran, den Owner mit zu geben?

Du hast ein Klasse TForm1 und eine globale Variable Form1.
Solange es nur ein Formular dieser Klasse gibt ist alles in Ordnung.
Wenn es aber mehrere Formulare der gleichen Klasse gibt, dann können ja nicht alle in der Variable Form1 gespeichert sein.
Das würde dann bedeuten, dass die Autocomplete Komponente auf das falsche Formular zugreift.
Es könnte sogar sein, dass die Variable Form1 = nil ist.
Man kann sich vorstellen, dass das sehr unangenehm werden kann.

Du meinst wahrscheinlich die Klasse TForm!? :P
Aber Spaß beiseite. Es liegt ja in der Verantwortung des Programmieres, welchem Formular er das AutoComplete zuweist.
Delphi-Quellcode:
AutoComplete1 := TAutoComplete.Create(Form1,'TextDatei',Memo1);
Da könnte auch Form2, Form3 oder sonstwas stehen. In der Komponente selbst greife ich ja nicht direkt auf die Form zu. Ich könnte natürlich noch eine Prüfung einbauen etwa
Wenn AOwner = nil dann löse eine Exeption aus.

himitsu 15. Dez 2008 09:29

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Tipps:
warum 'ne lokale Variable, wie z.B. comp, global in der Klase definieren?

als Owner (für die ListView) kannst du entweder das EditControl oder dessen .Parent verwenden.

wenn du in dieser for k:= 0 to wortzahl-1 do-Schleife viele Werte hinzufügen (Items.Add) willst, dann bietet sich Items.BeginUpdate und danach Items.EndUpdate an.
geht so schneller, da dann nichtmehr bei jedem Hinzufügen ein Update der StringList(ListView) ausgeführt wird.

die ListView sollte wieder ausgeblendet werden, wen sie nicht mehr benötigt wird. (z.B. das Edit verliert den Fokus)
in deinem Bild sieht man sogar gleich mehrere von diesen Dingern, zur selben Zeit.



kannst dich ja gern mal etwas umschauen:
  • Strg + Leertaste = Autovervollständigung sofort anzeigen
  • bei Eingabe eine Wortes, ab 3 Zeichen (Standard) Autovervollständigung anzeigen
  • Links/Rechts = Markierung (im Wort) ändern
  • Hoch/Runter/Bild Hoch/Bild Runter = in Liste Auswahl ändern
  • irgendwo hinklicken/ESC/Tab = abbrechen
  • Enter/Item anklicken = auswählen
  • Backspace/Zeichen eintippen = Wort/Auswahl ändern
  • Größe und Position der Auswahlbox ist unter dem EditControl (wenn's da hinpaßt), oder unter dem Cursor/Wort (in Memo und Co.), mit Breite des Controls, oder da, wie es angegeben ist (.Position und .Size)
  • via PopupMenü im Edit Wort hinzufügen
  • und über's PopupMenü der ListView Wort löschen
  • WortListe wird nicht von der Komponente gespeichert ... sollte man also selber machen ;)
    z.B.: If AutoComplete._WordsChanged Then AutoComplete.SaveWordsTo.....
  • Tschuldschung, hab mir mal deine Wörterlisten gemopst



[edit] Datei siehe #17

Woodman 15. Dez 2008 10:53

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Wow, ich erkenne meine Komponente nicht wieder :roll: (Das soll jetzt keine Bewertung sein)
Zitat:

Zitat von himitsu
Tipps:
warum 'ne lokale Variable, wie z.B. comp, global in der Klase definieren?

Warum nicht?(Ist ja als 'private' deklariert)
Zitat:

Zitat von himitsu
...
wenn du in dieser for k:= 0 to wortzahl-1 do-Schleife viele Werte hinzufügen (Items.Add) willst, dann bietet sich Items.BeginUpdate und danach Items.EndUpdate an.
geht so schneller, da dann nichtmehr bei jedem Hinzufügen ein Update der StringList(ListView) ausgeführt wird.

Das sehe ich ein. Das ich die ListView erst auf visible setze wenn die Liste aufgebaut ist, reicht also nicht aus?

Zitat:

Zitat von himitsu
die ListView sollte wieder ausgeblendet werden, wen sie nicht mehr benötigt wird. (z.B. das Edit verliert den Fokus)
in deinem Bild sieht man sogar gleich mehrere von diesen Dingern, zur selben Zeit.

Das war teilweise Absicht (Man sieht auch 2 Mouse-Cursor :P ), aber Du hast recht.

Zitat:

Zitat von himitsu
kannst dich ja gern mal etwas umschauen:
  • Strg + Leertaste = Autovervollständigung sofort anzeigen

  • Gute Idee :thumb:
    Zitat:

    Zitat von himitsu
  • bei Eingabe eine Wortes, ab 3 Zeichen (Standard) Autovervollständigung anzeigen

  • Funktioniert bei meiner Komponente
    Zitat:

    Zitat von himitsu
  • Links/Rechts = Markierung (im Wort) ändern

  • Ok, das funktioniert bei mir nicht.
    Zitat:

    Zitat von himitsu
  • Hoch/Runter/Bild Hoch/Bild Runter = in Liste Auswahl ändern

  • Funktioniert bei mir nur mit Hoch/Runter
    Zitat:

    Zitat von himitsu
  • irgendwo hinklicken/ESC/Tab = abbrechen

  • Funktioniert bei mir mit ESC bzw. non-matching Character
    Zitat:

    Zitat von himitsu
  • Enter/Item anklicken = auswählen

  • Funktioniert bei mir.
    Zitat:

    Zitat von himitsu
  • Backspace/Zeichen eintippen = Wort/Auswahl ändern

  • Funktioniert bei mir.
    Zitat:

    Zitat von himitsu
  • Größe und Position der Auswahlbox ist unter dem EditControl (wenn's da hinpaßt), oder unter dem Cursor/Wort (in Memo und Co.), mit Breite des Controls, oder da, wie es angegeben ist (.Position und .Size)

  • Da hab' ich's mir einfach gemacht, ist immer unter dem Wort bzw. Edit :wink:
    Zitat:

    Zitat von himitsu
  • via PopupMenü im Edit Wort hinzufügen

  • Funktioniert bei mir.
    Zitat:

    Zitat von himitsu
  • und über's PopupMenü der ListView Wort löschen

  • Funktioniert bei mir nicht.
    Zitat:

    Zitat von himitsu
  • WortListe wird nicht von der Komponente gespeichert ... sollte man also selber machen ;)
    z.B.: If AutoComplete._WordsChanged Then AutoComplete.SaveWordsTo.....

  • Das ist Geschmackssache, ich lagere gerne soviel wie möglich aus, so das ich mich im Hauptprogramm nicht mehr drum kümmern muss.
    Zitat:

    Zitat von himitsu
  • Tschuldschung, hab mir mal deine Wörterlisten gemopst

Dafür habe ich sie veröffentlicht.

Aber: Etwas klemmt noch in Deiner Version:
Versuch mal im RichEdit diesen Satz flüssig einzugeben:
Zitat:

Und nicht aus dieser Liste...
Und versuch mal diesen Satz per copy&paste im Memo einzugeben...

sx2008 15. Dez 2008 10:56

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von Woodman
...Es liegt ja in der Verantwortung des Programmieres, welchem Formular er das AutoComplete zuweist.
Delphi-Quellcode:
AutoComplete1 := TAutoComplete.Create(Form1,'TextDatei',Memo1);
Da könnte auch Form2, Form3 oder sonstwas stehen...

Hmmm... es hat bei dir noch nicht "klick" gemacht.
Ich wiederhole deinen Code vom 1. Beitrag:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
   AutoComplete1 := TAutoComplete.Create(self,'worte.txt',Memo1);       // RICHTIG
   AutoComplete2 := TAutoComplete.Create(Form1,'plz.txt',LabeledEdit1); // FALSCH
   AutoComplete3 := TAutoComplete.Create(Form1,'words4.txt',RichEdit1); // FALSCH
end;
Siehst du es jetzt? (weg mit den Tomaten :stupid: )
Du bist innerhalb der Klasse TForm1.
Self ist das aktuelle Objekt, auf dem du gerade arbeitet.
Form1 ist unter Umständen <> self.
Self ist richtig und Form1 ist falsch.
Ich hoffe du hast den Fehler jetzt erkannt.
Du musst zugeben, dass dieser Fehler ziemlich gemein und schwer zu erkennen ist.

Woodman 15. Dez 2008 11:17

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von sx2008
....Ich wiederhole deinen Code vom 1. Beitrag:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
   AutoComplete1 := TAutoComplete.Create(self,'worte.txt',Memo1);       // RICHTIG
   AutoComplete2 := TAutoComplete.Create(Form1,'plz.txt',LabeledEdit1); // FALSCH
   AutoComplete3 := TAutoComplete.Create(Form1,'words4.txt',RichEdit1); // FALSCH
end;
Siehst du es jetzt? (weg mit den Tomaten :stupid: )
Du bist innerhalb der Klasse TForm1.
Self ist das aktuelle Objekt, auf dem du gerade arbeitet.
Form1 ist unter Umständen <> self.
Self ist richtig und Form1 ist falsch.
Ich hoffe du hast den Fehler jetzt erkannt.
Du musst zugeben, dass dieser Fehler ziemlich gemein und schwer zu erkennen ist.

Aua, ich glaube, jetzt hab' ich es :wall: . Ok, das war jetzt mein Fehler im Hauptprogramm und hat nichts mit der Komponente AutoComplete zu tun. Richtig?

sx2008 15. Dez 2008 11:23

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von Woodman
Ok, das war jetzt mein Fehler im Hauptprogramm und hat nichts mit der Komponente AutoComplete zu tun. Richtig?

Exaktamente. :zwinker: Und weil der Fehler so schwer zu erkennen ist, war mein Rat, den Owner ganz wegzulassen und vom Steuerelement abzugreifen.

himitsu 15. Dez 2008 11:53

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Liste der Anhänge anzeigen (Anzahl: 1)
joar, vielleicht sollte man alle Zeichen (auch die in WordSeparator definierten) an das Edit weiterleiten :oops:


Zitat:

Ok, das war jetzt mein Fehler im Hauptprogramm ...
wie gesagt, am Einfachsten und Fehlerunanfälliger wäre es den Owner garnicht zu übergeben, sondern diesen über das Edit zu beziehen.


Zitat:

Wow, ich erkenne meine Komponente nicht wieder :roll: (Das soll jetzt keine Bewertung sein)
ok, dann dann bedank ich mich auch nicht für das Lob :mrgreen:

Zitat:

Warum nicht?(Ist ja als 'private' deklariert)
diese Variable wird nur kurzzeitig, innerhalb einer Procedur verwendet und auch nur wärend der Laufzeit dieser Prozedur verwendet ... nimmt also erstmal unnötig Platz in der Komponente ein, macht es etwas unübersichtlicher, weil man ja mehr von dieser Variable halten könnte ... es am Ende aber eigentlich nur 'ne lokale Variable einer Prozedur ist
Code:
TAutoComplete = class(TListView)
  ...
private
  [s]comp: TControl;[/s]


constructor TAutoComplete.Create(...
[b]var comp: TControl;[/b]
begin
Zitat:

Das sehe ich ein. Das ich die ListView erst auf visible setze wenn die Liste aufgebaut ist, reicht also nicht aus?
nee, die ganzen Bearbeitungsschritte innerhalb der Komponente laufen ja dennoch ab

Zitat:

Gute Idee :thumb:
hab ich mit von Delphi abgeguckt :stupid:

Zitat:

Da hab' ich's mir einfach gemacht, ist immer unter dem Wort bzw. Edit
Hauptsache es ist da :angel2:
war/ist aber och nicht so leicht es innerhalb des Fensters zu behalten und ist bestimmt och 'ne fehleranfällige Berechnung (du glaubst garnicht was da das vorher fehlende Minus von TEdit(_Edit).Font.Height mir für 'nen Spaß bereitete :wall: )

Zitat:

Das ist Geschmackssache, ich lagere gerne soviel wie möglich aus, so das ich mich im Hauptprogramm nicht mehr drum kümmern muss.
da bei mir ja auch noch von verschiedenen Quellen aus eingelesen werden kann, isses so einfacher, manchma isses ja nichtmal möglich (z.B. alles wo die Komponente nicht auf die Datei zugreift) und zusätzlich kann der User sich jetzt noch überlegen ob er überhaupt speichern will und wenn wo und wie.

Zitat:

Funktioniert bei mir nur mit Hoch/Runter
nun ja, ..bei mir ist halt die ListView aktiv (hat den Fokus), drum geht der Bildlauf dort von selbst

dafür muß ich alles Andere zum Edit zurückleiten.

siehe "vielleicht sollte man alle Zeichen ... weiterleiten :oops:"
sonst passieren komische Dinge :shock:
kleine Ändrung bei Case-Else in ListViewKeyPress

sirius 15. Dez 2008 15:45

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von himitsu
Zitat:

Wichtig: Durch AutoComlete werden die Ereignisbehandlungen 'OnChange', 'OnKeyDown', 'OnKeyPress' und 'OnContextPopup'überschrieben.
Sollten diese im Hauptprogramm benötigt werden, ist diese Lösung zunächst nicht einsetzbar.
dann überschreib die Eigenschaften doch nicht einfach!

ließ die vorherrigen Werte aus und ruf (falls da schon etwas eingetragen ist) dieses in deiner Klasse auf.

Jo, das ist die kurze Variante. Aber was ist, wenn jemand im Nachinein die Ereignisse ändert. Hier muss man weiter vorne ansetzen. Unter Umständen ist Subclassing das Mittel der Wahl.

Woodman 15. Dez 2008 18:11

Re: AutoComplete für TMemo, TRichEdit uvm.
 
@himitsu: Ich hab' mir erst jetzt Dein AutoComplete richtig angesehen :o . Da sieht man den professionellen Komponenten-Entwickler - alles ist konfigurierbar und sogar die eventuell bestehenden Events hast Du berücksichtigt :thumb: .
Zitat:

Zitat von himitsu
...
sonst passieren komische Dinge :shock:

Das stimmt :P , versuch mal diesen - sinnfreien - Satz unter Berücksichtigung der Groß/Kleinschreibung einzugeben:
Zitat:

Du große schöne Frau! Warum bist Du so schön?
Heraus kommt dabei:
Zitat:

Du grobe Schane Frau! warum Bist Du so Schan?

himitsu 15. Dez 2008 18:24

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Also, mit der letzen Version hab ich bei mir keine Probleme :gruebel:

[edit]Anhang entfernt (man darf ja mal die DP entlasten)

Woodman 15. Dez 2008 18:29

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von himitsu
Also, mit der letzen Version hab ich bei mir keine Probleme :gruebel:

Ja klar, weil Du das AutoComplete "ausgeschaltet" hast :P
Delphi-Quellcode:
  Procedure TAutoComplete.EditChange(Sender: TObject);
    Var B: Boolean;

    Begin
      {B := _IsKeyPressed;
      _IsKeyPressed := False;
      If B Then ShowListView Else Hide;
      If Assigned(_OnEditChange) Then _OnEditChange(Sender);}
    End;

himitsu 15. Dez 2008 18:39

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Ups, was hab ich denn da vergessen :shock:

stümmt, jetzt passiert des doch :wall:

OK, heißt also es gibt Probleme mit der Übergabe von Sonderzeichen ... ma gucken


Ach ja, hatte alles in den Edit-Ereignisprozeduren auskommentiert und igendwie funktioniert [Entf] und sowas wie Kopieren/Auschneiden/Einfügen beim Edit dennoch nicht ... hab also noch keine Ahnung warum :?

[edit] in #17 die Fehler bezüglich der Auskommentierung behoben

Woodman 15. Dez 2008 18:47

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von himitsu
...Ach ja, hatte alles in den Edit-Ereignisprozeduren auskommentiert und igendwie funktioniert [Entf] und sowas wie Kopieren/Auschneiden/Einfügen beim Edit dennoch nicht ... hab also noch keine Ahnung warum :?...

Das kann ich Dir sagen: Beim TEdit und TRichEdit funktionierts manuell.
Beim TMemo mußt Du noch das Popup-Menu bereinigen oder die ActionList aus meinem Testprogramm wieder zufügen.

Ich bin dann mal weg...

himitsu 15. Dez 2008 18:54

Re: AutoComplete für TMemo, TRichEdit uvm.
 
oder irgendwas vom OLE einbinden ... mir fällt einfach nur nimmer ein was das war.

So, das Problem mit den äöüß... liegt nicht an der Zeichenübergabe an das Edit, sonder vermutlich irgendwo an der ListBox-Selektierung ... muß ich nur noch rausfinden was da schiefgeht

himitsu 18. Dez 2008 07:51

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Liste der Anhänge anzeigen (Anzahl: 3)
Zu dem Memo ... ich hab langsam die Beführchtung,
es reicht, wenn man nur die ActionList auf's Formular zieht. :gruebel:

Bei Memo1 hab ich es mal (so wie bei dir) ins Popupmenü eingebunden, aber in Memo2 nicht und dennoch geht dieses dort jetzt auch. :shock:



Du hast 'nen Fehler beim Befüllen der ListBox ... es fehlen viele Wörter.
(siehe Anhang > Unbenannt.png und Unbenannt2.png)

"sch" = 4464 wörter, aber bei dir sind es nur 5
"fra" = 655 wörter und bei dir sind's wieder nur 5

Gut, ich laß auch nicht unendlich viele Wörter in der ListView zu, da die Delphi-Version leider ein "klitzekleines" Geschwindigkeitsproblem hat, wenn sie zu voll wird.

Zitat:

// Wichtig: Parent festlegen, sonst gibt's
// einen Laufzeitfehler
ach ja, weißt du auch warum?

Owner = Besitzer des Komponente und das kann alles (jeder nachkomme von TComponent) und nichts (nil) sein.
es ist nur derjenige, welcher sich um die Freigabe der Komponente kümmert (wenn er selber freigegeben wird), falls niemand anderes die Komponente freigibt,

welches eigentlich auch der Programmierer machen könnte:
Delphi-Quellcode:
procedure TForm1.FormDestroy(Sender: TObject);
begin
  AutoComplete1.Free;
  AutoComplete2.Free;
  AutoComplete3.Free;
end;
PS: drum hab ich als Owner auch die Edit-Komponente gewählt, da die Funktion an diese Komponente gebunden ist.

Parent aber ist die Komponente, auf welcher deine Komponente dargestellt wird ... und wenn da nichts angegeben ist, wo soll die ListView dann hin? (sozusagen ohne Leinwand um sich zu Zeichnen)



hab jetzt auch mal mit 'ner Version einer "unsichtbaren" ListView gespielt (ListView ist zwar noch vorhanden, da über sie die Eingabe läuft, aber so klein, daß man sie nicht sieht)

die Eingabe wurde verbessert und einige Fehler ausgemerzt
  • Entf-Taste wird nun unterstützt
  • das Schreiben geht flüssiger
  • Wörter werden nicht mehr verfällscht
  • man kann jetzt eine StringList für mehrere Komponenten(TAutoComplete) verwenden
    - einfach statt 'ner normalen StringList beim Laden TCommonWordList (oder deren Nachfahren) übergeben
  • statt nur TStringList und Nachkommen wird jetzt alles ab TStrings, als Quelle, unterstützt

[add]
Wenn du von statt TEdit TCustomEdit entgegennimmst, werden mehr Komponenten unterstützt.
TEdit macht nur einige Methoden sichtbar, welche es in TCustomEdit noch nicht sind und falls du dann innerhalb deiner Komponente Probleme hast auf bestimmte Methoden zuzugreifen, dann einfach nach TEdit casten.

[edit]merk grad, hab mir irgendwo 'nen Fehler bei der Positionierung der ListView eingebaut ... muß ich mal nachsehn wo der sich versteckt


Beitrag #17: AutoComplete.7z (742 KB) - Source+Exe

Woodman 18. Dez 2008 19:02

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zitat von himitsu
...
Du hast 'nen Fehler beim Befüllen der ListBox ... es fehlen viele Wörter.
(siehe Anhang > Unbenannt.png und Unbenannt2.png)

"sch" = 4464 wörter, aber bei dir sind es nur 5
"fra" = 655 wörter und bei dir sind's wieder nur 5

Das ist in Ordnung, wie Du oben siehst, öffne ich im Memo eine ander Textdatei als im RichEdit.
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
   AutoComplete1 := TAutoComplete.Create(self,'worte.txt',Memo1);
   AutoComplete2 := TAutoComplete.Create(Form1,'plz.txt',LabeledEdit1);
   AutoComplete3 := TAutoComplete.Create(Form1,'words4.txt',RichEdit1);
   
end;
Zitat:

Zitat von himitsu
Gut, ich laß auch nicht unendlich viele Wörter in der ListView zu, da die Delphi-Version leider ein "klitzekleines" Geschwindigkeitsproblem hat, wenn sie zu voll wird.

Bei der Option, das AutoComplete nur "anspringt", wenn 3 Zeichen eingetippt sind, gibt es dieses Problem (fast) nicht. :wink:
Zitat:

Zitat von himitsu
Zitat:

// Wichtig: Parent festlegen, sonst gibt's
// einen Laufzeitfehler
ach ja, weißt du auch warum?

Owner = Besitzer des Komponente und das kann alles (jeder nachkomme von TComponent) und nichts (nil) sein.
es ist nur derjenige, welcher sich um die Freigabe der Komponente kümmert (wenn er selber freigegeben wird), falls niemand anderes die Komponente freigibt,

welches eigentlich auch der Programmierer machen könnte:
Delphi-Quellcode:
procedure TForm1.FormDestroy(Sender: TObject);
begin
  AutoComplete1.Free;
  AutoComplete2.Free;
  AutoComplete3.Free;
end;
PS: drum hab ich als Owner auch die Edit-Komponente gewählt, da die Funktion an diese Komponente gebunden ist.

Parent aber ist die Komponente, auf welcher deine Komponente dargestellt wird ... und wenn da nichts angegeben ist, wo soll die ListView dann hin? (sozusagen ohne Leinwand um sich zu Zeichnen)

Das ist ein wichtiger Hinweis und war mir bis jetzt noch nicht bewusst bzw. bekannt:
Der Unterschied Owner <> Parent.
Früher dachte ich, die Kinder gehören den Eltern :wall:

Zitat:

Zitat von himitsu
hab jetzt auch mal mit 'ner Version einer "unsichtbaren" ListView gespielt (ListView ist zwar noch vorhanden, da über sie die Eingabe läuft, aber so klein, daß man sie nicht sieht)

Mhm, muss ich mal mit spielen. Ist etwas gewöhnungsbedürftig, besonders da man nicht weiß, was die Liste noch anbietet.
Zitat:

Zitat von himitsu
...[edit]merk grad, hab mir irgendwo 'nen Fehler bei der Positionierung der ListView eingebaut ... muß ich mal nachsehn wo der sich versteckt

Jau, denn ich blick jetzt nicht mehr durch :mrgreen:

himitsu 19. Dez 2008 07:29

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Das ist in Ordnung, wie Du oben siehst, öffne ich im Memo eine ander Textdatei als im RichEdit.
oh man, das Gedächtnis :wall:
OK, wenn die Datei kleiner ist, dann wäre das ein guter Grund :lol:

Zitat:

Bei der Option, das AutoComplete nur "anspringt", wenn 3 Zeichen eingetippt sind, gibt es dieses Problem (fast) nicht. :wink:
bis man dann mal eine schön große Wortliste verwendet... :stupid:

Zitat:

Früher dachte ich, die Kinder gehören den Eltern :wall:
joar, da darf man wohl nicht wortwörtlich übersetzen :roll:
Parent = Arbeitsplatz
Owner = Mörder
oder so

Zitat:

Zitat von himitsu
hab jetzt auch mal mit 'ner Version einer "unsichtbaren" ListView gespielt (ListView ist zwar noch vorhanden, da über sie die Eingabe läuft, aber so klein, daß man sie nicht sieht)

Mhm, muss ich mal mit spielen. Ist etwas gewöhnungsbedürftig, besonders da man nicht weiß, was die Liste noch anbietet.
Zitat:

Zitat von himitsu
...[edit]merk grad, hab mir irgendwo 'nen Fehler bei der Positionierung der ListView eingebaut ... muß ich mal nachsehn wo der sich versteckt

Jau, denn ich blick jetzt nicht mehr durch :mrgreen:[/quote]

Zitat:

Mhm, muss ich mal mit spielen.
Ist etwas gewöhnungsbedürftig, besonders da man nicht weiß, was die Liste noch anbietet.
du könntest die ListView da eventuell sogar weglassen und was Schnelleres verwenden, da bei dir der Input ja über das Memo läuft (bei mir halt über die ListView)

und was die Auswahl betrifft > Cursor-Tasten (hoch und runter), halt alles wie in der ListView und Auswählen mit Enter ... am Ende der begrenzen Liste (500 Einträge in der Demo) mit Enter die Liste erweitern (halt auch wie in der ListView))

himitsu 20. Dez 2008 16:44

Re: AutoComplete für TMemo, TRichEdit uvm.
 
das mit'm automatischen Positionieren funktioniert jetzt erstmal (auch wenn es mir vom Code her noch nicht gefällt)

und dann gab's noch einige andere Änderungen ... aber k.A. was ich gestern noch alles verbrockt hab :oops:

Beitrag #17: AutoComplete.7z (744 KB) - Source+Exe

juergen 23. Dez 2009 10:31

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Hallo himitsu,

aus einem anderen Thread heraus hattest du mich auf diesen hier aufmerksam gemacht.
Die Idee finde ich sehr gut und wollte das AutoComplete nun auch in mein Projekt übernehmen.

Ich kann auf die Methoden der AutoComplete-Unit zugreifen, aber es wird anscheinend nicht auf mein Edit angewendet.

Meine vllt. dumme Frage: :oops:
Wie bekomme ich das "Edit-Hack" auf mein Edit "aktiviert"?

Schon mal Danke für deine Mühen!


Edit: ähhh, sorry, nachfolgend noch meine Bemühungen, damit du nicht orakeln musst...
Delphi-Quellcode:
interface

uses
...AutoComplete;
...
private
AutoComplete1: TAutoComplete;
...
procedure TSearchForm.FormCreate(Sender: TObject);
var
  SL: TStringList; //fuer AutoComplete
begin
  AutoComplete1 := TAutoComplete.Create(Edit1, 'Search_Words.txt');
  SL := TStringList.Create;
  SL.LoadFromFile('Search_Words.txt');
...

procedure TSearchForm.Listbox1DblClick(Sender: TObject);
var
  Edit1text: string;
begin
...
  AutoComplete1.SaveWordsToString(Edit1text);
end;
...
procedure TSearchForm.FormDestroy(Sender: TObject);
begin
  AutoComplete1.SaveWordsToFile('Search_Word.txt');
  AutoComplete1.Free;
end;

himitsu 23. Dez 2009 12:44

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Eigentlich sollte dieses schon ausreichen, da das diese Komponente beim TAutoComplete.Create mit dem Edit verbunden wird. :gruebel:

Nur die TStringList (SL) kannst du weglassen, da du die Wörterliste ja schon beim TAutoComplete.Create direkt angibst, aber es sollte dennoch gehn, auch wenn die Datei nochmal in einer unabhängigen Stringliste geladen wurde.

Das Minimum wäre ja dieser Code und das ist soweit auch bei dir vorhanden.
Delphi-Quellcode:
{***** OnCreate *****}
AutoComplete1 := TAutoComplete.Create(Edit1, 'wordlist.txt');

{***** OnDestroy *****}
//If AutoComplete1.WordsChanged Then
//  AutoComplete1.SaveWordsToFile('wordlist.txt');
AutoComplete1.Free;

Änderst du eventuell nachträglich noch ein paar Events des Edits?
OnKeyDown, OnKeyUp, OnKeyPress und OnChange des Edits/Memors wird ja von der Komponente überschrieben, da hierrüber auf Tastatureingaben reagiert wird.

juergen 23. Dez 2009 16:35

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo himitsu,

Danke für deine Antwort! :thumb:
Zitat:

Zitat von himitsu
Änderst du eventuell nachträglich noch ein paar Events des Edits?
OnKeyDown, OnKeyUp, OnKeyPress und OnChange des Edits/Memors wird ja von der Komponente überschrieben, da hierrüber auf Tastatureingaben reagiert wird.

Das hatte ich schon entfernt, es tat sich aber nichts. :cry:

Ich habe nun mal ein ganz kleines Testprojekt erstellt, da bekomme ich das Edit auch nicht "verbunden".
Würde mich freuen wenn du dir das simple Testprojekt mal anschauen könntest.
Das "Edit-Hack" ist genau der Part, den ich leider nicht so verstehe... :oops:

Schon mal Danke vorab!

himitsu 23. Dez 2009 17:18

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Die wordlist.txt ist leer ... wenn keine Wörter vorhanden sind, dann kann auch kein Vorschlag generriert/angezeigt werden.

PS: Wenn du dem Edit ein Popupmenü verpaßt (kann auch ein ganz leeres TPopupMenu sein), dann wird darin auch ein Eintrag "markiertes Wort der Liste hinzufügen" erstellt.

PSS: Strg+Leertaste zeigt die Liste sofort an (wenn etwas vorhanden ist), ansonsten reagiert die Komponente standardmäßig erst ab 3 zusammenhängenden Buchstaben.

juergen 23. Dez 2009 18:57

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Hallo himitsu,
danke für deine Hilfe! :thumb:
Ich bin da inzwischen auch so halbwegs durchgestiegen.
Es kamen letztlich mehrere Probleme zusammen, Zuweisungen von Edit-Ereignissen , oder auch, dass das Popup-Menü erst ab 5 Zeichen aktiv wird.
Das Problem saß also eindeutig 60 cm vor dem Monitor... :stupid:

Schöne Weihnachtsfeiertage!

himitsu 23. Dez 2009 19:12

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Zitat:

Zuweisungen von Edit-Ereignissen
Wenn du dieses machst, bevor meine Klasse auf das Edit losgelassen wird, dann geht es auch,
da intern die alten Ereignisprozeduren gespeichert und Ereignisse dahin weitergeleitet werden.

Zitat:

Schöne Weihnachtsfeiertage!
Dir auch http://fnse.de/S01/0P7.gif

juergen 24. Dez 2009 22:14

Re: AutoComplete für TMemo, TRichEdit uvm.
 
Ho, ho, ho, allen ein schönes Weihnachtsfest!

Mein Wunsch ist es (wie passend für heute :mrgreen: ), dass ich beim Doppelklick auf ein Listbox.Item den Text aus einem Edit in die StringList aus der AutoComplete-Unit übernehme. Es gibt ja die Methode :arrow: AutoComplete1.SaveWordsToStringList()...
Die verlangt allerdingd ein TString-Typ und Edit hat ja ein String-Typ...
Ich habe im Moment leider keine Idee wie ich das bewerkstelligen kann, da ich auf die übliche Add-Methode für die StringList nicht zugreifen kann.

Danke schon mal vorab!


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:08 Uhr.

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