【发布时间】:2016-06-24 14:37:51
【问题描述】:
我使用 TWebBrowser 作为用户的编辑器 GUI。我希望能够将 Web 控件插入到文档中。一个简单的例子是一个复选框。 (如果需要,我可以详细说明原因)。当我第一次组装 HTML 文档(及其 STYLE 和 SCRIPTS 部分)然后将其 en-block 传递给 TWebBrowser 时,我已经完成了所有这些工作。但现在我希望能够将我的元素插入到现有文档中。
我在下面有这段代码,但它会导致 OLE 错误(参见代码中的 cmets):
procedure THTMLTemplateDocument.EnsureStylesInWebDOM;
var StyleBlock : IHTMLElement;
StyleText: string;
begin
StyleBlock := FWebBrowser.GetDocStyle;
if not assigned(StyleBlock) then
raise Exception.Create('Unable to access <STYLE> block in web document');
StyleText := FCumulativeStyleCodes.Text;
StyleBlock.InnerText := StyleText; <--- generates "OLE ERROR 800A0258"
end;
上述代码中调用的函数如下:
function THtmlObj.GetDocStyle: IHTMLElement;
//Return pointer to <STYLE> block, creating this if it was not already present.
var
Document: IHTMLDocument2; // IHTMLDocument2 interface of Doc
Elements: IHTMLElementCollection; // all tags in document body
AElement: IHTMLElement; // a tag in document body
Style, Head: IHTMLElement;
I: Integer; // loops thru Elements in document body
begin
Result := nil;
if not Supports(Doc, IHTMLDocument2, Document) then
raise Exception.Create('Invalid HTML document');
Elements := Document.all;
for I := 0 to Pred(Elements.length) do begin
AElement := Elements.item(I, EmptyParam) as IHTMLElement;
if UpperCase(AElement.tagName) <> 'STYLE' then continue;
result := AElement;
break;
end;
if not assigned(Result) then begin
Head := GetDocHead;
if assigned(Head) then begin
Style := Document.CreateElement('STYLE');
(Head as IHTMLDOMNode).AppendChild(Style as IHTMLDOMNode);
Result := Style;
end;
end;
end;
和
function THtmlObj.GetDocHead: IHTMLElement;
//Return pointer to <HEAD> block, creating this if it was not already present.
var
Document: IHTMLDocument2; // IHTMLDocument2 interface of Doc
Elements: IHTMLElementCollection; // all tags in document body
AElement: IHTMLElement; // a tag in document body
Body: IHTMLElement2; // document body element
Head: IHTMLElement;
I: Integer; // loops thru Elements in document body
begin
Result := nil;
if not Supports(Doc, IHTMLDocument2, Document) then
raise Exception.Create('Invalid HTML document');
if not Supports(Document.body, IHTMLElement2, Body) then
raise Exception.Create('Can''t find <body> element');
Elements := Document.all;
for I := 0 to Pred(Elements.length) do begin
AElement := Elements.item(I, EmptyParam) as IHTMLElement;
if UpperCase(AElement.tagName) <> 'HEAD' then continue;
Result := AElement;
break;
end;
if not assigned(Result) then begin
Head := Document.CreateElement('HEAD');
(Body as IHTMLDOMNode).insertBefore(Head as IHTMLDOMNode, Body as IHTMLDOMNode);
//now look for it again
Elements := Document.all;
for I := 0 to Pred(Elements.length) do begin
AElement := Elements.item(I, EmptyParam) as IHTMLElement;
if UpperCase(AElement.tagName) <> 'HEAD' then continue;
Result := AElement;
break;
end;
end;
end;
当我运行它时,StyleText =
'.selected {'#$D#$A' 字体粗细:粗体;'#$D#$A' //背景色:黄色;'#$D#$A'}'#$D#$A' .unselected {'#$D#$A' font-weight : normal;'#$D#$A' //background-color : white;'#$D#$A'}'#$D#$A#$D#$A
但我尝试让 StyleText 变得像“你好”这样简单,但它仍然崩溃。
Google 搜索“OLE ERROR 800A0258”会发现其他几个遇到类似问题的人,例如 here 和 here - 这位后来的用户似乎表示他通过使用 .OuterHTML 解决了问题,但我尝试了这个并产生了类似的错误。 This 线程似乎表明 .InnerText 是只读的。但在接口声明中(见下文),似乎有设置方法(即非只读)。
// *********************************************************************//
// Interface: IHTMLElement
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {3050F1FF-98B5-11CF-BB82-00AA00BDCE0B}
// *********************************************************************//
IHTMLElement = interface(IDispatch)
['{3050F1FF-98B5-11CF-BB82-00AA00BDCE0B}']
...
procedure Set_innerHTML(const p: WideString); safecall;
function Get_innerHTML: WideString; safecall;
procedure Set_innerText(const p: WideString); safecall;
function Get_innerText: WideString; safecall;
procedure Set_outerHTML(const p: WideString); safecall;
function Get_outerHTML: WideString; safecall;
procedure Set_outerText(const p: WideString); safecall;
function Get_outerText: WideString; safecall;
...
property innerHTML: WideString read Get_innerHTML write Set_innerHTML;
property innerText: WideString read Get_innerText write Set_innerText;
property outerHTML: WideString read Get_outerHTML write Set_outerHTML;
property outerText: WideString read Get_outerText write Set_outerText;
...
end;
谁能帮助弄清楚如何在 TWebBrowser 中现有 HTML 文档的 <STYLE> 部分设置样式?
【问题讨论】:
-
我请了一位德尔福专家帮助我使用嵌入的铬。他告诉我,如果浏览器在主窗体上,效果会很好。但是当它在辅助表单上时,它就不能正常工作了。
-
R.e.为什么不使用 Javascript... 我有一个 Delphi 应用程序,我想在编辑区域(TWebBrowser)中插入一个模板。目前有一个模板引擎可以弹出一个框,显示模板,完成后折叠成插入到文档中的文本。我正在尝试将该模板直接嵌入到编辑区域中。 HTML 文档不知道插入过程中需要什么,我认为 Javascript 做不到。
-
那你不懂javascript。花一点时间来处理它。您可以将任何对象插入 DOM,并通过 JavaScript 管理这些对象、它们的可见性和位置。您可以在运行时拥有该 javascript 请求并加载 html 片段并将其插入到您的页面中。查看 jQuery。如果您希望用户能够与生成的 HTML 进行交互,那么无论如何您都需要一些 javascript 知识。最终我认为你会碰壁,除非你学会如何在父文档内执行的 javascript 块中执行此操作。
-
@WarrenP 感谢您的帖子。我知道 javascript 可以操纵 DOM。但我认为我的设置与您的想法不同。此浏览器不与互联网交互。它只呈现由 Delphi 应用程序传递给它的内容。如果 javascript 要操作 DOM,则 Delphi 代码必须首先设置 javascript 代码并将其传递。事件链源自 Delphi 代码。所以我可以直接设置 STYLES,或者创建 javascript 来做。这两个动作都从 Delphi 代码开始。
-
我不建议它与互联网互动。但它应该与您正在运行的本地服务器交互,我认为拥有 JavaScript+JQUERY-like-layer+load-from-page 比进入 IShellDocView/IHTMLStyleSheet 接口(设计于 1995 年)并尝试做所有事情要好那样。
标签: html delphi twebbrowser innertext