2009-05-13 4 views
1

Dans Virtual Treeview de Mike Lischke, il y avait le code de contournement ajouté pour corriger un bogue lors de l'utilisation d'un contrôle TWebBrowser sur le même formulaire.Delphi: TOleControl met ActiveControl dans un mauvais état?

Le problème est que si l'utilisateur tente d'interagir avec un TOleControl (dont TWebBrowser descend), le premier clic de la souris est mangé. Ils doivent ensuite cliquer à nouveau pour donner le focus de contrôle. Puis ils peuvent interagir avec le contrôle.

Il a des commentaires à expliquer:

Chaque contrôle dérivé de TOleControl a potentiellement le problème de mise au point.

Afin d'éviter d'inclure le OleCtrls unité (qui, entre autres, inclure variantes), qui permettrait de tester la classe TOleControl, l'interface IOleClientSite est utilisée pour le test, qui est soutenu par TOleControl et un bon indicateur.

De la pleine snippit:

procedure TBaseVirtualTree.WMKillFocus(var Msg: TWMKillFocus); 
var 
    Form: TCustomForm; 
    Control: TWinControl; 
    Pos: TSmallPoint; 
    Unknown: IUnknown; 
begin 
    inherited; 

    [snip] 

    { 
    Workaround for wrapped non-VCL controls (like TWebBrowser), 
    which do not use VCL mechanisms and 
    leave the ActiveControl property in the wrong state, 
    which causes trouble when the control is refocused. 
    } 
    Form := GetParentForm(Self); 
    if Assigned(Form) and (Form.ActiveControl = Self) then 
    begin 
    Cardinal(Pos) := GetMessagePos; 
    Control := FindVCLWindow(SmallPointToPoint(Pos)); 
    { 
     Every control derived from TOleControl has potentially 
     the focus problem. In order to avoid including 
     the OleCtrls unit (which will, among others, include Variants), 
     which would allow to test for the TOleControl 
     class, the IOleClientSite interface is used for the test, 
     which is supported by TOleControl and a good indicator. 
    } 
    if Assigned(Control) and Control.GetInterface(IOleClientSite, Unknown) then 
     Form.ActiveControl := nil; 

    // For other classes the active control should not be modified. Otherwise you need two clicks to select it. 
    end; 
end; 

problème est que la solution de contournement ne fonctionne plus pour moi. Et pour être honnête, je n'ai aucune idée du problème et de la façon dont sa solution l'a résolu. Y a-t-il quelqu'un qui sait ce que ses commentaires comprennent de ce dont il parle, qui pourrait expliquer quel est le problème et comment ce qu'il fait était censé le réparer?

Solution pour enveloppées contrôles non-VCL (comme TWebBrowser), qui ne utilisent pas des mécanismes VCL et laissent la propriété ActiveControl dans le mauvais état , ce qui provoque des problèmes lorsque le contrôle est recentré. Chaque contrôle dérivé de TOleControl a potentiellement le problème de mise au point.

Le code atteint l'intention

Form.ActiveControl := nil; 
déclaration

, mais il fait est tout simplement pas l'affaire.

je voudrais corriger, mais je ne sais pas comment il l'a trouvé, ou comment il peut venir à ce sujet TOleControl ne «l'utilisation des mécanismes de VCL et laisse la propriété ActiveControl dans le mauvais état."


Bonus lecture

J'ai demandé à l'origine cette question on borland.public.delphi.nativeapi.win32 newsgroup in 2008

Question on Soft-Gems forum

Bump 20110515 (12 mois plus tard)

Bump 20150401 (7 ans plus tard): Encore biche travail sn't dans XE6

+0

Virtual TreeView est désactivé. Dernière version du 14. mars 09? Probablement le plus grand composant Delphi à mon humble avis. – Tom

+0

Il était défunt quand j'ai d'abord posé la question. Quand Mike est passé au développement Mac et MySQL, ça ne semblait pas bien pour VT. Il y a un soutien sporadique, mais rien d'officiel. –

+0

Lors de la relocalisation de cette question pour utiliser des balises existantes, j'ai trouvé que la balise tvirtualtreeview existait déjà dans cette question: http://stackoverflow.com/questions/687438/. Vous sauriez mieux ce qui est correct, alors cela vous dérangerait-il de changer l'un d'entre eux? Merci. –

Répondre

3

J'ai surmonté ce problème en utilisant TEmbeddedWB (ce qui est beaucoup mieux que le TWebBrowser standard) puis je devais ajouter cet événement OnShowUI:

