How to customise the TWebBrowser user interface (part 4 of 6)
2008-10-15 10:22
936 查看
Developing the customization class
As we decided above, TWBContainer will derive from TNulWBContainer and add all the required browser customization. Let us review what we want this customization to achieve:Display either the browser's built in pop-up menu or the menu assigned to the TWebBrowser.PopupMenu property.
Display or hide 3D borders.
Display or hide scroll bars.
Customize document appearance at run time, via a custom cascading style sheet.
Allow or inhibit users from selecting text in the browser control.
The browser control will display XP themed controls (such as buttons) only when the host application is using themes.
We will define properties to configure the customization. We will then need to re-implement just two methods of IDocHostUIHandler to achieve the desired results – ShowContextMenu and GetHostInfo. ShowContextMenu controls the display of the popup menu and GetHostInfo enables the browser control's appearance to be customized.
Listing 12 shows the declaration of TWBContainer.
type TWBContainer = class(TBaseContainer, IDocHostUIHandler, IOleClientSite) private fUseCustomCtxMenu: Boolean; fShowScrollBars: Boolean; fShow3DBorder: Boolean; fAllowTextSelection: Boolean; fCSS: string; protected { Re-implemented IDocHostUIHandler methods } function ShowContextMenu(const dwID: DWORD; const ppt: PPOINT; const pcmdtReserved: IUnknown; const pdispReserved: IDispatch): HResult; stdcall; function GetHostInfo(var pInfo: TDocHostUIInfo): HResult; stdcall; public constructor Create(const HostedBrowser: TWebBrowser); property UseCustomCtxMenu: Boolean read fUseCustomCtxMenu write fUseCustomCtxMenu default False; property Show3DBorder: Boolean read fShow3DBorder write fShow3DBorder default True; property ShowScrollBars: Boolean read fShowScrollBars write fShowScrollBars default True; property AllowTextSelection: Boolean read fAllowTextSelection write fAllowTextSelection default True; property CSS: string read fCSS write fCSS; end;
Listing 12
Notice that we expose a property for each of the aspects of the browser control that we will customize, with the exception of XP theme support which we handle automatically. The properties are:
UseCustomCtxMenu – the browser control displays its default context menu when the property is false and uses the menu assigned to TWebBrowser PopupMenu when true. If UseContextMenu is true but PopupMenu is not assigned then no popup menu is displayed.
Show3DBorder – the web browser displays a 3D border when the property is true and no border when false.
ShowScrollBars – TWebBrowser displays scroll bars only if the property is true.
AllowTextSelection – permits text selection in the browser control when true and inhibits it when false.
CSS – provides the default cascading style sheet. This string property must contain valid CSS or be set to the empty string. When set we use this property to customize the document appearance.
The class constructor simply sets the default property values. These are chosen to leave the browser control in its default state. Listing 13 shows the constructor.
constructor TWBContainer.Create(const HostedBrowser: TWebBrowser); begin inherited; fUseCustomCtxMenu := False; fShowScrollBars := True; fShow3DBorder := True; fAllowTextSelection := True; fCSS := ''; end;
Listing 13
Now we come on to the meat of the code. First let's look at how we re-implement ShowContextMenu. This is easier to write than to describe. See Listing 14 below.
function TWBContainer.ShowContextMenu( const dwID: DWORD; const ppt: PPOINT; const pcmdtReserved: IInterface; const pdispReserved: IDispatch): HResult; begin if fUseCustomCtxMenu then begin // tell IE we're handling the context menu Result := S_OK; if Assigned(HostedBrowser.PopupMenu) then // browser has a pop up menu so activate it HostedBrowser.PopupMenu.Popup(ppt.X, ppt.Y); end else // tell IE to use default action: display own menu Result := S_FALSE; end;
Listing 14
We first check the fUseCustomCtxMenu field to see what to do. If it is false we simply return S_FALSE to tell the web browser we have not handled the context menu. This causes the browser to display its default pop-up menu.
When fUseCustomCtxMenu is true we return S_OK to show we are handling the context menu ourselves. This prevents the default pop-up menu from being displayed. If the browser control's PopupMenu property is set we display the menu by calling its Popup method. The ppt parameter supplies the co-ordinates where the mouse was right clicked. We use this to position the top left corner of the pop-up menu.
GetHostInfo is more complex because it determines the display of the border, scroll bars, text selection, XP theme support and the default style sheet. We instruct the browser control about how to handle these items by filling in a TDocHostUIInfo structure, a pointer to which is passed as a parameter to the method. Listing 15 defines this structure and comments describe its fields. Listing 16 presents GetHostInfo itself.
type TDocHostUIInfo = record cbSize: ULONG; // size of structure in bytes dwFlags: DWORD; // flags that specify UI capabilities dwDoubleClick: DWORD; // specified response to double click pchHostCss: PWChar; // pointer to CSS rules pchHostNS: PWChar; // pointer to namespace list for custom tags end;
Listing 15
function TWBContainer.GetHostInfo( var pInfo: TDocHostUIInfo): HResult; const DOCHOSTUIFLAG_SCROLL_NO = $00000008; DOCHOSTUIFLAG_NO3DBORDER = $00000004; DOCHOSTUIFLAG_DIALOG = $00000001; DOCHOSTUIFLAG_THEME = $00040000; DOCHOSTUIFLAG_NOTHEME = $00080000; begin try // Clear structure and set size ZeroMemory(@pInfo, SizeOf(TDocHostUIInfo)); pInfo.cbSize := SizeOf(TDocHostUIInfo); // Set scroll bar visibility if not fShowScrollBars then pInfo.dwFlags := pInfo.dwFlags or DOCHOSTUIFLAG_SCROLL_NO; // Set border visibility if not fShow3DBorder then pInfo.dwFlags := pInfo.dwFlags or DOCHOSTUIFLAG_NO3DBORDER; // Decide if text can be selected if not fAllowTextSelection then pInfo.dwFlags := pInfo.dwFlags or DOCHOSTUIFLAG_DIALOG; // Ensure browser uses XP themes if application is doing if ThemeServices.ThemesEnabled then pInfo.dwFlags := pInfo.dwFlags or DOCHOSTUIFLAG_THEME else if ThemeServices.ThemesAvailable then pInfo.dwFlags := pInfo.dwFlags or DOCHOSTUIFLAG_NOTHEME; // Record default CSS as Unicode pInfo.pchHostCss := TaskAllocWideString(fCSS); if not Assigned(pInfo.pchHostCss) then raise Exception.Create('Task allocator can''t allocate CSS string'); // Return S_OK to indicate we've made changes Result := S_OK; except // Return E_FAIL on error Result := E_FAIL; end; end;
Listing 16
dwDoubleClick
This TDocHostUIInfo field is ignored by some browser versions.
For our purposes we only need to use the cbSize, dwFlags and pchHostCss fields of TDocHostUIInfo. We set the remaining fields to zero. cbSize is set to the size of the structure – a common Windows idiom.
Next we decide which flags to store in dwFlags to customize the control's user interface capabilities. Which flags we specify depends on the state of the ShowScrollBars, Show3DBorder and AllowTextSelection properties and whether XP themes are enabled. The flags we use are:
Other flags
There are numerous other DOCHOSTUIFLAG_ flags that can be assigned to dwFlags. The full set is defined in this article's demo code.
DOCHOSTUIFLAG_SCROLL_NO prevents the vertical scroll bar from being displayed.
DOCHOSTUIFLAG_NO3DBORDER inhibits the display of 3D borders.
Slightly less obviously, DOCHOSTUIFLAG_DIALOG prevents text selection – the name comes from the main use of this flag to prevent text selection in dialog boxes.
More complex is the way we ensure that the application's XP themes are echoed by the web browser control. We use the
Themesunit's ThemeServices object to check if themes are enabled. If so we use the DOCHOSTUIFLAG_THEME flag to request that the browser also uses themes. If themes are not enabled, but available, we switch off the browser's theme support by using DOCHOSTUIFLAG_NOTHEME. If themes are not available at all (e.g. in Windows 2000) we do nothing.
Lastly, we store the default style sheet (per the CSS property) as Unicode text in the pchHostCss field. We have to allocate storage for this Unicode string – and we must use the task allocator to do this. Note that we are not responsible for freeing this memory – TWebBrowser does this.
We use the TaskAllocWideString helper function (from the CodeSnip Database) to allocate the storage and convert the string to Unicode. The routine is shown in Listing 17.
function TaskAllocWideString(const S: string): PWChar; var StrLen: Integer; // length of string in bytes begin // Store length of string in characters, allowing for terminal #0 StrLen := Length(S) + 1; // Allocate buffer for wide string using task allocator Result := CoTaskMemAlloc(StrLen * SizeOf(WideChar)); if Assigned(Result) then // Convert string to wide string and store in buffer StringToWideChar(S, Result, StrLen); end;
Listing 17
Other examples
Article #22: "How to call Delphi code from scripts running in a TWebBrowser" demonstrates another class that descends from TNulWBContainer, this time re-implementing the GetExternal method.
And that completes the browser customization code. If you need to specify different customizations simply define a new class that descends from TNulWBContainer and provide the required functionality by re-implementing the appropriate IDocHostUIHandler methods.
To use our customization class simply create an instance of TWBContainer, passing a reference to the browser control that is to be customized, set the required properties of TWBContainer then load the required document.
Note: You should always set the properties of TWBContainer before loading any document into the browser control. The reason for this is that on operating systems earlier than Windows XP SP2 the control only reads the default CSS when the first document is loaded. Consequently, changing the CSS property after loading the first document will have no effect.
In the next section we will test our code by creating a sample application that exercises TWBContainer.
相关文章推荐
- How to customise the TWebBrowser user interface (part 1 of 6)
- How to customise the TWebBrowser user interface (part 2 of 6)
- How to customise the TWebBrowser user interface (part 3 of 6)
- How to customise the TWebBrowser user interface (part 5 of 6)
- How to customise the TWebBrowser user interface (part 6 of 6)
- Delphi如何自定义IE接口(How to customise the TWebBrowser user interface)
- How To Customise the Tab Bar (UITabBar) in an iPhone Application (Part 1 of 2)
- How To Customise the Tab Bar (UITabBar) in an iPhone Application (Part 2 of 2)
- FW: How to spawn a process that runs under the context of the impersonated user in Microsoft ASP.NET pages
- How to parse the user activity of a Lotus Notes database
- How to user SSE2 instructions to improve the performance of memory copy?
- How to spawn a process that runs under the context of the impersonated user in Microsoft ASP.NET pages
- Git 管理多个分支的公共部分 How to manage the common part of multiple branches
- HOW TO: Change the Owner of a User-Defined Data Type That Is in Use in SQL Server 2000
- How to get IOleSite interface of the WebBrowser in an ActiveX control
- How to customize the context menus of a WebBrowser control via the IDocHostUIHandler interface.
- How To Use the GitLab User Interface To Manage Projects
- Git 管理多个分支的公共部分 How to manage the common part of multiple branches
- How to avoid the detection of hidden regkey by hooking RegSaveKeyA
- Customizing the Windows CE .NET User Interface, Part 2