Using tables in TRichEdit or TWebBrowser; Translating a location in an HTML file to a screen x,y coordinate

BACKGROUND

Our company creates form-filling software for the government. Our current technique for displaying forms for completion by the user involves using a Delphi component called TRichEdit. Our method uses three basic steps shown below with a simple example for clarification.

1. First an RTF file that is a duplicate of the subject form is loaded into the TRichEdit component for display on the user's screen. A typical RTF file might look like this:

     {RTF Header stuff}
     A. Enter an amount on line A. /$1/
     B. Enter an amount on line B. /$2/
     C. This is the total of A & B. /$3/

2. Once the form is loaded into the TRichEdit component, our program locates the variables and substitutes answer text for each variable except the "current" variable. We use TRichEdit's FindText method to locate the "current" variable (i.e., /$1/) on the form. TRichEdit's SelStart property then lets us put the cursor at the location of that variable.

3. When the cursor is properly located at the "current" variable, we use an EM_POSFROMCHAR Windows message to determine the screen X,Y coordinates of the cursor location and then superimpose a text input box like TEdit (or any other Delphi control) at that location so that the user can enter the requested information.

Every time the user presses tab or clicks on an area of the form, the program updates its calculations, advances the "current" variable and refreshes the page with the input control in the new "current" location.

PROBLEM

As we encounter more complicated government forms, we've discovered that formatted tables work the best for laying them out. Unfortunately, we're finding that the TRichEdit component is not very capable when it comes to rendering tables accurately. It's not that the tables we are using are extremely complex, it's just that the TRichEdit is not capable of rendering anything more than a very basic table. We've tried a third-party solution by Woll2Woll software (TwwRichEdit), and although the RTF capabilities were much better than Borland's TRichEdit, the TwwRichEdit component still doesn't do tables adequately, i.e., not restricting text to a cell's boundaries and not observing font changes from cell to cell.

QUESTION

A. We need a TRichEdit or substitute RTF component that has (1) the ability to render more than just simple tables, and (2) permits the use of the FindText, SelStart and EM_POSFROMCHAR (or similar) commands so we can use it as explained above. Are we overlooking a way to make TRichEdit handle tables better or is there a 3rd party RTF component that has the desired functionality?

B. If the answer to A above is "no", using Delphi's HTML component (TWebBrowser) might work because it handles tables much better than the TRichEdit component. However, we don't know how to get the above-described functionality out of the HTML component. For example, positioning a cursor at a particular location in the HTML file (i.e, like SelStart does for RTF files) and then defining that location in terms of screen x,y coordinates (i.e., EM_POSFROMCHAR) so we can superimpose the appropriate Delphi input component (i.e., TEdit). Could you provide an example of these two functions using the HTML component?

We have countless forms in RTF format, so the first of the two methods is more desirable. I apologize for the length of this question.
efzAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

paulb1989Commented:
Maybe the TRichView component will help, it has many more capabilities than TRichEdit:

http://www.trichview.com/
0
efzAuthor Commented:
You're quite right. The TRichView component boasts many more capabilities specifically related to complex tables. Several days ago, before I posted this question on Experts Exchange, I sent an inquiry to TRichview. They haven't responded to my question yet. I did note, however, that their TRichView component did not inherit from the TCustomRichEdit control, so I'm guessing that the SelStart function may not be available in their component. Hopefully they'll let me know a bit more about this. Please accept my sincere thanks for your comment.
0
JaccoCommented:
We use a component WPRichEdit made by the company WPTools (written by Julian Ziersch). We first bought it because it was the only component we could find supporting right-aligned and decimal-aligned tabs. But it also supports complex tables and has extensive support for mail merging. We use it for automatic mail merging but I think it would be very possible to do manual filling of the insert points as well.

We have found now way of improving the existing TRichEdit since it is based on the inner working of the RichEd20.dll of microsoft. This DLL is included only to make WordPad work and does not include all formatting features Word does. It does not support the full RTF standard.

The SelStart method would have to change a bit but the concepts of moving the cursor around in the TWPRichEdit is about the same.

Regards Jacco
0
Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

