1

I have created a Rich Text Editor (richtext.RichTextCtrl) using wxPython 2.8.12.1 and Python 2.7. By using PyRTFParser, I achieved handling some RTF content and images. It also supports copy paste of RTF and images.

The issue is all the client databases contain RTF data stored using VB 6 RichText control. When I load these data into my RichTextCtrl, it does not support tables, looses some formatting and bullets, and shows errors for images (Windows Meta File).

I have to provide the facility that can show old data from databases (stored using VB 6 RichText control) into wxPython.

wx.TextCtrl provides TE_RICH and TE_RICH2 facilities but does not provide a method to retrieve RTF content. It does not support images too.

Consider following:

This is the word document from which I am copying content. Word Document to Copy content from

This is the paste result in VB 6 RichText control. Content pasted in VB 6 RichText control

This is the paste result in wx.TextCtrl with TE_RICH2. Provides better tables but no images. Content pasted in wx.TextCtrl

This is the paste result in richtext.RichTextCtrl. Table data is messed and formatting lost. Content pasted in richtext.RichTextCtrl

Is there any solution to support images in wx.TextCtrl as well as get RTF content form that? Or is there any way I can directly use VB 6 RichText control in wxpython?

RTF content example (stored in database):

{\rtf1\fbidis\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fswiss\fprq2\fcharset0 Calibri;}{\f1\froman\fprq2\fcharset0 Times New Roman;}{\f2\froman\fprq2\fcharset2 Symbol;}{\f3\froman\fprq2\fcharset0 Cambria;}{\f4\fnil\fcharset0 MS Sans Serif;}}
{\colortbl ;\red0\green0\blue0;\red151\green72\blue7;\red54\green95\blue145;}
{\stylesheet{ Normal;}{\s1 heading 1;}}
\viewkind4\uc1\trowd\trgaph108\trleft-15\clbrdrt\brdrw15\brdrs\clbrdrl\brdrw15\brdrs\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx3005\pard\intbl\ltrpar\sl276\slmult1\cf1\b\f0\fs24 Categor Limits\cell\cf0\b0\f1\fs20\row
\trowd\trgaph108\trleft-15\clbrdrl\brdrw15\brdrs\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx1335\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx3005\pard\intbl\ltrpar\sl276\slmult1\cf2\b\f0\fs22 Lower Limit\cell Sales Category\cell\cf0\b0\f1\fs20\row
\cf1\f0\fs22\trowd\trgaph108\trleft-15\clbrdrl\brdrw15\brdrs\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx1335\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx3005\intbl 0\cell Poor\cell\cf0\f1\fs20\row
\cf1\f0\fs22\trowd\trgaph108\trleft-15\clbrdrl\brdrw15\brdrs\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx1335\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx3005\intbl 1000\cell Average\cell\cf0\f1\fs20\row
\cf1\f0\fs22\trowd\trgaph108\trleft-15\clbrdrl\brdrw15\brdrs\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx1335\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx3005\intbl 5000\cell Good\cell\cf0\f1\fs20\row
\cf1\f0\fs22\trowd\trgaph108\trleft-15\clbrdrl\brdrw15\brdrs\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx1335\clbrdrb\brdrw15\brdrs\clbrdrr\brdrw15\brdrs \cellx3005\intbl 7000\cell Excellent\cell\cf0\f1\fs20\row
\pard\ltrpar\sa200\sl276\slmult1\f0\fs22 
\par \pard\ltrpar\fi-360\li720\sa200\sl276\slmult1\f2\'b7\tab\f0 Item 1
\par \f2\'b7\tab\f0 Item 2
\par \pard\ltrpar\keep\keepn\s1\sb480\sl276\slmult1\cf3\b\f3\fs28 Colorful Text here\'85
\par \pard\ltrpar\cf0\b0\f4\fs17 
\par }
arvinchhi
  • 477
  • 3
  • 13

4 Answers4

1

VB6 is an ANSI RTF. ie NO UNICODE. It's also very old and many newer versions have been released.

This is how to access a newer version. It creates a RTF window, send a message to get a COM interface, then you use it via TOM (thetext object model).

    Ret = LoadLibrary("c:\windows\system32\MSFTEDIT.dll")
    If Ret = 0 Then MsgBox "Load Lib " & Err.LastDllError
    Flags = WS_CHILD + WS_HSCROLL + WS_VSCROLL + WS_VISIBLE + ES_MULTILINE + ES_AUTOHSCROLL + ES_AUTOVSCROLL + ES_NOHIDESEL + ES_WANTRETURN
    Dim barray() As Byte
    barray = "RICHEDIT50W" & vbNullChar
    gRtfHwnd = CreateWindowEx(WS_EX_ACCEPTFILES + WS_EX_CLIENTEDGE, barray(0), "", Flags, 0, 0, ScaleX(Me.ScaleWidth, vbTwips, vbPixels), ScaleY(Me.ScaleHeight, vbTwips, vbPixels), Me.hWnd, vbNull, App.hInstance, vbNull)

    Ret = SendMessageByVal(gRtfHwnd, EM_SETTEXTMODE, TM_MULTILEVELUNDO + TM_PLAINTEXT + TM_MULTICODEPAGE, 0)
    If GetTextMode(gRtfHwnd) <> 41 Then MsgBox "get Text mode = " & GetTextMode(gRtfHwnd)
    Ret = SendMessageByVal(gRtfHwnd, EM_SETEDITSTYLE, SES_ALLOWBEEPS + SES_USECRLF, SES_ALLOWBEEPS + SES_USECRLF)
    Ret = SendMessageByVal(gRtfHwnd, EM_SETLANGOPTIONS, IMF_None, IMF_None)
    If GetTextMode(gRtfHwnd) <> 41 Then MsgBox "get Text mode (2) = " & GetTextMode(gRtfHwnd)
    Ret = SendMessageByVal(gRtfHwnd, EM_SETTYPOGRAPHYOPTIONS, TO_None, TO_None)
    'Below is the default anyway with CreateWin flags spec above
    Ret = SendMessageByVal(gRtfHwnd, EM_SETOPTIONS, ECO_AUTOHSCROLL + ECO_AUTOVSCROLL + ECO_NOHIDESEL + ECO_WANTRETURN, ECOOP_OR)


