I'm trying to scroll to the bottom of my displayed TWebBrowser document programmatically.
I've tried using the scroll method:
uses
MSHTML;
procedure TForm1.Button1Click(Sender: TObject);
var
Document: IHTMLDocument2;
begin
Document := WebBrowser.Document as IHTMLDocument2;
Document.parentWindow.scroll(0, Document.body.offsetHeight);
end;
I also tried using ScrollIntoView(false);:
procedure TForm1.Button1Click(Sender: TObject);
var
Document: IHTMLDocument2;
begin
Document := WebBrowser.Document as IHTMLDocument2;
Document.Body.ScrollIntoView(false);
end;
Just run JavaScript code to scroll it:
const
jsScrollDown = 'window.scrollTo(0, document.body.scrollHeight);';
var
Doc: IHTMLDocument2;
Hwn: IHTMLWindow2;
begin
Doc := WebBrowser1.Document as IHTMLDocument2;
if not Assigned(Doc) then Exit;
Hwn := Doc.parentWindow;
Hwn.execScript(jsScrollDown, 'JavaScript');
Or next generation, TEdgeBrowser supports directly scripts execution:
EdgeBrowser1.ExecuteScript(jsScrollDown);
Running JS code, allows scrolling easily to any element of the HTML document.
Using MS interfaces, without JS, it could be done like:
var
Doc: IHTMLDocument2;
Hwn: IHTMLWindow2;
begin
Doc := WebBrowser1.Document as IHTMLDocument2;
if not Assigned(Doc) then Exit;
Hwn := Doc.parentWindow;
Hwn.scrollTo(0, (Doc.body as IHTMLElement2).scrollHeight);
Be aware, MS interfaces works in legacy IE mode only, not supported by Edge engine.
Related
What is the equivalent of the piece of code below for zooming with the new TEdgeBrowser delphi component?
This is how I used the old TWebBrowser component.
procedure ApplyZoom(ZoomValue: Integer);
var
pvaIn, pvaOut: OLEVariant;
begin
pvaIn := ZoomValue;
pvaOut := Null;
WebBrowser.ControlInterface.ExecWB($0000003F, OLECMDEXECOPT_DONTPROMPTUSER, pvaIn, pvaOut);
end;
I have been trying to stream the contents of a TTabSheet, but WriteComponent just streams the TTabSheet object, but not the controls on it.
To get around this I thought I could stream all the controls on the tabsheet, using the following code, but this only streams the first control.
procedure TfrmMain.SaveComponentToFile(Component: TComponent; const FileName: TFileName);
var
FileStream : TFileStream;
MemStream : TMemoryStream;
i: integer;
begin
MemStream := nil;
if not Assigned(Component) then raise Exception.Create('Component is not assigned');
FileStream := TFileStream.Create(FileName,fmCreate);
try
MemStream := TMemoryStream.Create;
//ShowMessage(IntToStr(TTabSheet(Component).ControlCount));
for i := 0 to TTabSheet(Component).ControlCount - 1 do begin
Memstream.WriteComponent(TTabSheet(Component).Controls[i]);
end;
MemStream.Position := 0;
ObjectBinaryToText(MemStream, FileStream);
finally
MemStream.Free;
FileStream.Free;
end;
end;
The commented out ShowMessage does show the correct number of controls on the tabsheet, so why is the loop not streaming all 35 components?
I need some help with my code, my application supposed to get my voice and write everything i say in a TMemo component, but it's simply doesn't do anything
Here is my code:
Am using SAPI 5.4 Microsoft Speech Object Library
procedure TForm1.initRecognizer;
begin
// Create Voice Handler
SpVoice := TSpVoice.Create(nil);
//**//
// Create Reconizer Context
SpInProcRecoContext := TSpInProcRecoContext.Create(nil);
SpInProcRecoContext.OnHypothesis := SpInProcRecoContextHypothesis;
SpInProcRecoContext.OnRecognition := SpInProcRecoContextRecognition;
//**//
// Create Grammar Rule
RecoGrammar := SpInProcRecoContext.CreateGrammar(0);
RecoGrammar.DictationSetState(SGDSActive);
//**//
end;
procedure TForm1.SpInProcRecoContextHypothesis(ASender: TObject;
StreamNumber: Integer; StreamPosition: OleVariant;
const Result: ISpeechRecoResult);
begin
Memo1.Text := Result.PhraseInfo.GetText(0,-1,true);
end;
procedure TForm1.SpInProcRecoContextRecognition(ASender: TObject;
StreamNumber: Integer; StreamPosition: OleVariant;
RecognitionType: SpeechRecognitionType; const Result: ISpeechRecoResult);
begin
SpInProcRecoContext.Recognizer.AudioInput := Result;
Memo1.Text := Result.PhraseInfo.GetText(0,-1,true);
end;
Please If there's a fix Will appreciate it, thanks in advance.
I need to remove a little image from a website that I display in my TWebBrowser component in Delphi XE10 (VCL). I spend hours of searching and I tried a lot of code, but it is not working as I want.
This is a snippet of my code:
procedure TForm16.WebBrowser1DocumentComplete(ASender: TObject;
const pDisp: IDispatch; const [Ref] URL: OleVariant);
var
Doc: IHTMLDocument2;
ElementCollection: IHTMLElementCollection;
Frames: IHTMLElementCollection;
Element: IHTMLElement;
Frame: IHTMLDOMNode;
i: Integer;
begin
Doc := WebBrowser1.Document as IHTMLDocument2;
ElementCollection := Doc.body.all as IHTMLElementCollection;
Frames := ElementCollection.tags('IMG') as IHTMLElementCollection;
if Frames <> nil then
begin
for i := 0 to Frames.length - 1 do
begin
Element := Frames.item(i, 0) as IHTMLElement;
Frame := Element as IHTMLDOMNode;
if Frame <> nil then
begin
Frame.parentNode.removeChild(Frame);
end;
end;
end;
end;
Unfortunately it deletes all images. I want to delete a specific image that has a specific HREF. Can you help me with this?
I'm not sure if you are after the src or href attribute.
I'll assume you actually meant src (I'm not aware of href usage with IMG tag). if not, replace src with href in the follow answer.
Basically your code is fine. you can check the IHTMLElement attribute e.g.
if Element.getAttribute('src', 0) = 'something' then ...
I suggest using IHTMLDocument2.images collection directly and IHTMLImgElement which has the src/href properties e.g.:
procedure TForm1.WebBrowser1DocumentComplete(Sender: TObject;
const pDisp: IDispatch; var URL: OleVariant);
var
Doc: IHTMLDocument2;
Images: IHTMLElementCollection;
Img: IHTMLImgElement;
Node: IHTMLDOMNode;
Src: WideString;
I: Integer;
begin
Doc := TWebBrowser(Sender).Document as IHTMLDocument2;
if Assigned(Doc) then
begin
Images := Doc.images;
for I := Images.length - 1 downto 0 do
begin
Img := Images.item(I, 0) as IHTMLImgElement;
if Img.src = 'http://foo.bar/my.png' then // or "Img.href"
begin
Node := Img as IHTMLDOMNode;
Node.parentNode.removeChild(Node);
Break; // optional
end;
end;
end;
end;
Note that I'm iterating the DOM backwards
for I := Images.length - 1 downto 0 do
because if we need to remove more than one node we wont loose the next node index after removing the previous one.
I am trying to create an open dialog (in Windows 7) where the user is confined to the initial directory. On the open dialog I have set the optionsEX to [ofExNoPlacesBar] and that removes the bar that would let them select folders and directories to go to quickly but the user can use the bread crumb address tool to go up a level and type a different directory into the filename text box to change directories.
Thank you
If you are using Delphi 2009+, there is a TFileOpenDialog. Use this, and set
procedure TForm3.FileOpenDialog1FolderChange(Sender: TObject);
begin
FInitiated := true;
end;
procedure TForm3.FileOpenDialog1FolderChanging(Sender: TObject;
var CanChange: Boolean);
begin
CanChange := not FInitiated;
end;
procedure TForm3.btnOpenClick(Sender: TObject);
begin
FInitiated := false;
FileOpenDialog1.DefaultFolder := 'C:\MyFolder\';
FileOpenDialog1.Execute;
end;
where
var
FInitiated: boolean;
(Notice that there should be exactly one FInitiated per TFileOpenDialog. So, if FileOpenDialog is a private member of TForm3, let FInitiated be a private member of TForm3 as well.)
To improve the user experience, you will probably use
procedure TForm3.FileOpenDialog1FolderChanging(Sender: TObject;
var CanChange: Boolean);
begin
CanChange := not FInitiated;
if not CanChange then beep;
end;
or
procedure TForm3.FileOpenDialog1FolderChanging(Sender: TObject;
var CanChange: Boolean);
begin
CanChange := not FInitiated;
if not CanChange then
MessageBox(Handle, PChar('Directory selection is not allowed.'), PChar(Caption), MB_ICONINFORMATION);
end;
Use a different open dialog (make a form yourself with no folder navigation, only a file list box), or simply audit for a path not matching the initial dir and refuse to actually open the file.
The 'FileOpenDialog' has an OnFolderChanging event of type TFileDialogFolderChangingEvent which have a boolean CanChange parameter. I'd expect setting this parameter to false would serve the purpose.
edit:
Example usage as per Remy's comments (if I understood correctly);
procedure TForm1.FileOpenDialog1FolderChanging(Sender: TObject;
var CanChange: Boolean);
var
Dlg: TFileOpenDialog;
DefFolder: IShellItem;
iOrder: Integer;
begin
CanChange := False;
Dlg := Sender as TFileOpenDialog;
if Succeeded(SHCreateItemFromParsingName(PWideChar(WideString(Dlg.DefaultFolder)), nil, IShellItem, DefFolder)) then
try
CanChange := Dlg.ShellItem.Compare(DefFolder, SICHINT_ALLFIELDS, iOrder) = S_OK;
finally
DefFolder := nil;
end;
end;
The below also works but more vulnerable to path variations (see Andreas' comments below);
procedure TForm1.FileOpenDialog1FolderChanging(Sender: TObject;
var CanChange: Boolean);
begin
CanChange := SameFileName(TFileOpenDialog(Sender).FileName,
TFileOpenDialog(Sender).DefaultFolder);
end;