JaccoCommented:
Oh yeah, here is a link to their site:

http://www.wpcubed.com/index.htm

We always had very good email support from Julian as well.

Regards Jacco
0
paulb1989Commented:
In regards to TRichView there is an example of moving the caret to a paragraph below, so its possible to move the caret.

http://www.trichview.com/support/dnewsweb.cgi?cmd=article&group=trichview.support.examples&item=26&utag=
0
prevarantCommented:
...just listen
0
efzAuthor Commented:
To Jacco: Thanks for your pointer. I don't know how many TRichEdit substitutes there are, but I was hoping for specific knowledge about these issues so that I might get a confirmation without needing to purchase each one or download and test each demo in order to find out whether it does what I want. I've downloaded the TRichView materials and started combing thru the Help files. I'll try WPRichEdit next once I determine whether TRichView solves my problem. You and I were thinking along parallel lines concerning RichEd20.dll. I found Version 4. However, both RichEd20 and RichEd32 are present in my systems folder, how do I know which one Delphi 7 is using? You may be close on this because I noticed that WordPad (Windows XP) handles tables much better than my Delphi component. I believe that if I could get WordPad's functionality in my Delphi component my problem would be largely solved. Is it possible that the Delphi component is using RichEd32, yet WordPad is using RichEd20? How can I be certain which version my Delphi component (currently TwwRichEdit from Woll2Woll) is using?
0
OctabunCommented:
To find out what Windows control is used by a Rich Edit component use Spy++ or similar utility (or write your own to enum windows). With Delphi, both 7 and 2K5, TRichEdit should always use RichEd32, just look into the VCL code.

Another link for you: http://jvcl.sourceforge.net. This is project Jedy with lots of components, including TJvRichEdit that uses the best Rich Edit version available.

Yes, it is possible to use TWebBrowser instead of TRichEdit. Implement form in HTML, its logic in Java Script, and use document.external to communicate to the Delphi application.

"WebBrowser customization" MSDN topic is a good starting point. Since relevant interfaces and structures are not translated from C headers to Delphi units, you will need MSDN and Platform SDK any way.

The basic idea is as follows: create a descendent of TWebBrowser and implement IDocHostUIHandler in it. IDocHostUIHandler.GetExternal returns IDispatch that Java Script sees as document.external.