Dim ParaFormat As ITextPara
Dim FontFormat As ITextFont
Ret = SendMessageAny(gRtfHwnd, EM_GETOLEINTERFACE, 0, TomObj)
Set TomDoc = TomObj
Noodles
  • 1,981
  • 1
  • 11
  • 4
  • Ver 5 is Vista or higher. You need ver 4 to do XP. – Noodles Oct 11 '14 at 18:18
  • Plus the python controls can be accessed directly and you can do anything you want. You have to use Spy++ to get the window classname (if they are windowed controls) so you know what underlying features they have. Then EM_GETOLEINTERFACE to get the TOM interface. Then you can access your RTF through SendMessage API, TOM COM interface, and/or (you can mix and match) standard python forms. You'll have to use InsertObject for pictures. I believe ver 6 of RTF does complex maths as you type (but I'm on Vista). – Noodles Oct 11 '14 at 20:07
  • My application is built using Python, I have to find a way that I can create RTF control using Python code only and to access that control. – arvinchhi Oct 12 '14 at 08:04
  • Can't python make API calls like most other languages? Can it use COM? (if your language, which is about resentment to mine, can call com and api then my comments stand). Look at http://stackoverflow.com/questions/1025029/how-to-use-win32-apis-with-python – Noodles Oct 12 '14 at 08:11
  • You are stating that you want to get the data in VB6 format from your database. How is this data stored in the database? Can you provide an example? – Werner Oct 12 '14 at 15:38
  • @Werner edited question: added RTF content example that is stored in database. please have a look – arvinchhi Oct 13 '14 at 07:02
  • @arvinchhi, sorry I thought that the current version of wx.richtext had support to load RTF format. – Werner Oct 13 '14 at 07:42
  • @Werner, I have achieved partial RTF support using PyRTFParser. But it does not support tables and having other formatting issues – arvinchhi Oct 13 '14 at 07:54
  • @arvinchhi, where did you get your copy of PyRTFParser from? The version from http://www.transana.org/developers/PyRTFParser/ does not work out the box with wxPython 2.9 or 3.0.1 and when I try 'handler.LoadString(self.txtCtrl, str)' with your string it shows lots of control characters, as if it does not recognize the string you showed above as RTF. – Werner Oct 13 '14 at 09:39
  • @Werner, Yes it is the same copy of PyRTFParser. Just create a raw string instead of normal string. e.g. `content = r"""RTF content here"""`. Let me know if it does not work, I'll paste working code here. Edit: And ya I am using wxPython 2.8.12.1 with Python 2.7. – arvinchhi Oct 13 '14 at 10:12
  • @arvinchhi, that looks better:). I am on wxPython 3.0.1 with Py2.7. The table still doesn't look right, maybe Transana can help getting the parser to support tables. – Werner Oct 13 '14 at 12:11
1

Actually, it isn't necessary to create the RTF window; you can use the technique that Noodles describes on the native RTF control by getting its OLE interface. This allows you to use the functionality in later versions of RTF and still use the native VB6 RTF control. For details, see this.

BobRodes
  • 5,990
  • 2
  • 24
  • 26
  • TOM looks great approach. But I dont know how to do this using wxPython. My whole application is ready. I am still doing RnD and got little success creating `RICHTEXT.RichtextCtrl.1` using ActiveX. Still not finding any method to send messages to underlying COM. – arvinchhi Oct 13 '14 at 15:08
  • You need to add a reference to riched20.dll to use the VB6 rich text control with TOM. I can't speak for how you might use it in the python environment though. – BobRodes Oct 13 '14 at 18:40
1

Plenty of web pages telling you how to do it. Search python COM

import win32com.client
xl = win32com.client.Dispatch("Excel.Application")

is from the first page

For API calls you use pywin32 extensions.

Something like

import win32con
import win32gui
import win32process
win32gui.EnumWindows (callback, hwnds)

But as I don't know python that's the limit of knowledge gleaned from google in 2 minutes.

CatsRuLeZ
  • 11
  • 1
1

We've shown you as much as basic programmers can.

We've shown you the API and COM calls needed.

We've shown you the real basics of doing COM and API in Python.

Here is how python does API call enum windows (from post above)

import win32con
import win32gui
import win32process
win32gui.EnumWindows (callback, hwnds)

This is how you get a TOM interface in Basic.

Dim TomObj As Object
Ret = SendMessageAny(gRtfHwnd, EM_GETOLEINTERFACE, 0, TomObj)
Set TomDoc = TomObj

If you do not read the Windows Software Development Kit it will never work. If you do not read your own language's documentation it will never work.

We've shown you what to look up.

  • Sorry for late reply.. actually I have achieved creating required window using `win32com`. But was stuck in other issues.. I appreciate your efforts – arvinchhi Oct 15 '14 at 06:35