Limiting StaticText width

I have a panel with several sizers and some gauges that I want to
expand to the size of the area or frame that the panel is placed
in which is working fine. I'm experiencing a problem however
when a StaticText increases to a size that will be larger than the
space available, expanding the edges of the panel and the
gauges off the screen or visible area. I was wondering if there
was a way to stop the text from doing that by snipping it short
with a ... without specifying a precise size, basically so it knows
where the edge of the display area is. I can get around it by
moving the texts that I update to their own panels so I can call
Update on their panels, leaving the gauges to be the same size,
but the text still runs out of my StaticBox and off the display
which isn't ideal.

I could wrap the text down a line but I notice wrap breaks on
spaces and as my long text is a file path it is likely to not have
spaces, is it possible to break on something other than spaces?

Is anyone aware of a solution to this?

Hi,

I have a panel with several sizers and some gauges that I want to
expand to the size of the area or frame that the panel is placed
in which is working fine. I'm experiencing a problem however
when a StaticText increases to a size that will be larger than the
space available, expanding the edges of the panel and the
gauges off the screen or visible area. I was wondering if there
was a way to stop the text from doing that by snipping it short
with a ... without specifying a precise size, basically so it knows
where the edge of the display area is. I can get around it by
moving the texts that I update to their own panels so I can call
Update on their panels, leaving the gauges to be the same size,
but the text still runs out of my StaticBox and off the display
which isn't ideal.

I could wrap the text down a line but I notice wrap breaks on
spaces and as my long text is a file path it is likely to not have
spaces, is it possible to break on something other than spaces?

Is anyone aware of a solution to this?

You you can't wrap the StaticText content, then the only solution I
can see is to "ellipsize" it, i.e. shortening it by prepending or
appending "..." to the file path. To do that, however, I believe your
best bet would be to go owner-drawn (or simply subclass
wx.lib.stattext), measuring the text size on the OnSize event for your
control and, if needed, prepend/append the "..." to you path.

Attached a proof of concept, with "ellipsization" at the end (i.e.,
"..." is appended and file name is truncated at the end). I gather it
would be trivial to extend to prepending the "..." instead of
appending.

Oh, by the way, in wxPython 2.9 you can also use
wx.StaticText.Ellipsize to (maybe) do the same thing, although I have
never used it myself.

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

EllipticStaticText.py (4.53 KB)

···

On 28 November 2011 21:54, Paul wrote:

I need to have a transparent background on the statictext, if I set
backBrush to wx.TRANSPARENT the text old text isn't drawn over
and I soon end up with a chunky black rectangle as the texts
stack up. Any idea how to prevent this?

Also using the example in my app isn't working exactly, the get
client area I presume gets a bigger size than it has available, the
text doesn't span the full width of the panel (there's something
to the left) and the panel doesn't span the full frame (the panel
is just part of the whole window). I've tried subtracting the x
from the static text position and other things to try and get the
size but I can't seem to crack it.

Hi,

I need to have a transparent background on the statictext, if I set
backBrush to wx.TRANSPARENT the text old text isn't drawn over
and I soon end up with a chunky black rectangle as the texts
stack up. Any idea how to prevent this?

Also using the example in my app isn't working exactly, the get
client area I presume gets a bigger size than it has available, the
text doesn't span the full width of the panel (there's something
to the left) and the panel doesn't span the full frame (the panel
is just part of the whole window). I've tried subtracting the x
from the static text position and other things to try and get the
size but I can't seem to crack it.

The attachment I sent was just a proof of concept, just to give you
some food for thought. You may also get some insight by examining the
source of wx.lib.stattext.

Other than that, I believe you should provide a simple, short,
runnable, self-contained sample application showing your problem and
showing what you have tried up to now. A description of the problem
using words only is way too insufficient for us to help you in a
meaningful way.

http://wiki.wxpython.org/MakingSampleApps

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

···

On 29 November 2011 13:25, Paul wrote:

You have to either clear the background before repainting the text, or draw some sort of background as part of your paint. The chunky black mess comes from drawing the text with anti-aliasing. When the text is drawn the first time some pixels are set to some shade of grey (and blended in to the background) rather than full black. When the text is draw subsequent times the blended pixels are blended with grey again, making them a little darker each time. If the actual text being drawn changes then the problem is even worse. The only way to have a transparent background without running into problems like this is to not have a transparent background, but rather to draw what you want the background to be (such as the same color as the parent window) as the background of the text widget.

···

On 11/29/11 4:25 AM, Paul wrote:

