width

8 views
Skip to first unread message

pablo digonzelli

unread,
Mar 11, 2001, 6:30:41 PM3/11/01
to
Hello all !!!.
I have a View , really StaticText view. I am displaying a text on it.
I want to set the width of the view in function of the text i'm displaying
in.
i use width: (text size * font pontSize) method on the view.
but, the view don't adjust exactly to the text.
it is a little wider .

My question is: How can i adjust more exactly the size of the view.

TIA
Pablo


Andy Bower

unread,
Mar 12, 2001, 7:21:52 AM3/12/01
to
Pablo,

The reason why your original attempt at resizing the view does not work
correctly is becase #pointSize returns the *height* of the characters and
not the width. The difficulty is that most fonts are "proportional", that is
their characters are different widths (e.g. an M is bigger than an i). In
order to find the width of a particular string you will have to ask for the
text size of the whole string, as calculated by a Canvas using #textExtent:.
Here's an example:

"Build a shell with a text field in it"
shell := ShellView new create.
textEdit := shell addSubView: TextEdit new.
shell show.

"Now set the text edit contents"
textEdit value: 'Hello, this is a line of text'.

"Compute the size of the text string (note this is a Point)"
size := textEdit canvas textExtent: textEdit value. "Display it"

"Set the width of the text view to the width of the string"
textEdit width: size x.

Best Regards,

Andy Bower
Dolphin Support
http://www.object-arts.com

---
Visit the Dolphin Smalltalk WikiWeb
http://www.object-arts.com/wiki/html/Dolphin/FrontPage.htm
---


pablo digonzelli

unread,
Mar 12, 2001, 10:37:34 AM3/12/01
to
Thanks a lot Andy !!!
Pablo
"Andy Bower" <bo...@object-arts.com> wrote in message
news:98if7j$20l62$1...@ID-51044.news.dfncis.de...

Chris Uppal

unread,
Mar 14, 2001, 9:40:11 AM3/14/01
to
Andy,

> shell := ShellView new create.
> textEdit := shell addSubView: TextEdit new.
> shell show.

> textEdit value: 'Hello, this is a line of text'.

> size := textEdit canvas textExtent: textEdit value. "Display it"

> textEdit width: size x.

I've just tried this on my machine here, and it results in the TextEdit
being about 25% wider than it needs to be.

It doesn't actually matter to me (since I don't use this technique) but
it might be indicative of another place where Dolphin/Windows is not
picking up the actual font in use ?

-- chris


pablo digonzelli

unread,
Mar 14, 2001, 11:41:13 AM3/14/01
to
Andy,
I try and found the same as Chris

"Chris Uppal" <chris...@metagnostic.REMOVE-THIS.org> wrote in message
news:98nvkm$jk5$1...@taliesin.netcom.net.uk...

Blair McGlashan

unread,
Mar 14, 2001, 12:35:21 PM3/14/01
to
"pablo digonzelli" <pdig...@sa-sanmiguel.com> wrote in message
news:98o6ks$2sbfp$1...@ID-62316.news.dfncis.de...

> Andy,
> I try and found the same as Chris
>
> "Chris Uppal" <chris...@metagnostic.REMOVE-THIS.org> wrote in message
> news:98nvkm$jk5$1...@taliesin.netcom.net.uk...
> > Andy,
> >
> > > shell := ShellView new create.
> > > textEdit := shell addSubView: TextEdit new.
> > > shell show.
> > > textEdit value: 'Hello, this is a line of text'.
> > > size := textEdit canvas textExtent: textEdit value. "Display it"
> > > textEdit width: size x.

There are two problems with this:
1) View>>canvas doesn't actually set the Font of the supplied Canvas to the
actualFont of the view, so the calculated extent will be for the default
system font.
2) The width needs to be the window width, not the client width, so width of
the text needs to be adjusted (expanded) to allow for the adornment.

shell := ShellView new create.

shell layoutManager: FlowLayout new.

t := shell addSubView: TextEdit new.

t value: 'Hello, this is a line of text'.

size := t canvas font: t actualFont; textExtent: t value.

t extent: (t calcExtentFromClientExtent: size+2).

t2 := shell addSubView: TextEdit new.

t2 value: 'and this another'.

size := t2 canvas font: t2 actualFont; textExtent: t2 value.

t2 extent: (t2 calcExtentFromClientExtent: size+2).

shell show


