2016-10-09 1 views
0

mon application est une fenêtre de type showontop avec un menu contextuel (mastermenu) apparaissant à l'emplacement du curseur à l'extérieur du principal form (demoForm), déclenchée par un message winapi externe (changement de presse-papiers). Le problème ennuyeux est que le menu ne disparaîtra pas quand on clique à l'extérieur de l'application au lieu de cliquer sur les éléments de menu ou le formulaire principal comme quand normalement fait pour rejeter un menu. L'accent s'éteint, mon application reste au top et le menu reste flottant.Fermez TPopupMenu lorsque vous le déplacez - en supprimant son comportement flottant lorsque vous cliquez à l'extérieur d'une application (toujours en haut)

Essayé de suivre de nombreux articles et même changé de D7 à XE5 sans succès. Vérifié cela aussi: Automatically Hide or Close PopUp Menu when Mouse Pointer is outside it - Delphi La mine n'est pas compliquée par les minuteries de retard ou le contrôle de plateau.

Plus précisément, l'emprunt d'une solution que je l'ai fait:

procedure TDemoForm.tmrMenumouseOutMonitorTimer(Sender: TObject); 
var 
    hPopupWnd: HWND; 
    R: TRect; 
    PT: TPoint; 
begin 
    hPopupWnd := FindWindow('#32768', mastermenu); 
    if hPopupWnd = 0 then Exit; 
    GetWindowRect(hPopupWnd, R); 
    GetCursorPos(Pt); 
    if PtInRect(R, Pt) then begin 
    //do something 
    end else begin 
    //do something 
    end; 
end; 

où je suis en train de sonder la position du curseur avec une minuterie (MenumouseOutMonitorTimer) pour détecter si le curseur déplacé hors du menu (mastermenu). Au cas où il sortirait, j'émettrai un .closeMenu()

Mais, ce code jette une chaîne, pAnsiChar/pwidestring discordance dans D7/XE5 au dernier argument FindWindow(). Peut-être que je devrais utiliser FindWindowEx? XE5 renvoie directement certaines poignées d'un TPopupMenu mais je ne sais pas comment les utiliser pour résoudre mon problème.

(sur Win7, ciblant également XP)

Je suis un débutant, toute aide sera appréciée.

code complet ici:

unit FmDemo; 

interface 

uses 
    System.Classes, 
    Vcl.Controls, 
    Vcl.StdCtrls, 
    Vcl.Forms, Menus, Dialogs, FileCtrl, ExtCtrls,PJCBView;// ....; 

type 
    TDemoForm = class(TForm) 
    //...... 
    PJCBViewer1: TPJCBViewer; //custom control 
    masterMenu: TPopupMenu; 
    tmrMenumouseOutMonitor: TTimer; 
    procedure tmrMenumouseOutMonitorTimer(Sender: TObject); 

    private 
    //........ 
    procedure menuItemClickHandler(Sender: TObject); 
    end; 

var 
    DemoForm: TDemoForm; 

implementation 

uses 
     Jpeg, Shellapi, Graphics, SysUtils, RichEdit, Messages;//GifImage 

{$R *.dfm} 

procedure tdemoform.menuItemClickHandler(Sender: TObject); 
begin 
    //....... 
end; 

procedure TDemoForm.PJCBViewer1ClipboardChanged(Sender: TObject); 
var 
    pnt: TPoint; 
begin 
    demoform.BringToFront; //formStyle -> fsStayOnTop already 
    /////////////////////////////////// 
    ///menu under cursor display code// 
    /////////////////////////////////// 

    if GetCursorPos(pnt) then 
    begin 
     masterMenu.Popup(pnt.X, pnt.Y); 
    end; 
    //remember to return focus to source window after each menu action (not implemented) 
end; 

procedure TDemoForm.tmrMenumouseOutMonitorTimer(Sender: TObject); 
var 
    hPopupWnd: HWND; 
    R: TRect; 
    PT: TPoint; 
begin 
    hPopupWnd := FindWindow('#32768', masterMenu); 
    if hPopupWnd = 0 then Exit; 
    GetWindowRect(hPopupWnd, R); 
    GetCursorPos(Pt); 
    if PtInRect(R, Pt) then begin 
    //do something 
    end else begin 
    //do something 
    end; 
end; 

//... other business logic 

initialization 
    CF_RTF := RegisterClipboardFormat(richedit.CF_RTF); 
end. 
+0

Afficher un MCVE s'il vous plaît –

+0

Le popup n'aura pas un titre/fenêtre texte, FindWindow ne le trouvera pas quand même. –

+0

ok. tenter un MCVE. – user30478

Répondre

2

Voici une MCVE qui ne nécessite pas un contrôle tiers.

... 

implementation 

uses 
    menus; 

{$R *.dfm} 

var 
    Pop: TPopupMenu; 
    Wnd: HWND; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Left := 200; 
    Top := 100; 
    Pop := TPopupMenu.Create(nil); 
    Pop.Items.Add(TMenuItem.Create(Pop)); 
    Pop.Items[0].Caption := 'test'; 
    Wnd := GetForegroundWindow; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    SetForegroundWindow(Wnd); // comment this for the popup to be released when clicked outside 
    Pop.Popup(100, 50); 
end; 

Cliquez en dehors du formulaire et le popup ne sera pas libéré.

Comme vous pouvez le voir, j'ai dû imposer artificiellement la condition qui reproduit le problème, c'est-à-dire que votre fenêtre n'est pas au premier plan lorsque vous faites apparaître le menu.

Comme mentionné à plusieurs endroits de la page que vous avez liée, pour que le popup soit normalement publié, votre fenêtre doit être au premier plan lorsque vous ouvrez le menu, vous n'aurez pas besoin de l'interroger et de le trouver, puis le libérer manuellement. SetForegroundWindow ne garantit pas que votre fenêtre viendra à l'avant. Pour plus d'informations sur ce problème et pour plusieurs solutions, voir this question.

+0

Cela a semblé fonctionner pendant un moment mais, maintenant je vois le même problème dans les deux win7, XP. Comme indiqué, j'ai commenté le setforegroundWindow() mais le problème persiste: 1. Je déclenche le popup en dehors de l'application via le changement de presse-papiers (pas de clic sur le bouton). 2. l'application passe en arrière-plan, mais les affichages contextuels. si je clique à nouveau dans la même fenêtre externe (pas celle de ma demande mais la source du changement de presse-papiers). le menu 'flotte'. – user30478

+2

@user - J'espère que vous n'avez pas commenté votre SerForegroundWindow, c'est ainsi que j'ai répliqué le problème. Vous devriez intégrer l'une des solutions dans la page que j'ai liée pour mettre votre forme au premier plan, n'est-ce pas? –

+0

Au lieu de simplement setForegroundWindow(), utilisez votre réponse liée dans la méthode du gestionnaire de déclencheurs qui appelle le menu. Maintenant, le menu se comporte correctement. Je ne m'inquiète pas de ce qui arrive à la forme car elle sera cachée/minimisée de toute façon. Testé D7/XP/Win7 J'ai vu que j'avais aussi consulté cette question liée et que j'avais amélioré votre réponse mais que j'avais implémenté quelqu'un d'autre. BTW cet outil est pour la méta-programmation, c'est-à-dire aidera à générer des tutoriels Delphi pour beaucoup de gens là-bas comme moi dans un monde de ressources limitées. Merci Sertac et David aussi. – user30478