I need to have a transparent background on the statictext, if I set
backBrush to wx.TRANSPARENT the text old text isn't drawn over
and I soon end up with a chunky black rectangle as the texts
stack up. Any idea how to prevent this?

--
Robin Dunn
Software Craftsman

Andrea Gavana <andrea.gavana <at> gmail.com> writes:

Hi,

> I need to have a transparent background on the statictext, if I set
> backBrush to wx.TRANSPARENT the text old text isn't drawn over
> and I soon end up with a chunky black rectangle as the texts
> stack up. Any idea how to prevent this?
>
> Also using the example in my app isn't working exactly, the get
> client area I presume gets a bigger size than it has available, the
> text doesn't span the full width of the panel (there's something
> to the left) and the panel doesn't span the full frame (the panel
> is just part of the whole window). I've tried subtracting the x
> from the static text position and other things to try and get the
> size but I can't seem to crack it.

The attachment I sent was just a proof of concept, just to give you
some food for thought. You may also get some insight by examining the
source of wx.lib.stattext.

Other than that, I believe you should provide a simple, short,
runnable, self-contained sample application showing your problem and
showing what you have tried up to now. A description of the problem
using words only is way too insufficient for us to help you in a
meaningful way.

MakingSampleApps - wxPyWiki

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

I have included some code bellow showing roughly how the frame is layed out. I
think the problem is that the text is keeping the size of the panel, so it
doesn't think it needs to ellipsize?

import wx
import wx.lib.mixins.inspection
from wx.lib.stattext import GenStaticText as StaticText

if wx.Platform == "__WXMAC__":
    from Carbon.Appearance import kThemeBrushDialogBackgroundActive

class MainPanel(wx.Panel):
    
    def __init__(self,parent,id):
        wx.Panel.__init__(self,parent,id)
        
        sizer= wx.BoxSizer(wx.VERTICAL)
        some_text=wx.StaticText(self,-1,"some text",style=wx.ALIGN_CENTER)
        sizer.Add(some_text,0,wx.ALIGN_CENTER|wx.EXPAND|wx.ALL,5)
        middle_sizer= wx.BoxSizer(wx.HORIZONTAL)
        panel= wx.Panel(self,-1)
        box=wx.StaticBox(panel,-1)
        box_sizer= wx.StaticBoxSizer(box,wx.VERTICAL)
        panel_sizer= wx.GridBagSizer(0,0)
        icon = wx.StaticBitmap(
            panel, -1, wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE,
                                               size=(38, 38)))
        panel_sizer.Add(icon,(0,0),(2,1),wx.ALL,5)
        #file_sizer= wx.BoxSizer(wx.VERTICAL)
        elliptic_text= EllipticStaticText(panel,-
1,"/home/user/Some/folder/and_some_more_folders/another_folder/some_file.file")
        panel_sizer.Add(elliptic_text,(0,1),(1,1),wx.ALL,5)
        gauge= wx.Gauge(panel,-1,100)
        gauge.SetValue(60)
        #file_sizer.Add(gauge,-1,wx.EXPAND)
        panel_sizer.Add(gauge,(1,1),(1,1),wx.EXPAND)
        #panel_sizer.Add(file_sizer,0,wx.EXPAND)
        panel_sizer.AddGrowableCol(1)
        box_sizer.Add(panel_sizer,0,wx.EXPAND|wx.ALL,5)
        panel.SetSizer(box_sizer)
        middle_sizer.Add(panel,5,wx.ALL|wx.EXPAND,5)
        some_text= wx.StaticText(self,-
1,"Some\nmore\ntext",style=wx.ALIGN_CENTER)
        middle_sizer.Add(some_text,1,wx.ALIGN_CENTER|wx.ALL|wx.EXPAND,5)
        sizer.Add(middle_sizer,0,wx.EXPAND)
        some_text= wx.StaticText(self,-1,"text")
        sizer.Add(some_text,0,wx.ALL,5)
        
        self.SetSizer(sizer)
        self.Layout()
        self.Centre()
        self.Fit()
        #add panel