The only issue not covered in MSDN is how IDocHostUIHandler gets to Web browser. Fortunately, the answer is very simple: as soon as you implement IDocHostUIHandler, Delphi COM support framework makes it available through QueryInterface, and TOleControl implements IOleSiteClient and presents it to Web browser. Web browser calls QueryInterface and gets IDocHostUIHandler.
0
efzAuthor Commented:
To PaulB1989: I've had te weekend to study TRichView and I don't think it's going to do what I ask. I don't know what RTF standard it adheres to but it didn't have the fidelity that I was hoping for. Although cell size and place was accurate, and text was restricted to the intended cell, font formatting was lost, ie., font changes and styles applied within a cell were ignored. Of course that's a big part of our form design, so I don't think TRichView is the answer. I'm not looking for a clone of Microsoft's Word for Windows, but I need something that will render tables at least as accurately as WordPad. Many thanks for your time and attention. LEt me know if anything else comes to mind.
0
efzAuthor Commented:
To Jacco: If it's not too much trouble, I could email a PDF of the government form along with our RTF version. If you could load it into WPRichEdit component and let me know if the two look reasonably similar, I'd be satisfied. You could also load our RTF file into Word for Windows or WordPad (with WordPad you'll need to set the margins) to compare whether the WPRichEdit component is accurate enough. Let me know if you're interested and, even if you're not,  thank you for all your help anyway.
0
JaccoCommented:
Mail it to Jacco@despammer.com and I'll see what I can do.

Regards Jacco
0
OctabunCommented:
Please note that according to microsoft there are 3 versions of RichEdit. Version numbers of RichEdit20.dll indicate that there are 5. The actual version used depends mainly on the versions of Windows, Word, IE installed.

I looked into the TJvRichEdit code and found that, naturally, new features are added with every new version. TJvRichEdit knows about version 4, so some WorldPad features on Windows XP may be missing.

Correct RichEdit component should look exactly like WordPad. If you are testing WPRichEdit on XP, check for the latest version.

Just in case RichEdit does not work for you, there is another, MSDN/SDK free, way to link HTML form with your application: create an ActiveX object to communicate with your application and use it in JavaScript.
0
efzAuthor Commented:
To Octabun: You're pushing the limits of my meager skill level, but here's how I followed up on your suggestion. I took a blank form and looked at the interface's "uses" command and noticed that when I added Delphi's TRichEdit control to the form, Delphi added the ComCtrls reference to the "uses" command. I looked up the ComCtrls.pas file and noted a call to RichEdit in its "uses" command. I followed that to the RichEdit.pas file and found the following code:

------------------------------------------
const
  {$EXTERNALSYM cchTextLimitDefault}
  cchTextLimitDefault     = 32767;


  {$EXTERNALSYM RICHEDIT_CLASSA}
  RICHEDIT_CLASSA       = 'RichEdit20A';     { Richedit2.0 Window Class. }
  {$EXTERNALSYM RICHEDIT_CLASSW}
  RICHEDIT_CLASSW       = 'RichEdit20W';     { Richedit2.0 Window Class. }
  {$EXTERNALSYM RICHEDIT_CLASS}
  RICHEDIT_CLASS = RICHEDIT_CLASSA;
  RICHEDIT_CLASS10A       = 'RICHEDIT';        { Richedit 1.0 }

---------------------------------------------

Unless I don't understand what I'm reading (which could very well be the case), it looks to me like my Delphi TRichEdit control is NOT using the riched32.dll. Can you tell whether I'm correct about this? If so, how do I change it to utilize the riched32.dll instead of the riched20.dll? I'm excited about this  because it seems possible that making this switch might solve my problem.

Please accept my sincere thanks for any other light you may be able to shed on this issue.
0
OctabunCommented:
I look at the D2K5 code (just trying to decide if it is still OK doing Borland).

When you add TRichEdit to the form, Delphi adds a reference into your form class, like

TRichedit1: TRichEdit;

If you press and hold Ctrl and point on "TRichEdit" with the mouse, it will get underlined as a Web link. Click it when underlined and Delphi will go to the declaration: ComCtrls will be opened and the cursor located at

TRichEdit = class(TCustomRichEdit)

You will see that TRichEdit is exactly TCustomRichEdit with published properties. This is for those who would like to modify TRichEdit: they will inherit from TCustomRichEdit and decide what properties are published themselves.

Do the same link navigation with TCustomRichedit and you will see that it inherits from TCustomMemo, which is the base for all memos and, as such, knows nothing about Windows RichEdit. Thus, all rich edit specific code is in TCustomRichEdit class.

Go to CreateParams member. The parameters for Windows window creation are made there. You will see a constant definition of the TRichEdit library

  RichEditModuleName = 'RICHED32.DLL';

and another constant name of the windows class

  CreateSubClass(Params, 'RICHEDIT');

Thus, Delphi per se is limited to RichEdit1. This can be tested in another way: start a Delphi app containing TRichEdit and look at the libraries it loads. Note TRichEd32.dll.

How come the RichEdit unit knows more? It has the following comments:

{       Copyright (c) 1985-1999, Microsoft Corporation  }
{       Translator: Borland Software Corporation        }

It indicates that this unit is a translation of the Microsoft C/C++ header file found in Platform SDK into Delphi. Yes, Microsoft knows everything about its RichEdit, but Delphi does not use all the knowledge.

For comparison, TJvRichEdit creates parameters as

  case RichEditVersion of
    1:
      CreateSubClass(Params, RICHEDIT_CLASS10A);
  else
    CreateSubClass(Params, RICHEDIT_CLASS);
  end;

So, it knows about 2 RichEdit classes and finds the proper one as

          if GetFileVersionInfo(PChar(FileName), Wnd, InfoSize, VerBuf) then
            if VerQueryValue(VerBuf, '\', Pointer(FI), VerSize) then
            begin
              RichEditVersion := (FI.dwFileVersionMS and $FFFF) div 10;
              if RichEditVersion = 0 then
                RichEditVersion := 2;
            end;

This looks into the version resource of RICHED20.DLL, which on WindowsXP SP2 with Office 2003 is 5.30.23.1221. So, there are 5 versions of RichEdit.

Now I search the Jedy code and see lots of strings like

  if RichEditVersion >= 2 then

with numbers 1 .. 3 and >= and <= operators. So, Jedy code knows about 4 versions of RichEdit.

Hope this helps.

0
efzAuthor Commented:
To Octabun: I obtained the lastest versions of JEDI's JvRichEdit control and I've come to the following conclusions. None of the RichEdit controls (Delphi's TRichEdit, Woll2Woll's TwwRichEdit, TRichView or JEDI's TJvRichEdit) is good enough at handling tables to do the kind of formatting I require. After reviewing these components I've noticed that the specific problem is always the same, that is, none of these components are able to preserve paragraph formatting within cells. In other words, if you have two or three paragraphs in a cell, even short lines of just a word or two, these components end up stringing the text together in one long line (sans line breaks) and run it right out of the cell boundaries. I thought WordPad handled this adequately, but I was wrong. WordPad has the same deficiency. I tried splitting cells in different ways as well as nesting tables in order to attempt to preserve paragraph formatting, but none of my workarounds worked. Some weren't able to preserve even character formatting and the ones that did couldn't preserve paragraph formatting, so after a year of toying with this problem on and off, I think that your assistance has finally made me realize I've exhausted my possibilities and I should give it up and try another method, i.e,, using HTML files as our form files. You and Jacco have been extremely kind and patient in helping me and for that you have my sincerest thanks.
0
OctabunCommented:
And still the saga is not over. I tested your case (left/right justified, numbered, bulleted paragraphs in table cells, a table in a table): TRichEdit (naturally), TJvRichedit (unfortunately), and .NET RichTextBox (?!) all fail exactly as you describe.

But WordPad works OK!

I decided that something has changed recently and looked into "Platform SDK for Windows XP SP2". Now Microsoft counts 4 versions of RichEdit:

Rich Edit version / DLL / Class name:

1.0 / Riched32.dll / RichEdit
2.0 / Riched20.dll / RichEdit20A or RichEdit20W
3.0 / Riched20.dll / RichEdit20A or RichEdit20W
4.1 / Msftedit.dll / RICHEDIT50W
 
Version 4.1 should be available in Windows XP SP1 and up.

When I forced TRichEdit and TJvRichEdit to load Msftedit.dll and subclass RICHEDIT50W, both displayed tables perfectly. So, it must be possible to fix either component (IMHO, with TJvRichEdit it is easier) to solve your formatting problem. Or just wait until Jedi incorporates SP1 features.

INHO HTML is still the way to go since sooner or later you will need HTML of your forms, say for email, and there is no easy way to convert RTF to HTML.
0
efzAuthor Commented:
To Octabun: I hear what you're saying about evolving from RTF files to HTML files and I agree whole heartedly. The reasons I would abandon the RTF format with great reluctance is that (1) our company has hundreds of forms already in RTF format, (2) our programs offer a feature that allows the user to send any form to the word processor instead of the printer and the RTF format is handled better than HTML by both Word and WordPerfect, and (3) our forms can be layed out by a non-programmer using Word whereas the HTML versions would require substantially more knowledge on the part of the designer.

You may have noted that I first said WordPad worked okay with tables and then in my last comment I changed my tune saying it didn't. The reason was you hunch that "something has changed recently." I had been doing most of my testing using WordPad in XP (Version 5.1, Build 2600 ... : Serv Pack 2). My last comment was based on using WordPad in Win2000 (Version 5.0, Build 2195, Serv Pack 4).

Programming's changed alot since I began in 1984, and there's a lot I don't know, but your last comment raises two questions:

1. Could you describe in simple-to-follow steps how to "force" the Delphi TRichEdit component to use the latest version of RichEd? We currently use TwwRichEdit but I think I could apply the method if you showed me how to do it with the Delphi component. Actually the ww version is derived from TCustomRichEdit, so I may not have to do anything other than follow your instructions.

2. From a distribution standpoint, if "forced" it as you say, would my resulting program only run correctly on Windows XP machines? In other words, if my users had the correct RichEd dll, could they run our programs as desired even if they were using Windows 98SE for example?
0
OctabunCommented:
1.

For Delphi 2005 TRichEdit:

Copy  ComCtrls to your project folder, so that your changes are local to the project.

Add ComCtrls to your project, to be sure that your modified file is used instead of Delphi stock ComCtrls.

Go to TCustomRichEdit.CreateParams and edit RichEditModuleName value as "RichEditModuleName = 'MSFTEDIT.DLL';"

Edit the CreateSubclass call as "CreateSubClass(Params, 'RICHEDIT50W');"

Run the project and find out that an exception is raised in TRichEditStrings.Insert. It is sort of saveguard check. Since the code looks reasonable, most likely the version 1.0 check does not hold with version 4.1, so comment it out:

    //if RichEdit.SelStart <> (Selection.cpMax + Length(Str)) then
    //  raise EOutOfResources.Create(sRichEditInsertError);

Now "richEdit.Lines.LoadFromFile(OpenDialog.FileName);" displays correctly formatted table. I do not know if there are other incompatibilities between Delphi version 1.0 code and used version 4.1.

In TJvRichEdit there is code that determines the RichEdit version trying to load RichEd20.dll and creates subclass accordingly. Just forcing it to load MSFTEDIT.DLL does not produce any exceptions, most likely to numerous RichEditVersion checks.

If TwwRichEdit does the same, try to load MSFTEDIT.DLL before RichEd20.dll and subclass RICHEDIT50W on success. This will provide code that will work on any Windows and work correctly on XP SP1 and up.

2.

Since MSFTEDIT.DLL is required for RichEdit to work correctly, yes, it will normally work correctly only on WinXP SP1 and up.

If you look at functions exported by MSFTEDIT.DLL, you will see that most likely it does 2 things: registers the RICHEDIT50W window class with REExtendedRegisterClass, and provides the window procedure for this class with RichEditWndProc.

If it is legal to redistribute MSFTEDIT.DLL with your application, which I doubt, it MAY work on Windows 98 if you a) register the RICHEDIT50W class yourself (trial and error playing with REExtendedRegisterClass parameters, starting with none), or b) do not subclass any Windows controls but use RichEditWndProc from MSFTEDIT.DLL to handle all messages not handled by the TwwRichEdit window procedure (trial and error play with WNDCLASSEX parameters when you register your class). I would estimate the chances of success for this hack at about 25%, so IMHO it is wise to require Windows XP SP1.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
efzAuthor Commented:
To Octabun: Good gravy man! I think you're on to something. I did exactly as you said and got the Insert error. When I commented out the line of code you suggested, everything worked. The only flaw I noticed in my admittedly short test is that graphics in cells don't appear. I was using the Delphi component TRichEdit. Unfortunately for me, that shortcoming made the solution ng. I had ready access to the TwwDbRichEdit component (which I've been mistakenly referring to as TwwRichEdit) so I decided to try your solution on that component. I encountered a good omen right off the bat when I noticed while makeing the recommended changes that Woll2Woll had commented out the same code you recommend striking out. Excellent call on your part, Master Octabun. I'm elated to report that the TwwDbRichEdit control presented the embedded bmps fine and in brief testing I could detect no obvious shanks, so I consider your answer to be absolute gold. It worked so well I decided not to try the graphics testing on the JEDI version. The JEDI component also seemed top-notch and might have worked, but Help files were not available (if I understood correctly) and at this time I didn't want to make the investment of time it would take to learn how to use TJvRichEdit.

On the compatibility issue, we have a number of Windows environments on which to test your solution and it seemed to work on all of them so long as they have the msftedit.dll in the the system folder. My programming rarely involves registering classes, so (1) I wasn't able to follow your instructions on this point, and (2) your solution seemed to work without taking your suggested registration steps. Excellent work as far as I'm concerned.

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.