Introduction
This article describes ways of creating a Web-style GUI in an MFC application. Under the formula �application with Web-style GUI� I mean that the user interface or a part of it is made on HTML basis. There is an example of Web-style dialog in the picture.
In an attempt to use such an interface in applications, I faced the following problems:
- Processing web interface events (getting events from DHTML to MFC code).
- Interactions with the Web elements (modifying DHTML from MFC code).
In order to solve these questions, MSDN library advices to use DHTML COM interfaces (see also Handling HTML Element Events). It seemed to me that this is a bad alternative to the simple interaction with GUI model in MFC: event maps and direct handling with control objects.
This article gives an explanation of some work methods which make easier the creation of web-interface and the work with it from the application. Namely:
- Receiving events from the web-interface through
OnBeforeNavigate2()
event.
- The interaction with the web GUI through the HTML script functions in the HTML code.
In this article, I describe CHtmlDialog
, CHtmlScript
, CHtmlCtrl
classes for the creation of Web style GUI in this article. An archive including ChtmlDialog
class and examples of its use is attached to the article (read readme.txt before use).
Examples of Web-style GUI implementations
The web-style GUI for applications was certainly used for the first time in Microsoft Applications which are part of Windows OS.
Web-interface in Windows XP help window.
Web-interface in Norton-AntiVirus program.
Web-GUI implements Inductive User Interface in Windows XP "User Accounts" dialog.
HTML display using CHtmlView class
We need to change the HTML code for the application to look different from Internet Explorer.
Displaying HTML in an MFC application is quite simple. All you have to do is to use CHtmlView
class. To try it, you have to start a new project with the help of �MFC AppWizard (exe)�. Choose �Single Document� type and turn on Document View architecture support. And on the last page of the **View class wizard, set �CHtmlView� as a base class. Next, add the HTML page into application resources.
In order to make our program to look more like an application than an Internet Explorer window, it is necessary to change something in the HTML page code:
- To set the standard background color for Windows Applications as background color.
- To forbid Internet Explorer context menu to be displayed (except the context menu above the EditBox fields).
- To forbid the mouse selection for the HTML content. Allow selection only for the text in the EditBox fields.
- Forbid the mouse cursor change over the static text. In IE, the cursor placed over the text becomes an edit cursor - �I� (as in EditBox fields) so as the user to be able to mark and copy the text from the HTML page. In Windows applications, the text cursor usually appears only in EditBoxes.
The following HTML code executes these changes. These actions are possible due to DHTML technology.
�
<SCRIPT LANGUAGE="JScript">
function onSelect1(){
if ( window.event.srcElement.tagName !="INPUT" ) {
window.event.returnValue = false;
window.event.cancelBubble = true;
}
}
function onContextMenu(){
if ( window.event.srcElement.tagName !="INPUT" ) {
window.event.returnValue = false;
window.event.cancelBubble = true;
return false;
}
}
function onLoad()
{
var Objs = document.all;
for (i=0; i< Objs.length; i++)
if (Objs(i).tagName!="INPUT" && Objs(i).tagName!="A")
Objs(i).style.cursor = "default";
document.onselectstart = onSelect1;
document.oncontextmenu = onContextMenu;
}
</SCRIPT>
<BODY onload="onLoad();"
leftmargin=0 topmargin=0 rightmargin=0 bottommargin=0
style = "background-color: buttonface;" >
// the HTML background color will be as in Windows Applications
�
In such a way, we have created an application that displays HTML as its interface. The Menu, Toolbar and status line remained, but this is normal, because we aren�t forced to give up using traditional controls, and in this way gain a certain flexibility.
At this step, we faced the DHTML technology due to which everything here is possible. The DHTML technology itself is possible due to DOM (Document Object Model) technology. The DOM represents the HTML document as objects [MSDN Library].
HTML window event processing
What is missing in CHtmlView?
A typical script working with interface elements presumes receiving events from them (buttons for example) and data placing (for example, into a text field). Particularly in our case, it is necessary to organize an interaction of the HTML window with the MFC code. This in not a complicate thing to do � the idea is to transmit the event from HTML to MFC code using the function OnBeforeNavigate2
of the CHtmlView
class [Thomas Aust].
In HTML, or being more specific Dynamic HTML, also exists the conception of event. The possibilities of the event model in DHTML are very large, for example, an event can be stopped at a certain step of its processing.
At the occurrence of the event in HTML, it can be transformed into a window.navigate(%line%)
call. The MFC code will receive such an event as a OnBeforeNavigate2
call with the %line%
parameter. It is possible to transmit any HTML parameters in %line%
, and MFC code will be able to process the user�s action. The transmission of event "click OK button", at the same time the text from txtBox
is transmitted:
.
.
.
<SCRIPT LANGUAGE="JScript">
function onBtnOk(){
var Txt = txtBox.value;
window.navigate("app:1005@" + Txt);
}
</SCRIPT>;
<BODY>
.
.
.
<input type=text style="width:50" id=txtBox >
<input type=BUTTON value="Ok" onClick="onBtnOk()" style="width:45%">
// the button has an event handler � the onBtnOk() script function
.
.
.
</BODY>
</HTML>
The MFC code which will process the event:
void CHtmlCtrl::OnBeforeNavigate2( LPCTSTR lpszURL,
DWORD nFlags,
LPCTSTR lpszTargetFrameName,
CByteArray& baPostedData,
LPCTSTR lpszHeaders,
BOOL* pbCancel )
{
const char APP_PROTOCOL[] = "app:";
int len = _tcslen(APP_PROTOCOL);
if (_tcsnicmp(lpszURL, APP_PROTOCOL, len)==0) {
OnAppCmd(lpszURL + len);
*pbCancel = TRUE;
}
CHtmlView::OnBeforeNavigate2(lpszURL, nFlags,
lpszTargetFrameName, baPostedData,
lpszHeaders, pbCancel);
}
As not only the HTML but also the MFC code can be the event source, it is necessary for the MFC code to be able to transmit data into HTML. In order to make it possible, we can call scripts (Jscript\VBScript) in HTML and transmit data as script-functions� parameters. The idea and realization of this method belong to [Eugene Khodakovsky]. The acquisition of �Script� object from HTML:
void CHtmlCtrl::OnDocumentComplete(LPCTSTR lpszURL)
{
.
.
.
HRESULT hr;
hr = GetHtmlDocument()->QueryInterface(IID_IHTMLDocument,
(void**) &m_pDocument);
if (!SUCCEEDED(hr)) {
m_pDocument= NULL;
return;
}
IDispatch *disp;
m_pDocument->get_Script( &disp);
.
.
.
}
Next, the MFC code which calls the specific script function with the parameters:
.
.
.
CStringArray strArray;
strArray.Add("Parameter 1");
strArray.Add("Parameter 2");
strArray.Add("Parameter 3");
m_HtmlCtrl.CallJScript2("SetParameters", strArray);
.
.
.
The scripts in HTML are very powerful and easy tools. It is possible to write a whole program with it which will handle the HTML content and react to users� actions. The DHTML object model makes this programming quite easy.
In this way, the part of the MFC code which works with the interface and user�s actions can be moved to the HTML script. If the HTML pages are kept apart from the application, it is possible to change the interface�s logic without recompiling the EXE file.
CHtmlDialog � the HTML-based dialog window
Why it is necessary to use Advanced Hosting Interfaces?
Every application has dialogs besides the main window. These dialogs can have a quite complicated user interface. I mean not only the design, but also the reaction to user�s actions. So, it makes sense to use DHTML here too. The problem "How to place a class derived from CView
on a dialog" is solved in the article by [Paul DiLascia, MSDN]. After the changes in CHtmlView
, we have a CHtmlCtrl
class (derived from CView
) which can be placed on a dialog. The CHtmlDialog
class solves two problems � setting the dialog window name and its size. These parameters are indicated on the HTML page. The CHtmlDialog
class use:
- Insert the dialog into resources. Place the STATIC element on it (STATIC will be replaced with the HTML control item). Next, create an MFC based class on this dialog (inherited from
CDialog
).
- Change the inheritance class to
ChtmlDialog
in the header file (Dlg4.h for example).
class CDlg4 : public CHtmlDialog
{
public:
- Add the
CHtmlDialog
constructor call in the Dlg4
class constructor in the CPP file (Dlg4.cpp for example). CDlg4::CDlg4(CWnd* pParent )
:CHtmlDialog(CDlg4::IDD,pParent, IDR_HTML4,
IDC_STATIC1)
{
}
The ChtmlDialog
class also allow to change dialog size from HTML. (See _onHtmlCmd
in CHtmlDialog
).
Dialog window screenshots.
The hereby given Dialog example is taken from real life: it is necessary to give the user the possibility to add data blocks of a certain type on the smart-card. Although, it can be not a smart-card, but the file database of this card. So, this dialog must be logical: show the necessary icon � of a document or a smart-card (in the top left corner), use the text �Key� instead of �Document�. In general, the dialog must be adaptable. But this is not all.
Next, the things from Usability area come � the Dialog is displayed in a shorten variant at first, because the user has no need to know how many free space is available. The program was developed for Administrators and Developers. For example, the Administrator doesn�t have to know and see every time the free space number and the message that new data block size can be changed. The information about free space is given to the user at the very beginning, here it is needed to the Developer mostly (testing while developing smart-card applications).
If there is no free space on the smart-card, the Dialog will react � show the �Question� icon, the explanatory text and will disable the �OK� button. Next, the Dialog does user�s work � chooses the block which does not exist on the smart-card (or in the document) at the opening. If the user chooses an existing block , the Dialog will react � show the �Question� icon, the explanatory text, and will disable the �OK� button.
The main program calls this dialog at any time � even if the smart-card is full. In this situation, the dialog appears in an extended variant with the �Question� icon, explanatory text, and blocked �OK� button. Here the Dialog plays an informational role, otherwise the error message �there left no free space� must be shown, and instead a known dialog will appear � as a result, the user�s memory is not so loaded. As a result, such �interface logic� takes a lot of C++ code. And imagine that the application has 5 such dialogs.
Everything is almost finished, but there still are two problems:
- The window which displays HTML in our application (ActiveX element) will always have a �pressed in� border and this cannot be changed. The explicit window options setting through
SetWindowLong( GWL_STYLE)
doesn�t work. This isn�t looking very good.
- If the user changes the HTML display options (Internet Explorer Properties-> General Tab, Colors, Fonts,.. Buttons), it will influence the HTML appearance in our application, in other words, the fonts and colors will change. This doesn�t suit anyone. The application user may simply not recognize it when it is launched next time.
If the first problem can be tolerated, the second one is very serious. It is possible such a situation will occur when the application will look different depending on user�s IE settings.
Here is the way an HTML dialog looks if the user changes display settings in IE options. To solve this problem, it is necessary to provide the Advanced Hosting Interfaces support. Advanced Hosting Interfaces (AHI) are such COM interfaces which the WebBrowser�s ActiveX element has (starting with version 4.0). They help to take full control over the WebBrowser element [MSDN Library]. The realization of AHI in applications and this interfaces� advantages are well demonstrated in [Ethan Akhgari]�s examples.
The problems described here are solved by OnGetHostInfo
and OnGetOptionKeyPath
event redefinition (see Html_Host_Handlers.cpp). I�ll stop at this point. Thank you for your attention.
Usage
Please take a look at the projects in the source files archive.
Revision history
- 2003 December, Initial public release at Russian dev site.
- 2004 July, translation into English.