Why is it necessary to add 2? Not sure, but then I was never very good with
off-by-one errors, so off-by-two errors confuse me totally :-). Actually I
vaguely remember something screwy about the Win32 API AdjustWindowRect
(which underlies View>>calcExtentFromClientExtent:), so maybe its about time
I went back to the API documentation.

Is it a good idea for View>>canvas to answer a canvas that isn't configured
with the font one has specified for the View (or that which it inherits)?
Not sure, its always worked like that but I don't know the reason or whether
it is deliberate or not.

Regards

Blair


pablo digonzelli

unread,
Mar 14, 2001, 1:57:55 PM3/14/01
to
It is working OK

"Blair McGlashan" <bl...@object-arts.com> wrote in message
news:98o9ph$2rsb7$1...@ID-50941.news.dfncis.de...

Blair McGlashan

unread,
Mar 15, 2001, 5:13:05 AM3/15/01
to
Pablo

You wrote in message news:98oeld$2rmu6$1...@ID-62316.news.dfncis.de...
> It is working OK
>

Certainly that is true for small fonts, but I looked into it a bit more (to
see why that extra 2 pixels width was necessary) and this time I first
engaged my brain and thought about what the extent needed to take account
of:

1) EDIT controls seem to implicitly have space for a border. There is an
reference to this in the MFC source code, which has a specialised
implementation of their window rect. calculation method which passes
WS_BORDER to AdjustWindowRectEx. We therefore need to override
TextEdit>>calcRectangleFromClientRectangle:
2) EDIT controls have left and right margins (see MSDN help for
EM_GETMARGINS). The control calculates these from the text metrics of the
font specified for the control, although the precise algorithm is not
specified.
3) The EDIT control allows for the 'external leading' font metric when
calculating the base line.

I looked more closely at the TextEdit class and found the #calculateExtent
method, which appears to be intended to calculate the window extent required
for the current text/font combination. However it doesn't correctly take
account of the Font due to a bug in the way it accesses the font, and it
also ignores the margins and external leading. I've attached a "fixed"
version. If anyone can think of any further subtleties the calculation needs
to account for, please let me know.

If you file in the code below then the #calculateExtent method of TextEdit
will answer what I think is the correct extent for the text currently in the
control, regardless of the Font used.

Note that #calculateExtent is a private method, but if you set the
#usePreferredExtent: aspect of the control to true, then the public method
#layoutExtent will answer the calculated extent. So revising my example
code, and with the patch applied:

shell := ShellView new create.

shell layoutManager: FlowLayout new; height: 200.
2 timesRepeat: [ | t f |


t := shell addSubView: TextEdit new.

f := Font choose.
t usePreferredExtent: true; font: f; value: f displayString.
t extent: t layoutExtent].
shell show

Its a shame that Microsoft don't document more clearly the calculation that
an EDIT control uses to decide the formatting rectangle for text as if they
did then trial and error wouldn't be necessary to discover it. On the other
hand Smalltalk is ideal for trial and error experimentation, and it was fun!

Regards

Blair

------------------------
!TextEdit methodsFor!

calcRectangleFromClientRectangle: aClientRectangle
"Private - Given a client <Rectangle>, answer the required window rectangle
that would be required to achieve this taking into account the current
window
styles etc.
Implementation Note: We must override because of EDIT controls implicit
border."

| rect |
rect := RECT fromRectangle: aClientRectangle.
UserLibrary default
adjustWindowRectEx: rect
dwStyle: self baseStyle | WS_BORDER "implicit border"
bMenu: false
dwExStyle: self extendedStyle.
^rect asRectangle! !
!TextEdit categoriesFor:
#calcRectangleFromClientRectangle:!geometry!private! !

!TextEdit methodsFor!

calculateExtent
"Private - Answer a calculated preferred extent for the receiver."

| canvas extent leading margins |

canvas := self canvas.
canvas font: self actualFont.
extent := canvas textExtent: self plainText.
leading := canvas textMetrics tmExternalLeading.
canvas free.

margins := self margins.
extent := extent + ((self margins first + self margins last)@leading).

"Now adjust required client extent to window extent"
^self calcExtentFromClientExtent: extent
! !
!TextEdit categoriesFor: #calculateExtent!geometry!private! !

Win32Constants at: #EM_GETMARGINS put: 16rD4!

!TextEdit methodsFor!

margins
"Private - Answer the left and right margins."

| dword |
dword := self sendMessage: EM_GETMARGINS.
^Array
with: dword highWord
with: dword lowWord! !
!TextEdit categoriesFor: #margins!constants!private! !


Reply all
Reply to author
Forward
0 new messages