class EllipticStaticText(StaticText):

    def __init__(self, parent, id=wx.ID_ANY, label='', pos=wx.DefaultPosition,
size=wx.DefaultSize,
                 style=0, name="ellipticstatictext"):
        """
        Default class constructor.

        :param `parent`: the L{EllipticStaticText} parent. Must not be ``None``;
        :param `id`: window identifier. A value of -1 indicates a default value;
        :param `label`: the text label;
        :param `pos`: the control position. A value of (-1, -1) indicates a
default position,
         chosen by either the windowing system or wxPython, depending on
platform;
        :param `size`: the control size. A value of (-1, -1) indicates a default
size,
         chosen by either the windowing system or wxPython, depending on
platform;
        :param `style`: the static text style;
        :param `name`: the window name.
        """

        StaticText.__init__(self, parent, id, label, pos, size, style, name)

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

    def OnSize(self, event):
        """
        Handles the ``wx.EVT_SIZE`` event for L{EllipticStaticText}.

        :param `event`: a `wx.SizeEvent` event to be processed.
        """

        event.Skip()
        self.Refresh()

    def OnEraseBackground(self, event):
        """
        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{EllipticStaticText}.

        :param `event`: a `wx.EraseEvent` event to be processed.

        :note: This is intentionally empty to reduce flicker.
        """

        pass

    def OnPaint(self, event):
        """
        Handles the ``wx.EVT_PAINT`` event for L{EllipticStaticText}.

        :param `event`: a `wx.PaintEvent` to be processed.
        """

        dc = wx.BufferedPaintDC(self)
        width, height = self.GetClientSize()

        if not width or not height:
            return

        clr = self.GetBackgroundColour()

        if wx.Platform == "__WXMAC__":
            # if colour is still the default then use the theme's background on
Mac
            themeColour = wx.MacThemeColour(kThemeBrushDialogBackgroundActive)
            backBrush = wx.Brush(themeColour)
        else:
            backBrush = wx.Brush(clr, wx.SOLID)

        dc.SetBackground(backBrush)
        dc.Clear()

        if self.IsEnabled():
            dc.SetTextForeground(self.GetForegroundColour())
        else:
            
dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))

        dc.SetFont(self.GetFont())

        label = self.GetLabel()
        text = self.ChopText(dc, label, width)

        dc.DrawText(text, 0, 0)

    def ChopText(self, dc, text, max_size):
        """
        Chops the input `text` if its size does not fit in `max_size`, by
cutting the
        text and adding ellipsis at the end.

        :param `dc`: a `wx.DC` device context;
        :param `text`: the text to chop;
        :param `max_size`: the maximum size in which the text should fit.
        """

        # first check if the text fits with no problems
        x, y = dc.GetTextExtent(text)

        if x <= max_size:
            return text

        textLen = len(text)
        last_good_length = 0

        for i in xrange(textLen, -1, -1):
            s = text[0:i]
            s += "..."

            x, y = dc.GetTextExtent(s)
            last_good_length = i

            if x < max_size:
                break

        ret = text[0:last_good_length] + "..."
        return ret
    
class MainApp(wx.App,wx.lib.mixins.inspection.InspectionMixin):
    def OnInit(self):
        self.Init()
        return True

def Example():

    app = MainApp(False)
    frame = wx.Frame(None, -1, "EllipticStaticText example ;-)", size=(400,
300))

    panel = MainPanel(frame,-1)
    #sizer = wx.BoxSizer(wx.VERTICAL)

    #elliptic = EllipticStaticText(panel, -1,
r"F:\myreservoir\re\util\python\hm_evaluation\data\HM_Evaluation_0.9.9.7.exe")
    #whitePanel = wx.Panel(panel, -1)
    #whitePanel.SetBackgroundColour(wx.WHITE)

    #sizer.Add(elliptic, 0, wx.ALL|wx.EXPAND, 10)
    #sizer.Add(whitePanel, 1, wx.ALL|wx.EXPAND, 10)

    #panel.SetSizer(sizer)
    #sizer.Layout()

    frame.CenterOnScreen()
    frame.Show()

    app.MainLoop()

if __name__ == "__main__":

    Example()

···

On 29 November 2011 13:25, Paul wrote:

Andrea Gavana <andrea.gavana <at> gmail.com> writes:

Hi,

> I need to have a transparent background on the statictext, if I set
> backBrush to wx.TRANSPARENT the text old text isn't drawn over
> and I soon end up with a chunky black rectangle as the texts
> stack up. Any idea how to prevent this?
>
> Also using the example in my app isn't working exactly, the get
> client area I presume gets a bigger size than it has available, the
> text doesn't span the full width of the panel (there's something
> to the left) and the panel doesn't span the full frame (the panel
> is just part of the whole window). I've tried subtracting the x
> from the static text position and other things to try and get the
> size but I can't seem to crack it.

The attachment I sent was just a proof of concept, just to give you
some food for thought. You may also get some insight by examining the
source of wx.lib.stattext.

