2
votes

I've seen a lot of posts about this around the Internet but none of the advice works.

Here is my test code:

import wx
class DisplayText(wx.Dialog):

    def __init__(self, parent, text="", displayMode=0):

        # Initialize dialog
        wx.Dialog.__init__(self, parent, size=(480,320), style=( wx.DIALOG_EX_METAL | wx.STAY_ON_TOP ) )

        # Freeze UI so user won't see stuff flashing
        self.Freeze()

        # (For Mac) Setup a panel
        self.panel = wx.Panel(self,size=(480,320))
        self.panel.SetBackgroundColour(wx.Colour(0,0,128))

        # Setup sizer for vertical centering
        self.sizer = wx.BoxSizer(wx.HORIZONTAL)

        # Create text field
        self.txtField = wx.StaticText(self.panel,size=(448,-1),style=wx.ALIGN_CENTRE_HORIZONTAL)
        self.txtField.SetLabel(text)
        self.txtField.Wrap(448)
        self.txtField.SetLabel(self.txtField.GetLabel())
        self.txtField.SetFont(wx.Font(36, wx.DEFAULT, wx.BOLD, 0))      
        self.txtField.SetForegroundColour(wx.Colour(255,255,255))

        # Add the static text to the sizer
        self.sizer.Add(self.txtField,1, 0,15)
        self.panel.SetSizer(self.sizer)

        # Ensure layouts are applied
        self.sizer.Layout()

        # Thaw UI
        self.Thaw()

        # Center form
        self.Center()

app = wx.App(False)

c = DisplayText(None, text="Now is the time for all good men to come to the aid of their country.")
c.Show()
import wx.lib.inspection 
wx.lib.inspection.InspectionTool().Show() 
app.MainLoop()

Based on my understanding of StaticText, the problem seems to be that when I call the Wrap() function, the control wraps the text but does not change the control's size. This means the sizer, unaware of the actual vertical size of the wrapped text, cannot properly reposition the static text.

One post I found suggested using wx.EXPAND, but this does not solve the problem. Allowing the sizer to expand the StaticText simply makes the StaticText fill the entire frame, and since StaticText doesn't vertically center in and of itself, the text will end up at the top of the form, not the center.

Another post suggested experimenting with wx.ALIGN_CENTER_VERTICAL in the sizer, but this didn't help either, because the same problem remains - the sizer can only work on the size of the control, and the control's size is NOT changing after the text is wrapped and re-rendered.

Various attempts have resulted in either the text wrapped but at the top of the form, only the first line being shown in the center of the form, only the first line being shown at the top of the form, and the text not being wrapped and thus flowing off the right hand edge of the form. But no combination of anything I've read has worked to vertically center the wrapped text on the form.

What I therefore would have to be able to do is somehow figure out the size of the text vertically after the wrapping has taken place. This can't be assumed because on different platforms, or even on the same platform, or even based on the text itself, the font's vertical pixel size may differ. So this needs to somehow be calculated.

I'm thinking if I can somehow figure out the actual size of the rendered text inside the StaticText control, I could then explicitly set the control's size and then let the sizer do its work.

This seems like it should be a relatively simple thing to accomplish...

Advice would be greatly appreciated!

1

1 Answers

1
votes

The key was the static text style; you needed to enable the multi-line style for the wrap to work: wx.TE_MULTILINE.

I also set the layout on the panel itself, not the sizer but that might not be related to the problem.

On my machine, Windows 7 64bit, I needed to change the SetFont call; you might need to change it back.

import math
from threading import Thread
import time
import wx

e = lambda x: complex(math.cos(x), 0) + complex(0, math.sin(x))
r = lambda x: ((e(0*math.pi/3.0)*e(x)).real + 1)/2.0
g = lambda x: ((e(2*math.pi/3.0)*e(x)).real + 1)/2.0
b = lambda x: ((e(4*math.pi/3.0)*e(x)).real + 1)/2.0
colo = lambda rad: map(lambda x: int(128 * x(rad)), [r, g, b])

class DisplayText(wx.Dialog):

    def __init__(self, parent, text="", displayMode=0):

        # Initialize dialog
        wx.Dialog.__init__(self, parent, size=(480, 320), style=( wx.DIALOG_EX_METAL | wx.STAY_ON_TOP ) )

        # Freeze UI so user won't see stuff flashing
        self.Freeze()

        # (For Mac) Setup a panel
        self.panel = wx.Panel(self, size=(480, 320))
        self.panel.SetBackgroundColour(wx.Colour(0, 0, 128))
        self.panel.SetBackgroundColour(wx.Colour(*colo(0)))

        # Setup sizer for vertical centering
        self.sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.panel.SetSizer(self.sizer)

        # Create text field
        self.txtField = wx.StaticText(self.panel, size=(448, -1), style=(wx.ALIGN_CENTRE_HORIZONTAL | wx.TE_MULTILINE ))
        self.txtField.SetFont(wx.Font(36, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))      
        self.txtField.SetForegroundColour(wx.Colour(255, 255, 255))
        self.txtField.SetLabel(text)
        self.txtField.Wrap(448)
        self.sizer.Add(self.txtField, 1, 0, 15)

        # Add the static text to the sizer
        # Ensure layouts are applied
        self.panel.Layout()
        self.panel.Refresh()

        # Thaw UI
        self.Thaw()

        # Center form
        self.Center()

        self.angle = 0
        self.angle_inc = (2*math.pi)/25.0

    def change_colour(self):
        t = Thread(target=self.epilepsy_mode)
        t.start() 

    def epilepsy_mode(self):
        while True:
            time.sleep(0.02)
            self.panel.SetBackgroundColour(wx.Colour(*colo(self.angle)))
            self.panel.Refresh()
            self.angle = (self.angle + self.angle_inc) % (2*math.pi)

app = wx.App(False)

c = DisplayText(None, text="Now is the time for all good men to come to the aid of their country.")
c.Show()
#import wx.lib.inspection 
#wx.lib.inspection.InspectionTool().Show() 
c.change_colour()

app.MainLoop()