calc nr of visible characters in wx.TextCtrl

Hello list,

I would like to find a good estimate of the amount
of characters that are visible in a wx.TextCtrl.
The size of the wx.TextCtrl is changed dynamically (wx.EXPAND)

For now I use:

    def calcNrOfVisibleCharacters(self):

        cs = self.textcontrol1.GetClientSize()[0]
        te = self.textcontrol1.GetFullTextExtent('X')
        
        return cs/(te[0]+te[3])

But this seems to be a really bad estimation. (I am not sure why though).

(I hit "Send" by accident the first time)

Hello list,

I would like to find a good estimate of the amount
of characters that are visible in a wx.TextCtrl.
The size of the wx.TextCtrl is changed dynamically (wx.EXPAND)

For now I use:

     def calcNrOfVisibleCharacters(self):
         # get widget's size
         cs = self.textcontrol1.GetClientSize()[0]
         # get size of characters and inter character spacing
         te = self.textcontrol1.GetFullTextExtent('X') # returns
(width,height,descent,leading)
         return max(cs/(te[0]+te[3])-3, 3) # minus 3 is found by trial and error

But this seems a weird calculation.
The textcontrol (a wx.TextCtrl) uses a wx.MODERN (monospace) font.

The questions:
* Do GetClientSize() and GetFullTextExtent() return values in the same units?
(i.e. pixels).
* Are there other ways to find out the amount of visible characters?

Best regards,
Stefaan.

The best-guess solution I can think up based on the functions listed
in the docs is: get the current screen coordinates of the control with
GetRect (a Window function), then offset the corners by a few pixels
to what should be over the upper left and lower right visible
characters, and then use HitTest to determine what characters are
under those points.

Which is kinda nasty round-the-block way of doing things that dosn't
even work on all platforms. You'd THINK TextCtrl would have some kind
of Get(First|Last)Visible(Position|Line) functions, eh?

···

On 8/14/06, stefaan <stefaan.himpe@gmail.com> wrote:

Hello list,

I would like to find a good estimate of the amount
of characters that are visible in a wx.TextCtrl.
The size of the wx.TextCtrl is changed dynamically (wx.EXPAND)

For now I use:

    def calcNrOfVisibleCharacters(self):

        cs = self.textcontrol1.GetClientSize()[0]
        te = self.textcontrol1.GetFullTextExtent('X')

        return cs/(te[0]+te[3])

But this seems to be a really bad estimation. (I am not sure why though).

stefaan пишет:
       def calcNrOfVisibleCharacters(self):
           # get widget's size
           cs = float(self.textcontrol1.GetClientSize()[0])
           # ^^
           # get size of characters and inter character spacing
           te = float(self.textcontrol1.GetFullTextExtent('X')) # returns (width,height,descent,leading)
           # ^^
           return max(cs/(te[0]+te[3])-3.0, 3.0) # minus 3 is found by trial and error

Hello Dmitriy,

Dmitriy Baranov <dmitriy <at> summatech.ru> writes:
          cs = float(self.textcontrol1.GetClientSize()[0])
           # ^^
           # get size of characters and inter character spacing
           te = float(self.textcontrol1.GetFullTextExtent('X'))
           # ^^

Thank you for answering, but that doesn't seem to solve the problem,
especially since the values returned are ints, and I am not interested
in displaying half characters.

This is my analysis for now:

When resizing the control to become smaller,
I see that the calculated #visible characters is too large,
and when resizing the control to become bigger,
the calculated #visible characters is too small
(causing wrapping and vertical scrollbars to appear).

I am doing this calculation in an wx.EVT_SIZE handler
to adjust the number of characters being displayed.
While quickly resizing the control using the mouse,
when asking GetClientSize() I assume you get some instantaneous value.
The actual value when finishing resizing probably can still
change a bit after you asked GetClientSize(), and it will not
necessarily lead to a new wx.EVT_SIZE event.

Therefore, the result of such a calculation in an wx.EVT_SIZE
event handler is unreliable. To make things worse, when
resizing quickly, sometimes vertical scrollbars will appear
because of the text that was already inside the control.
This then leads to a "jump" in the result of GetClientSize
(which seems to answer the length of the text control minus the scroll bars).
This in turn leads to an even worse result.

The minus 3 provides some safety to this "non-determinism".
Unfortunately it is still not fully reliable.

stefaan wrote:

(I hit "Send" by accident the first time)

Hello list,

I would like to find a good estimate of the amount
of characters that are visible in a wx.TextCtrl.
The size of the wx.TextCtrl is changed dynamically (wx.EXPAND)
For now I use:
      def calcNrOfVisibleCharacters(self):
         # get widget's size
         cs = self.textcontrol1.GetClientSize()[0]
         # get size of characters and inter character spacing
         te = self.textcontrol1.GetFullTextExtent('X') # returns
(width,height,descent,leading)
         return max(cs/(te[0]+te[3])-3, 3) # minus 3 is found by trial and error

The descent is the space below the base line that descenders may occupy (like the tail on a 'y' or a 'g') so it doesn't have anything to do with the width. Also the amount of extra space that the control has outside of the bounds of the text will vary between platforms, and possibly even between themes on the same platform, so this will never be a very exact estimation.

But this seems a weird calculation.
The textcontrol (a wx.TextCtrl) uses a wx.MODERN (monospace) font.

wx.MODERN is not required to be monospace, so you may want to use wx.TELETYPE instead.

The questions:
* Do GetClientSize() and GetFullTextExtent() return values in the same units?
(i.e. pixels).

Yes.

* Are there other ways to find out the amount of visible characters?

Not with wx.TextCtrl.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!