Other than that, I believe you should provide a simple, short,
runnable, self-contained sample application showing your problem and
showing what you have tried up to now. A description of the problem
using words only is way too insufficient for us to help you in a
meaningful way.

MakingSampleApps - wxPyWiki

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

My last post doesn't seem to be appearing. I hope it doesn't appear twice now!

I've attached my code below. I think the problem may be that the file path text
is what's keeping the panel at that size, so the ellipsize doesn't think it
needs to be smaller, what i need to define the size of the panel is the space
available in the panels sizer

import wx
import wx.lib.mixins.inspection
from wx.lib.stattext import GenStaticText as StaticText

if wx.Platform == "__WXMAC__":
    from Carbon.Appearance import kThemeBrushDialogBackgroundActive

class MainPanel(wx.Panel):
    
    def __init__(self,parent,id):
        wx.Panel.__init__(self,parent,id)
        
        sizer= wx.BoxSizer(wx.VERTICAL)
        some_text=wx.StaticText(self,-1,"some text",style=wx.ALIGN_CENTER)
        sizer.Add(some_text,0,wx.ALIGN_CENTER|wx.EXPAND|wx.ALL,5)
        middle_sizer= wx.BoxSizer(wx.HORIZONTAL)
        panel= wx.Panel(self,-1)
        box=wx.StaticBox(panel,-1)
        box_sizer= wx.StaticBoxSizer(box,wx.VERTICAL)
        panel_sizer= wx.GridBagSizer(0,0)
        icon = wx.StaticBitmap(
            panel, -1, wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE,
                                               size=(38, 38)))
        panel_sizer.Add(icon,(0,0),(2,1),wx.ALL,5)
        #file_sizer= wx.BoxSizer(wx.VERTICAL)
        elliptic_text= EllipticStaticText(panel,-
1,"/home/user/Some/folder/and_some_more_folders/another_folder/some_file.file")
        panel_sizer.Add(elliptic_text,(0,1),(1,1),wx.ALL,5)
        gauge= wx.Gauge(panel,-1,100)
        gauge.SetValue(60)
        #file_sizer.Add(gauge,-1,wx.EXPAND)
        panel_sizer.Add(gauge,(1,1),(1,1),wx.EXPAND)
        #panel_sizer.Add(file_sizer,0,wx.EXPAND)
        panel_sizer.AddGrowableCol(1)
        box_sizer.Add(panel_sizer,0,wx.EXPAND|wx.ALL,5)
        panel.SetSizer(box_sizer)
        middle_sizer.Add(panel,5,wx.ALL|wx.EXPAND,5)
        some_text= wx.StaticText(self,-
1,"Some\nmore\ntext",style=wx.ALIGN_CENTER)
        middle_sizer.Add(some_text,1,wx.ALIGN_CENTER|wx.ALL|wx.EXPAND,5)
        sizer.Add(middle_sizer,0,wx.EXPAND)
        some_text= wx.StaticText(self,-1,"text")
        sizer.Add(some_text,0,wx.ALL,5)
        
        self.SetSizer(sizer)
        self.Layout()
        self.Centre()
        self.Fit()
        #add panel

class EllipticStaticText(StaticText):

    def __init__(self, parent, id=wx.ID_ANY, label='', pos=wx.DefaultPosition,
size=wx.DefaultSize,
                 style=0, name="ellipticstatictext"):
        """
        Default class constructor.

        :param `parent`: the L{EllipticStaticText} parent. Must not be ``None``;
        :param `id`: window identifier. A value of -1 indicates a default value;
        :param `label`: the text label;
        :param `pos`: the control position. A value of (-1, -1) indicates a
default position,
         chosen by either the windowing system or wxPython, depending on
platform;
        :param `size`: the control size. A value of (-1, -1) indicates a default
size,
         chosen by either the windowing system or wxPython, depending on
platform;
        :param `style`: the static text style;
        :param `name`: the window name.
        """

        StaticText.__init__(self, parent, id, label, pos, size, style, name)

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

    def OnSize(self, event):
        """
        Handles the ``wx.EVT_SIZE`` event for L{EllipticStaticText}.

        :param `event`: a `wx.SizeEvent` event to be processed.
        """

        event.Skip()
        self.Refresh()

    def OnEraseBackground(self, event):
        """
        Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{EllipticStaticText}.

        :param `event`: a `wx.EraseEvent` event to be processed.

        :note: This is intentionally empty to reduce flicker.
        """

        pass

    def OnPaint(self, event):
        """
        Handles the ``wx.EVT_PAINT`` event for L{EllipticStaticText}.

        :param `event`: a `wx.PaintEvent` to be processed.
        """

        dc = wx.BufferedPaintDC(self)
        width, height = self.GetClientSize()

        if not width or not height:
            return

        clr = self.GetBackgroundColour()

        if wx.Platform == "__WXMAC__":
            # if colour is still the default then use the theme's background on
