2009-04-06 3 views
2

Dans une partie de l'application sur laquelle je travaille, il y a un contrôle de formulaire qui effectue la validation à la réception du message CMExit, ce qui correspond exactement à la documentation Delphi (cet exemple de code provient des fichiers d'aide Delphi):Message CMExit Delphi non envoyé lorsque le dialogue modal est fermé?

procedure TDBCalendar.CMExit(var Message: TWMNoParams); 
begin 
try 
    FDataLink.UpdateRecord;       { tell data link to update database } 
except 
    on Exception do SetFocus;      { if it failed, don't let focus leave } 
end; 
inherited; 
end; 

Le but de ceci est d'effectuer la validation dès que le contrôle perd le focus. Ainsi, par exemple, si je devais cliquer sur le bouton OK, le contrôle de formulaire perdrait le focus, cette méthode s'exécuterait et une exception rétablirait le contrôle de formulaire. (Ainsi, l'événement "clic" sur le bouton OK ne passerait jamais et la boîte de dialogue ne se fermerait jamais).

Le problème que j'ai est que ce contrôle de formulaire est dans une fenêtre de dialogue modale. Cliquer sur OK envoie en effet le message CMExit et provoque la mise à jour de l'enregistrement (et la validation à se produire). Cependant, si vous appuyez sur Entrée alors que vous êtes dans le contrôle de formulaire, la boîte de dialogue modale se ferme sans envoyer le message CMExit. C'est comme si le contrôle de forme ne "perd jamais le focus". Cela signifie que non seulement la boîte de dialogue se ferme sans que le formulaire ne valide réellement les données, mais l'ensemble de données n'est pas non plus mis à jour.

Compte tenu de ce problème, où est le meilleur endroit pour moi de placer mon code de mise à jour/validation de jeu de données? Je pourrais le déplacer vers le formulaire de dialogue lui-même et l'implémenter dans le gestionnaire OnCloseQuery, mais cela signifierait que la logique est dupliquée dans le contrôle de formulaire et sur le formulaire lui-même. (Le contrôle de formulaire est utilisé dans d'autres endroits, et je veux éviter de changer son comportement).

(je spécule que CMExit ne se déclenche pas parce que le contrôle ne fait ne perdre le focus. La forme est fermée, mais le contrôle de la forme encore « a le focus » sur la forme fermée.)

+0

Cm_Exit est un événement qui change la mise au point. N'appelez pas SetFocus à partir de celui-ci. Ne changez pas la mise au point tant que la mise au point est déjà en cours. Au lieu de cela, publiez un message et modifiez le focus en réponse à celui-ci. Le système d'exploitation n'aime pas être interrompu pendant le changement de mise au point. Il devient confus sur ce qui a vraiment l'accent. –

Répondre

7

Fermeture d'une formulaire ne déclenche pas nécessairement l'événement on-exit d'un TControl. L'utilisateur pourrait frapper Alt-F4, par exemple.

Je suggérerais de déplacer la validation vers un proc séparé, et d'appeler ce proc séparé à la fois des événements de fermeture on-exit et.

Le code ci-dessous devrait fonctionner sans trop de modification:

function TDBCalendar.UpdateSuccessful: boolean; 
begin 
    { tell data link to update database } 
    { if successful, return True, else return False } 
    { this function must be Public if a form is gonna check this value } 
    Result := True; 
    try 
    FDataLink.UpdateRecord; 
    except on Exception do 
    Result := False; 
    end; 
    inherited; 
end; 

procedure TDBCalendar.CMExit(var Message: TWMNoParams); 
begin 
    //if not valid, then don't let them leave 
    if not(UpdateSuccessful) then begin 
    SetFocus; 
    end; 
end; 

/////////////////////////////////////////// 
//on the form that contains your control... 
/////////////////////////////////////////// 

procedure TMyForm.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
    //if not valid, then don't let them close the form 
    if not(dbcal.ControlIsValid) then begin 
    Action := caNone; 
    end 
    else begin 
    inherited; 
    end; 
end; 
Questions connexes