function THtmlFrame.webBrowserShowUI(const dwID: Cardinal; 
    const pActiveObject: IOleInPlaceActiveObject; 
    const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame; 
    const pDoc: IOleInPlaceUIWindow): HRESULT; 
begin 
    try 
    if WebBrowser.CanFocus then 
     WebBrowser.SetFocus; // tell the VCL that the web-browser is focused 
    except 
    on E: EInvalidOperation do 
     ; // ignore "Cannot focus inactive or invisible control" 
    end; 
    Result := S_FALSE; 
end; 


Mais si vous Vous devez utiliser TWebBrowser pour écrire plus de code:

type 
    IDocHostUIHandler = interface(IUnknown) 
    ['{bd3f23c0-d43e-11cf-893b-00aa00bdce1a}'] 
    function ShowContextMenu(const dwID: DWORD; const ppt: PPOINT; 
     const CommandTarget: IUnknown; const Context: IDispatch): HRESULT; stdcall; 
    function GetHostInfo(var pInfo: TDOCHOSTUIINFO): HRESULT; stdcall; 
    function ShowUI(const dwID: DWORD; const pActiveObject: IOleInPlaceActiveObject; 
     const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame; 
     const pDoc: IOleInPlaceUIWindow): HRESULT; stdcall; 
    function HideUI: HRESULT; stdcall; 
    function UpdateUI: HRESULT; stdcall; 
    function EnableModeless(const fEnable: BOOL): HRESULT; stdcall; 
    function OnDocWindowActivate(const fActivate: BOOL): HRESULT; stdcall; 
    function OnFrameWindowActivate(const fActivate: BOOL): HRESULT; stdcall; 
    function ResizeBorder(const prcBorder: PRECT; const pUIWindow: IOleInPlaceUIWindow; const fRameWindow: BOOL): HRESULT; stdcall; 
    function TranslateAccelerator(const lpMsg: PMSG; const pguidCmdGroup: PGUID; const nCmdID: DWORD): HRESULT; stdcall; 
    function GetOptionKeyPath(out pchKey: POLESTR; const dw: DWORD): HRESULT; stdcall; 
    function GetDropTarget(const pDropTarget: IDropTarget; out ppDropTarget: IDropTarget): HRESULT; stdcall; 
    function GetExternal(out ppDispatch: IDispatch): HRESULT; stdcall; 
    function TranslateUrl(const dwTranslate: DWORD; const pchURLIn: POLESTR; out ppchURLOut: POLESTR): HRESULT; stdcall; 
    function FilterDataObject(const pDO: IDataObject; out ppDORet: IDataObject): HRESULT; stdcall; 
    end; // IDocHostUIHandler 

    ICustomDoc = interface(IUnknown) 
    ['{3050f3f0-98b5-11cf-bb82-00aa00bdce0b}'] 
    function SetUIHandler(const pUIHandler: IDocHostUIHandler): HResult; stdcall; 
    end; 

    TDocHostUIHandler = class(TInterfacedObject, IDocHostUIHandler) 
    private 
    FWebBrowser: TWebBrowser; 
    protected 
    function EnableModeless(const fEnable: BOOL): HResult; stdcall; 
    function FilterDataObject(const pDO: IDataObject; out ppDORet: IDataObject): HResult; stdcall; 
    function GetDropTarget(const pDropTarget: IDropTarget; out ppDropTarget: IDropTarget): HResult; stdcall; 
    function GetExternal(out ppDispatch: IDispatch): HResult; stdcall; 
    function GetHostInfo(var pInfo: TDocHostUIInfo): HResult; stdcall; 
    function GetOptionKeyPath(var pchKey: POLESTR; const dw: DWORD): HResult; stdcall; 
    function HideUI: HResult; stdcall; 
    function OnDocWindowActivate(const fActivate: BOOL): HResult; stdcall; 
    function OnFrameWindowActivate(const fActivate: BOOL): HResult; stdcall; 
    function ResizeBorder(const prcBorder: PRECT; const pUIWindow: IOleInPlaceUIWindow; 
     const fFrameWindow: BOOL): HResult; stdcall; 
    function ShowContextMenu(const dwID: DWORD; const ppt: PPOINT; 
     const pcmdtReserved: IInterface; const pdispReserved: IDispatch): HResult; stdcall; 
    function ShowUI(const dwID: DWORD; const pActiveObject: IOleInPlaceActiveObject; 
     const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame; 
     const pDoc: IOleInPlaceUIWindow): HResult; stdcall; 
    function TranslateAccelerator(const lpMsg: PMSG; const pguidCmdGroup: PGUID; const nCmdID: DWORD): HResult; stdcall; 
    function TranslateUrl(const dwTranslate: DWORD; const pchURLIn: POLESTR; var ppchURLOut: POLESTR): HResult; stdcall; 
    function UpdateUI: HResult; stdcall; 
    public 
    constructor Create(AWebBrowser: TWebBrowser); 
    property WebBrowser: TWebBrowser read FWebBrowser; 
    end; 


