【Delphi】如何解决使用webView2时主界面置顶,而导致网页选择文件对话框被覆盖问题
一、问题描述:
在Delphi 中使用WebView2控件,如果预先把主界面置顶(Self.FormStyle := fsStayOnTop;),此时,如果在Web页面中有使用(<input type="file" id="fileInput" accept=".txt, .pdf, .doc, .docx" required> )选择文件,这样就会导致选择文件的对话框被覆盖,从而无法操作。
二、解决方案
由于WebView2通过H5打开文件选择窗口时,Delphi无法直接获取到事件通知,因为文件选择时由浏览器进程管理的,所以需要使用一些技巧来解决。
使用javascript监听文件选择事件:
可以通过在 WebView2 中注入 JavaScript 代码来监听文件选择窗口的打开和关闭事件,然后通过 WebView2 的事件机制将这些事件传递到 Delphi 端。
操作步骤:
- 注入 JavaScript 代码:在页面加载完成后,注入 JavaScript 代码来监听文件选择窗口的打开和关闭事件。
- 通过 WebMessage 传递事件:将事件通过 `window.chrome.webview.postMessage` 传递到 Delphi 端。
- 在 Delphi 中处理事件:在 Delphi 中监听 WebView2 的 `WebMessageReceived` 事件,并根据接收到的消息调整主窗体的置顶状态。
示例代码:
JavaScript 代码:
document.addEventListener('focus', function(event) {
if (event.target.tagName === 'INPUT' && event.target.type === 'file') {
window.chrome.webview.postMessage('fileDialogOpen');
}
}, true);
document.addEventListener('blur', function(event) {
if (event.target.tagName === 'INPUT' && event.target.type === 'file') {
window.chrome.webview.postMessage('fileDialogClose');
}
}, true);
Delphi 代码:
procedure TForm1.WebView2NavigationCompleted(ASender: TObject; const Args: ICoreWebView2NavigationCompletedEventArgs);
begin
// 注入 JavaScript 代码
WebView2.ExecuteScript(
'document.addEventListener(''click'', function(event) {' +
' if (event.target.tagName === ''INPUT'' && event.target.type === ''file'') {' +
' window.chrome.webview.postMessage(''fileDialogOpen'');' +
' }' +
'}, true);',
nil
);
end;
procedure TBase_Form.WebViewWebMessageReceived(Sender: TObject; const Source,
MessageHTML, Json: WString);
begin
if MessageHTML = 'fileDialogOpen' then
begin
Self.FormStyle := fsNormal;
FH5OpenDialog := True;
end;
end;
因为文件选择按键获取焦点的同时只要点击,就立即失去了焦点,所以没有解决问题,这就需要配合Delphi的TApplicationEvents控件中的OnActivate事件来共同处理。
注意
定义公用变量:FH5OpenDialog
procedure TBase_Form.ApplicationEvents1Activate(Sender: TObject);
begin
if FH5OpenDialog then
begin
Self.FormStyle := fsStayOnTop;
FH5OpenDialog := False;
end;
end;