Mac
            themeColour = wx.MacThemeColour(kThemeBrushDialogBackgroundActive)
            backBrush = wx.Brush(themeColour)
        else:
            backBrush = wx.Brush(clr, wx.SOLID)

        dc.SetBackground(backBrush)
        dc.Clear()

        if self.IsEnabled():
            dc.SetTextForeground(self.GetForegroundColour())
        else:
            
dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))

        dc.SetFont(self.GetFont())

        label = self.GetLabel()
        text = self.ChopText(dc, label, width)

        dc.DrawText(text, 0, 0)

    def ChopText(self, dc, text, max_size):
        """
        Chops the input `text` if its size does not fit in `max_size`, by
cutting the
        text and adding ellipsis at the end.

        :param `dc`: a `wx.DC` device context;
        :param `text`: the text to chop;
        :param `max_size`: the maximum size in which the text should fit.
        """

        # first check if the text fits with no problems
        x, y = dc.GetTextExtent(text)

        if x <= max_size:
            return text

        textLen = len(text)
        last_good_length = 0

        for i in xrange(textLen, -1, -1):
            s = text[0:i]
            s += "..."

            x, y = dc.GetTextExtent(s)
            last_good_length = i

            if x < max_size:
                break

        ret = text[0:last_good_length] + "..."
        return ret
    
class MainApp(wx.App,wx.lib.mixins.inspection.InspectionMixin):
    def OnInit(self):
        self.Init()
        return True

def Example():

    app = MainApp(False)
    frame = wx.Frame(None, -1, "EllipticStaticText example ;-)", size=(400,
300))

    panel = MainPanel(frame,-1)
    #sizer = wx.BoxSizer(wx.VERTICAL)

    #elliptic = EllipticStaticText(panel, -1,
r"F:\myreservoir\re\util\python\hm_evaluation\data\HM_Evaluation_0.9.9.7.exe")
    #whitePanel = wx.Panel(panel, -1)
    #whitePanel.SetBackgroundColour(wx.WHITE)

    #sizer.Add(elliptic, 0, wx.ALL|wx.EXPAND, 10)
    #sizer.Add(whitePanel, 1, wx.ALL|wx.EXPAND, 10)

    #panel.SetSizer(sizer)
    #sizer.Layout()

    frame.CenterOnScreen()
    frame.Show()

    app.MainLoop()

if __name__ == "__main__":

    Example()

···

On 29 November 2011 13:25, Paul wrote:

No, I think it is just clipping the custom widget at the edge of the parent panel because the best size is still being calculated as the width needed for the whole thing. You should probably either ellipsize the widget's main label attribute so it will use that text for calculating the needed width, or you should override DoGetBestSize and calculate the needed width your own way.

···

On 11/30/11 4:32 AM, Paul wrote:

Andrea Gavana<andrea.gavana<at> gmail.com> writes:

Hi,

On 29 November 2011 13:25, Paul wrote:

I need to have a transparent background on the statictext, if I set
backBrush to wx.TRANSPARENT the text old text isn't drawn over
and I soon end up with a chunky black rectangle as the texts
stack up. Any idea how to prevent this?

Also using the example in my app isn't working exactly, the get
client area I presume gets a bigger size than it has available, the
text doesn't span the full width of the panel (there's something
to the left) and the panel doesn't span the full frame (the panel
is just part of the whole window). I've tried subtracting the x
from the static text position and other things to try and get the
size but I can't seem to crack it.

The attachment I sent was just a proof of concept, just to give you
some food for thought. You may also get some insight by examining the
source of wx.lib.stattext.

Other than that, I believe you should provide a simple, short,
runnable, self-contained sample application showing your problem and
showing what you have tried up to now. A description of the problem
using words only is way too insufficient for us to help you in a
meaningful way.

MakingSampleApps - wxPyWiki

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

I have included some code bellow showing roughly how the frame is layed out. I
think the problem is that the text is keeping the size of the panel, so it
doesn't think it needs to ellipsize?

--
Robin Dunn
Software Craftsman