Search code examples
xmlpython-3.xwxpythonrtf

Using wxPython Rich text control


I am using a rtf control to display text. I cannot understand the rtf control object structure. How do you get text into the rtf buffer?

I have accessed the buffer and added an xml handler. Where do I go from there?

import wx
import wx.richtext as rt


class MainFrame(wx.Frame):
    """Create MainFrame class."""
    def __init__(self):
        """Initialise the class."""
        wx.Frame.__init__(self, None, -1, 'Demonstrate wxPython Rich Text')
        self.panel = MainPanel(self)
        self.refresh_rtf(self.raw_xml())
        self.Centre()

    def refresh_rtf(self, xml):
        handler = wx.richtext.RichTextXMLHandler()
        rtf_buffer = self.rtf_control.GetBuffer()
        rtf_buffer.AddHandler(handler)

        #handler.ImportXML(rtf_buffer, self.rtf_control)
        #self.rtf_control.Refresh()

    def raw_xml(self):
        xml = ('<?xml version="1.0" encoding="UTF-8"?>'
            '<richtext version="1.0.0.0" xmlns="http://www.wxwidgets.org">'
            '<paragraphlayout textcolor="#4C4C4C" fontsize="11"'
                            'fontstyle="90"'
                            'fontweight="90" fontunderlined="0"'
                            'fontface="Ubuntu" alignment="1"'
                            'parspacingafter="10" parspacingbefore="0"'
                            'linespacing="10">'
                '<paragraph>'
                    '<text>"What do we want: "</text>'
                    '<text textcolor="#FF0000">all</text>'
                '</paragraph>'
            '</paragraphlayout>'
        '</richtext>')
        return xml


class MainPanel(wx.Panel):
    """Create a panel class to contain screen widgets."""
    def __init__(self, frame):
        """Initialise the class."""
        wx.Panel.__init__(self, frame)
        rtf_sizer = self._create_rtf_control(frame)
        main_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.Add(rtf_sizer, flag=wx.ALL, border=10)
        self.SetSizerAndFit(main_sizer)

    def _create_rtf_control(self, frame):
        rtf_style = wx.VSCROLL|wx.HSCROLL|wx.TE_READONLY|wx.BORDER_SIMPLE
        frame.rtf_control = wx.richtext.RichTextCtrl(self,
                                                 size=(400, 200),
                                                 style=rtf_style)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(frame.rtf_control)
        return sizer


if __name__ == '__main__':
    """Run the application."""
    screen_app = wx.App()
    main_frame = MainFrame()
    main_frame.Show(True)
    screen_app.MainLoop()

*****EDIT*****

For reference I have added here the Python 2 code that achieved the result I want

def refresh_rtf(self, xml):
    if xml != '':
        out = StringIO()
        handler = wx.richtext.RichTextXMLHandler()
        rtf_buffer = self.rtf_control.GetBuffer()
        rtf_buffer.AddHandler(handler)
        out.write(str(xml))
        out.seek(0)
        handler.LoadStream(rtf_buffer, out)
        self.rtf_control.Refresh()

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.


Solution

  • I have given this up as a bad job. I'm sure it's possible, but no one seems to be able to guide me

    Instead I have implemented the functionality using

    html.HtmlWindow
    

    The revised code, which functions perfectly, is:

    import wx
    import wx.html as html
    
    
    class MainFrame(wx.Frame):
        """Create MainFrame class."""
        def __init__(self):
            """Initialise the class."""
            wx.Frame.__init__(self, None, -1, 'Demonstrate wxPython Html')
            self.panel = MainPanel(self)
            self.Centre()
            self.html_display.SetPage(self.raw_html())
    
        @staticmethod
        def raw_html():
            html = ('<p><font color="#4C4C4C", size=2>What do we want: '
                        '<font color="#FF0000">all</font>'
                    '</p>')
            return html
    
    
    class MainPanel(wx.Panel):
        """Create a panel class to contain screen widgets."""
        def __init__(self, frame):
            """Initialise the class."""
            wx.Panel.__init__(self, frame)
            html_sizer = self._create_html_control(frame)
            main_sizer = wx.BoxSizer(wx.HORIZONTAL)
            main_sizer.Add(html_sizer, flag=wx.ALL, border=10)
            self.SetSizerAndFit(main_sizer)
    
        def _create_html_control(self, frame):
            txt_style = wx.VSCROLL|wx.HSCROLL|wx.BORDER_SIMPLE
            frame.html_display = html.HtmlWindow(self, -1,
                                                    size=(400, 200),
                                                    style=txt_style)
            sizer = wx.BoxSizer(wx.HORIZONTAL)
            sizer.Add(frame.html_display)
            return sizer
    
    
    if __name__ == '__main__':
        """Run the application."""
        screen_app = wx.App()
        main_frame = MainFrame()
        main_frame.Show(True)
        screen_app.MainLoop()
    

    A bit of work to convert the raw data, but not too much