{ TDocHostUIHandler } 

function TDocHostUIHandler.EnableModeless(const fEnable: BOOL): HResult; 
begin 
    Result := S_OK; 
end; 

function TDocHostUIHandler.FilterDataObject(const pDO: IDataObject; out ppDORet: IDataObject): HResult; 
begin 
    ppDORet := nil; 
    Result := S_FALSE; 
end; 

function TDocHostUIHandler.GetDropTarget(const pDropTarget: IDropTarget; out ppDropTarget: IDropTarget): HResult; 
begin 
    ppDropTarget := nil; 
    Result := E_FAIL; 
end; 

function TDocHostUIHandler.GetExternal(out ppDispatch: IDispatch): HResult; 
begin 
    ppDispatch := nil; 
    Result := E_FAIL; 
end; 

function TDocHostUIHandler.GetHostInfo(var pInfo: TDocHostUIInfo): HResult; 
begin 
    Result := S_OK; 
end; 

function TDocHostUIHandler.GetOptionKeyPath(var pchKey: POLESTR; const dw: DWORD): HResult; 
begin 
    Result := E_FAIL; 
end; 

function TDocHostUIHandler.HideUI: HResult; 
begin 
    Result := S_OK; 
end; 

function TDocHostUIHandler.OnDocWindowActivate(const fActivate: BOOL): HResult; 
begin 
    Result := S_OK; 
end; 

function TDocHostUIHandler.OnFrameWindowActivate(const fActivate: BOOL): HResult; 
begin 
    Result := S_OK; 
end; 

function TDocHostUIHandler.ResizeBorder(const prcBorder: PRECT; const pUIWindow: IOleInPlaceUIWindow; const fFrameWindow: BOOL): HResult; 
begin 
    Result := S_FALSE; 
end; 

function TDocHostUIHandler.ShowContextMenu(const dwID: DWORD; const ppt: PPOINT; const pcmdtReserved: IInterface; const pdispReserved: IDispatch): HResult; 
begin 
    Result := S_FALSE 
end; 

function TDocHostUIHandler.TranslateAccelerator(const lpMsg: PMSG; const pguidCmdGroup: PGUID; const nCmdID: DWORD): HResult; 
begin 
    Result := S_FALSE; 
end; 

function TDocHostUIHandler.TranslateUrl(const dwTranslate: DWORD; const pchURLIn: POLESTR; var ppchURLOut: POLESTR): HResult; 
begin 
    Result := E_FAIL; 
end; 

function TDocHostUIHandler.UpdateUI: HResult; 
begin 
    Result := S_OK; 
end; 

function TDocHostUIHandler.ShowUI(const dwID: DWORD; const pActiveObject: IOleInPlaceActiveObject; const pCommandTarget: IOleCommandTarget; 
    const pFrame: IOleInPlaceFrame; const pDoc: IOleInPlaceUIWindow): HResult; 
begin 
    try 
    if WebBrowser.CanFocus then 
     WebBrowser.SetFocus; // tell the VCL that the web-browser is focused 
    except 
    on E: EInvalidOperation do 
     ; // ignore "Cannot focus inactive or invisible control" 
    end; 
    Result := S_OK; 
end; 



// install the DocHostUIHandler into the WebBrowser 
var 
    CustomDoc: ICustomDoc; 
begin 
    if WebBrowser1.Document.QueryInterface(ICustomDoc, CustomDoc) = S_OK then 
    CustomDoc.SetUIHandler(TDocHostUIHandler.Create(WebBrowser1)); 
end; 
+0

J'utilise TEmbeddedWB, mais le problème arrive aussi avec TWebBrowser - et je ne voudrais pas que les gens s'en prennent à TEmbeddedWB. J'ai essayé d'ajouter CanFocus/SetFocus à l'événement OnShowUI - ne fonctionne pas. Principalement parce que l'événement OnShowUI ne se déclenche réellement que lorsque je clique sur le contrôle du navigateur Web. –