![]() |
lästiges beepen abstellen ??
über die Eigenschaft keypreview fange ich mit meinem Form eingaben ab .. ist die gedrückt taste enter .. soll ne procedure ausgeführt werden .. so weit kein Problem .. aber beim ausführen dann tut s immer kurz beepen .. wie bei ner fehleingabe .. wie krieg ich das weg ??
Danke schon im voraus!! |
Hi,
Das geht so: procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char); begin if Key = Char(VK_RETURN) then begin Key := #0; // Bewirkt, dass die Taste nicht weitergeleitet wird // und somit wird das Beep unterdrückt. end; end; |
Hallo Erni, :)
Code:
Gruß
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState); VAR Mgs: TMsg; BEGIN IF (Shift = [ssShift]) THEN CASE Key OF VK_RETURN : BEGIN // Shift + ENTER-Taste erkannt Key := 0; Perform(WM_NextDlgCtl, 1, 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten END; VK_TAB : BEGIN // ENTER-Taste erkannt Key := 0; Perform(WM_NextDlgCtl, 1, 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten END; END // für CASE Key OF ELSE CASE Key OF VK_RETURN : BEGIN // ENTER-Taste erkannt Key := 0; Perform(WM_NextDlgCtl, 0, 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten END; VK_TAB : BEGIN // ENTER-Taste erkannt Key := 0; Perform(WM_NextDlgCtl, 0, 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten END; END // für CASE Key OF END; Paul Jr. |
danke tom .. aber es hat leider nich funktioniert ..
ahm Paul .. deins hat .. allerdings ist mir nicht ganz klar was folgende befehle im einzelnen bedeuten:
Code:
Also die procedure Perform erzeugt ne WindowsMessage .. aber woher weiß ich an wen .. also was bedeuten die Parameter??
Perform(WM_NextDlgCtl, 0, 0);
Code:
Was bedeuten die einzelnen Parameter ?? Msg mal ausgenommen ..
PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
Danke !! |
Zitat:
Form schreiben. |
Moin Ernie,
ich hoffe Paul hat nichts dagegen, dass ich ihm da vorgreife. ;-) Also das Perform bezieht sich auf Form1, da es in einem Methodenaufruf von TForm1 augerufen wird, ohne angabe eines anderen Controls. Man könnte hier also auch schreiben Form1.Perform... Ersatzweise ginge auch SendMessage(self.Handle...), wobei sich das Self wiederum aus dem TForm1 ableitet. WM_NEXTDLGCTL entspricht dem Druck auf TAB. Das nächste/vorige Control in der Tabulatorreihenfolge erhält den Tastaturfokus. Die folgende erste null (null entspricht false) sagt aus, dass das nächste Control genommen werden soll, würde dort ein Wert ungleich 0 stehen (entspricht in C true, und die API ist ja in C geschrieben) würde das vorige Control den Fokus erhalten (entspricht also Shift-Tab). Die zweite null sagt aus, dass wParam (also die erste null) angibt, ob das nächste oder das vorige Control in der Tabulatorreihenfolge gemeint ist. Würde hier ein Wert ungleich null stehen, würde das Betriebssystem wParam als Handle auf das Control verstehen, das als nächstes den Fokus erhält. (präziser es ist hier das niederwertige Datenwort, also die unteren 16 Bit gemeint, die über die Funktion von wParam entscheiden). Damit hätten wir den Perform. Kleiner Tip am Rande: Sollte Perform mal nicht das gewünschte Ergebnis bringen, einfach mal mit SendMessage probieren. Manchmal hilft das. Perform scheint ab und zu nicht wie erwartet zu funktionieren. So und jetzt das PeekMessage: Damit werden Messages aus der MessageQueue des Threads ausgelesen. In diesem Falle wird es nur dazu benutzt unerwünschte Werte aus der Queue zu entfernen. Der erste Parameter ist hier eigentlich nur ein Dummy, aber die Funktion braucht hier nun einmal eine Variable (eigentlich werden hier die Daten der ausgelesenen Message gespeichert). Die null an zweiter Stelle besagt, dass die Messagequeue aller Fensters des aktuellen Threads beachtet werden sollen. Mit den beiden nun folgenden WM_CHAR wird angegeben, dass nur die Messages von WM_CHAR bis WM_CHAR ausgelesen werden sollen, da es hier darum geht genau dieses zu entfernen. Meist wird man hier wohl WM_KEYFIRST, WM_KEYLAST bzw. WM_MOUSEFIRST, WM_MOUSELAST vorfinden, um alle Tastatur- bzw. Mausmessages abzufangen. PM_REMOVE besagt schliesslich, dass die Message nicht nur ausgelesen, sondern sogar aus der Queue entfernt werden soll. Dadurch wird der Beep unterdrückt. PeekMessage ist noch umfangreicher, aber das liest Du wohl am besten im PSDK oder auf MSDN nach. Das würde hier zu weit führen. Ich hoffe Du kommst mit meinen Ausführungen klar. |
doch war nicht schlecht .. also eigentlich gut .. weil hab s doch verstanden.. DANKE!!
|
Hallo Christian :D
gut erklärt Gruß Paul Jr. |
Ich möchte mich ja nicht einmischen, aber den Code von PaulJr kann man noch ein wenig vereinfachen (gleiches zusammenfassen).
Code:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState); var Mgs: TMsg; begin case Key of VK_RETURN, VK_TAB: begin // ENTER oder TAB-Taste erkannt Key := 0; Perform(WM_NextDlgCtl, ord(Shift = [ssShift]), 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten end; end // für CASE Key OF end; |
Da gibt's aber noch ein Problem:
Jetzt kann man in einem Memo mit der Enter-Taste keinen Zeilenumbruch machen. |
Dann muss man einfach für jede Edit-Komponente die Ereignisbehandlungsroutine (EventHandler ist viel kürzer) auf dieselbe Methode setzen und nicht mehr über das FormKeyDown-Ereignis alle abfangen.
Oder man prüft mit Hilfe der Eigenschaft ActiveControl von TForm, welche Komponente gerade den Focus hat. Z.B.:
Code:
if (ActiveControl <> nil) and not (ActiveControl is TMemo) then
begin { hier den vorherigen Code einfügen } end; |
Hallo toms,
dafür könnte man den ender benutzen:
Code:
if Not (Sender is TMemo) then
begin case Key of VK_RETURN, VK_TAB: begin // ENTER oder TAB-Taste erkannt Key := 0; Perform(WM_NextDlgCtl, ord(Shift = [ssShift]), 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten end; end // für CASE Key OF end; |
Moin Zusammen,
da VK_TAB nicht an die KeyDown, KeyUp und KeyPress weitergeleitet wird, könnte man die Abfrage darauf auch weglassen. |
Während ich meine zweite Idee eingearbeitet habe, hat MrSpock gepostet.
Der Parameter Sender ist im TForm1.FormKeyDown immer Form1, außer du rufst die Methode selbst mit anderem Parameter auf, oder du weist einer anderen Komponente diese Methode als OnKeyDown-Ereignis zu. Meine Lösung mit ActiveControl habe ich sowie deine mit Sender überprüft. Meine funktioniert, bei deiner ändert sich nichts. Obwohl es mit persönlich auch mit Sender besser gefallen hätte. |
Also Leute ok...ihr habt gewonen... :D
ich zeige hier die ganze Prozedur (so wie ich die wirklich benutze) , die meine Meinung nach keine Wünsche offen lässt... :mrgreen: Gruß Paul Jr. [code:1:1bd18cbf32] (* Diese Prozedur sollte man in dem OnKeyDown Ereignis des Formulars aufrufen. ______________________________ |
Hi,
Warum ist dein Code so seltsam formatiert?
Code:
procedure EnterTab(Sender: TObject; var Key: Word; Shift: TShiftState;
ClassAus: array of TClass; ObjectAus: array of TObject; bESC_Close: Boolean = True); var Mgs: TMsg; //_____________________________KAPSELUNG function ClassObjectAusschliessen: Boolean; var Index: Integer; begin Result := False; with Sender as TForm do begin for Index := Low(ClassAus) to High(ClassAus) do if ActiveControl is ClassAus[Index] then // Diese Classe ausschliessen begin Result := True; Exit; end; for Index := Low(ObjectAus) to High(ObjectAus) do if ActiveControl = ObjectAus[Index] then // Dieses Object ausschliessen begin Result := True; Break; end; end; end; //_______________________________HAUPTPROGRAMM begin if Sender is TForm then with Sender as TForm do begin if (Shift = [ssShift]) then case Key of VK_RETURN: if not ClassObjectAusschliessen then begin // Shift + ENTER-Taste erkannt Key := 0; Perform(WM_NextDlgCtl, 1, 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten end; VK_TAB: if ClassObjectAusschliessen then begin // ENTER-Taste erkannt Key := 0; Perform(WM_NextDlgCtl, 1, 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten end; end // für CASE Key OF else case Key of VK_RETURN: if not ClassObjectAusschliessen then begin // ENTER-Taste erkannt Key := 0; Perform(WM_NextDlgCtl, 0, 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten end; VK_TAB: if ClassObjectAusschliessen then begin // ENTER-Taste erkannt Key := 0; Perform(WM_NextDlgCtl, 0, 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten end; VK_ESCAPE: if bESC_Close then begin Key := 0; Close; PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten end; end // für CASE Key OF end; // für WITH Sender As TForm DO end; |
Also Toms...für solche Fragen habe ich wirklich keine Zeit...sei mir nicht böse :D
Ich zeige jetzt hier, meine Meinung nach, eine sehr starke Prozedur und einziges was Dir dazu einfällt ist die Frage nach Formatierung... :mrgreen: __________________________________________________ _________ Nachtrag: Programmierung Beispiele. Um sich wirklich Bewusst zu werden wie Leistungsfähig so ein Konstrukt ist mache ich hier einpaar Einsatz- Beispiele mit verschiedenen Varianten. Dazu erstellt man bitte ein neues Projekt und legt drauf z.B. drei TMemo (Memo1, Memo2, Memo3) und drei TEdit (Edit1, Edit2, Edit3) Komponenten. Bitte die Eigenschaft des Formulars KeyPriview auf TRUE setzen und natürlich die Prozedur EnterTab in das Projekt aufnehmen (bei mir liegt diese natürlich in einer allgemeiner UNIT) __________________________________________________ ________________ 1.) Die Umwandlung ENTER --> TAB sollte in aller Komponenten wirksam werden Darüber Hinaus bei ESC wird das Formular geschlossen [code:1:14985e6b65] PROCEDURE TForm1.FormKeyDown(Sender: TObject; var Key: Word; |
Ich optimiere den Code noch einmal :)
Code:
Sag mal Paul Jr. was hast du für eine Delphi-Version, oder schreibst du jedesmal das procedure der EventHandler in PROCEDURE um?
procedure EnterTab(Sender: TObject; var Key: Word; Shift: TShiftState;
ClassAus: array of TClass; ObjectAus: array of TObject; bESC_Close: Boolean = True); var Mgs: TMsg; //_____________________________KAPSELUNG function ClassObjectAusschliessen: Boolean; var Index: Integer; begin Result := True; with Sender as TForm do begin for Index := Low(ClassAus) to High(ClassAus) do if ActiveControl is ClassAus[Index] then // Diese Classe ausschliessen Exit; for Index := Low(ObjectAus) to High(ObjectAus) do if ActiveControl = ObjectAus[Index] then // Dieses Object ausschliessen Exit; end; Result := False; end; //_______________________________HAUPTPROGRAMM begin if Sender is TForm then with Sender as TForm do begin case Key of VK_RETURN, VK_TAB: if not ClassObjectAusschliessen then begin Key := 0; Perform(WM_NextDlgCtl, ord(Shift = [ssShift]), 0); PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten end; VK_ESCAPE: if bESC_Close and (Shift <> [ssShift]) then begin Key := 0; Close; PeekMessage(Mgs, 0, WM_CHAR, WM_CHAR, PM_REMOVE); // Beep-Ton ausschalten end; end // case end; // für WITH Sender As TForm DO end; |
Ok jbg :evil:
einverstanden...öffne Bitte ein neues Thema z.B.:: Code-Fromatierung und erkläre mir DORT bitte was ich falsch mache (ich benutze Delphi5 und Delphi6 abwechslend (Enterprise) Aber bitte NICHT hier... Gruß Paul Jr. |
HALT!
toms und jbg haben nur ganz simple Fragen gestellt. Bitte nicht persönlich angegriffen fühlen. OK? |
Die Diskussion um die Code-Forumatierung hat in dem Moment begonnen, als die Lochstreifen abgelöst wurden und ist in so ziemlich jedem Programmier-Forum schon x-mal geführt worden ... wenn es Euch ein Bedürfnis ist, könnt Ihr diese Diskussion natürlich auch hier (Rubrik: Klatsch und Tratsch) fortführen.
@jbg: Man darf sich jederzeit über die Code-Formatierung anderer wundern; aber hälst Du Dich da nicht an unwichtigen Details auf? Grüße, Daniel |
Hallo Leute,
dieses Thema hab ich jetzt ein halbes Jahr zurückgestellt. In dem alten Delphi Forum wurde es "verschüttet". :mrgreen: Gott sei Dank verschwindet Wissen so schnell nicht im Nirwana. Was ich nicht genau weiß, ist wo ich das ganze einbauen soll / muß. Also bei mir ist die Problemstellung folgende : fleißige Zahlentipper sollen den Numerik Block einfach benutzen können und halt eine Zahl mit Enter abschließen können. Da die Tabtaste bekanntermaßen genau auf der anderen Seite der Tastatur ist, eignet sie sich für diesen Zweck nicht. Außerdem will ich dieses Prinzip im gesamten Programm durchziehen, also bei allen möglichen Typen von Eingabefeldern. Kann mir da noch jemand was zu sagen ? Gruß Hansa |
Hallo Hansa,
wenn ich Dich richtig verstehe, dann soll bei jedem drücken der Enter-Taste im Edit, der Focus zu nem anderen Edit springen, oder irgend eine Proz ausgeführt werden. Erstelle eine OnChange Prozedur. Die kannst Du ja im OI jedem Edit anhängen. Dort prüfst Du nur noch if Key = Enter then SetFocus.Nächstes Edit. Das findest Du mit FindComponent auf dem Formular. Grüsse,Daniel :hi: |
Einfacher geht es wohl mit der API GetNextDlgItem oder so. Damit bekommt das nächtse Kontroll in der Tab-Reihenfolge den Focus. Die genaue Syntax kann ich leider im Moment nicht angeben, ich bin mir auch noch nicht mal sicher, ob die wirklich so heißt.
|
Hi,
Zitat:
Gruß Hansa |
Moin Zusammen,
ich schlag mal vor: GetNextDlgTabItem Hier im KeyDown Event eines Edit Feldes angewendet, und zwar so, dass ich nur eine Routine für alle Edits des Formualares brauche.
Code:
[b]procedure[/b] TfrmLanguage.edTitleKeyDown(Sender: TObject; [b]var[/b] Key: Word; Shift: TShiftState);
[b]begin[/b] [b]if[/b] (Key = VK_RETURN)[b]then[/b] [b]begin[/b] windows.SetFocus(GetNextDlgTabItem(self.Handle,TWinControl(Sender).Handle,false)); [b]end[/b]; [b]end[/b]; |
Hallo,
vielen Dank für die Antworten. Aber ich will doch nur die Stelle wissen, wo ich das dann einbaue. Bei jedem Edit-Feld ? Naja, dann sieht mich vorerst hier keiner mehr. Dann habe ich vorerst nur in jedem Feld das einzubauen. Dann kommt folgendes : Frage : wieso komme ich aus dem Feld nicht mehr raus ? Antwort : TAB drücken. Frage : Wo ist denn das ? Antwort : Links oben. Frage : Wo ist links ? :mrgreen: Nee Nee, ich will eine durchgängig intuitiv zu verstehende Benutzeroberfläche. Der Code scheint ja zu funktionieren. Habe es zumindest hingekriegt, daß Enter oder Return funktionieren, allerdings MIT beep. Das ist aber Anfang des Jahres passiert. Gruß Hansa Hallo Christian Seehase, hab Dein Posting gerade noch gesehen. Die Frage ist, an welcher ZENTRALEN Stelle das alles passieren soll ? Darum gehts halt. |
Hallo,
hab den ganzen Thread nochmal durchgelesen. PaulJr. hatte das hier geschrieben : Zitat:
Aber wo? darum gehts ! Sonst will ich ja gar nix wissen. :mrgreen: Gruß Hansa |
Moin Hansa,
ich hab' den Thread auch noch mal gelesen, und bin dabei zu folgendem gekommen:
EnterTab steht dabei wo immer Du magst, solange jede Formularunit darauf zugreifen kann. |
Hallo Christian, :hi:
Code:
Versteht mich denn keiner ? Das ist nicht mehr viel. Aber es nützt doch nichts, eine Prozedur zu schreiben, mit uses einzubinden und dann alles so lassen wie es ist. Welche Unit interessiert denn, ob irgendwo eine Prozedur steht ?
EnterTab steht dabei wo immer Du magst, solange jede Formularunit darauf zugreifen kann.
Gruß Hansa |
Hallo,
Zitat:
Du stellt bei jedem Deiner Formulare, auf dem sich die für Dich relevanten Eingabefelder befinden die Eigenschaft "KeyPreview" auf true. Dann setzt Du ebenfalls in jedem dieser Formulare die Ereignis-Routine für das Ereignis "OnKeyDown" auf "Enter-Tab". Und genau damit hast Du die gewünschte Verknüpfung. |
Hallo Daniel,
na siehst Du, manchmal sieht man etwas offensichtliches nicht. :mrgreen: Habe mir zwischenzeitlich mal das KeyPreview angesehen, da war es fast klar, aber das hier nicht : Zitat:
Gruß Hansa |
Hallo,
ihr seit Spitze ! :bounce2: Das geht jetzt einwandfrei. Hatte schon befürchtet, mich mit diesem Kram schon wieder wochenlang aufzuhalten. Aber jetzt habe ich noch bemerkt, daß auf meiner Form die Felder total durcheinander erreicht werden (kreuz und quer). Die Taborder ist also noch verkehrt. :mrgreen: Aber jetzt weiß ich zumindest, wo ich weiter machen muß. Gruß Hansa |
Hi,
das Thema ist immer noch nicht beendet ! :(
Code:
Drücke ich auf der Form esc, so kommt obige Abfrage zwar, aber er springt in das letzte "betretene" Feld zurück, anstatt die Form zu schließen. Lasse ich MessageDlg (sonst nichts) weg, klappt es wunderbar. Was kann das denn jetzt noch sein ?
procedure TKuStamm.FormClose(Sender: TObject; var Action: TCloseAction);
begin IF NOT KuModul.KuDatenSatz.IsEmpty THEN BEGIN if MessageDlg('Soll der Datensatz gespeichert werden ?', mtInformation, [mbYes, mbNo], 0) = mrYes then begin KuModul.KuDatenSatz.post; KuModul.TransAction.Commit; END END; KuModul.Database.close; end; Gruß Hansa |
Moin Hansa,
eine Idee, nur so aus dem Gefühl heraus, ohne dass ich's im Moment begründen könnte. Tausch' doch mal MessageDlg durch MessageBox aus (nicht Application.MessageBox)
Code:
BTW:
[b]if[/b] MessageBox(
self.Handle, 'Soll der Datensatz gespeichert werden ?', 'Fenstertitelzeile', MB_ICONQUESTION [b]or[/b] MB_YESNO) = IDYES [b]then[/b] [b]begin[/b] [color=#000080]// ...[/color] [b]end[/b]; Hast Du die Möglichkeit des Abbruchs jetzt absichtlich weggelassen? |
Hallo Christian,
Zitat:
Gruß Hansa |
Nee,
kein Unterschied bis auf die Titelzeile. Werde das jetzt mit einer ganz einfachen Variable durchziehen, die ich im Quelltext setze. Gruß Hansa |
Hi,
also das muß an MessageDlg liegen. Kann das Verhalten aber noch präzisieren : Drücke ich ESC kommt der Dialog. Egal was ich auswähle lande ich wieder in dem Feld, wo ich ESC drückte. Drücke ich wieder ESC wird die Form geschlossen, eine neuerliche Abfrage kommt nicht. Irgendwas hängt da im "luftleeren Raum". :angle: Gruß Hansa |
Moin Hansa,
ich hab' eben noch mal zurückgeblättert, und dabei gesehen, dass in der EnterTab Routine (in der ja auch ESC abgefragt wird) Perform verwendet wird. Meiner Erfahrung nach macht das manchmal Probleme. Das Perform könntest Du mal gegen SendMessage(self.Handle,..... oder SendMessage(Handle,.... oder SendMessage(TWinControl.Handle,.... austauschen (für TWinControl natürlich den entsprechenden Namen einsetzen). Je nachdem, in welcher Form das Perform verwendet wird. |
Hallo Christian,
in dem ESC-Teil von EnterTab kommt kein Perform vor, also kann ich es auch nicht ersetzen. Vielleicht ist das aber der Fehler ! Nur was soll ich da hinschreiben ? Gruß Hansa |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:50 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz