1. sachidhanantham ramalingam
  2. PowerBuilder
  3. Wednesday, 21 October 2020 07:13 AM UTC

Hi,

 I am using Power Builder 2017 R3 Build 1880, am using Label Data window, in that have added a Compute column,
If i try to show the string value (i.e.Aluminiumhydroxide-Magnesiumhydroxide-Calciumcarbonate-Sodiumbicarbonate-Alginicacid [Note: there is no SPACE in between the string value]) on that compute coulmn then label get displayed with truncated string in starting and ending point also displayed in a single line shown as below

When i give space in between the string value (i.e. Aluminiumhydroxide-Magnesiumhydroxide Calciumcarbonate Sodiumbicarbonate-Alginicacid) then showing properly as below

Kindly provide your suggestion to solve this problem.

Thanks,
--Sachi...

sachidhanantham ramalingam Accepted Answer Pending Moderation
  1. Thursday, 10 December 2020 12:45 PM UTC
  2. PowerBuilder
  3. # 1

Hi John,

Thanks for your inputs, we will check and update you.

--Sachi...

Comment
  1. John Fauss
  2. Wednesday, 6 January 2021 19:59 PM UTC
I recently posted in CodeXchange a sample application called "String Break" that addresses this issue. There is a non-visual object (n_stringbreak) that analyzes the contents of a string in relation to the properties of either a static text control, text DataWindow Object (DWO) or computed field DWO such as width, height, typeface, point size, etc. and simulates a line break by inserting a space into the string at the optimal place(s). You can designate what additional characters can cause a line break (such as the hyphen in your example), and whether you want the line breaks to occur before or after the characters. It will also optionally end the displayed data with an ellipsis. The sample application helps you set up all of the properties to be tested step-by-step so you can experiment with ease.



A very interesting problem with a lot of factors to take into account. Perhaps you or someone else will find it useful.



Regards, John
  1. Helpful
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Friday, 6 November 2020 02:23 AM UTC
  2. PowerBuilder
  3. # 2

Sachi -

I've been experimenting with possible ways to accomplish what you're wanting to do and I've had some success. I was hoping to be able to develop a global function that could be called from a DataWindow expression in a computed field, but in order to be able to call the critical GetTextExtentPoint32W WinAPI function, the code has to be able to have a reference to either a StaticText window control (a Text DataWindow Object won't do because these are not Windows controls) or a reference to an open window, and I don't think I can make it work from a DataWindow expression that way.

That's a round-about way of saying that there are compromises.

Some kind of a post-retrieve loop through all of the rows in a DataWindow would be required, performing a GetItemString on a column that contains the string to be analyzed, invoking a function in a non-visual object to analyze the input string while taking the size and font properties of the computed field into account and inserting a space, if needed, then finally replacing the string in the column via SetItem.

There's a small sample app I've written to test the functionality and it shows how it can work, using the example data in the screen shots you posted, for example, or other test data. It's not yet complete, but I'm very close.

Given these limitations, would this functionality be useful to you?

Regards, John

Comment
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Thursday, 22 October 2020 16:23 PM UTC
  2. PowerBuilder
  3. # 3

Here's a function (from the PowerBuilder Foundation Class) that will the width & height (in pixels) of a string when rendered by Windows.

You need a Windows "size" structure. Here's exported PB source code showing an example:

type os_size from structure
   long l_cx
   long l_cy
end type

Here are the external function declarations for four WinAPI functions the of_GetTextSize function will call:

Function Boolean GetTextExtentPoint32W ( &
   ULong hdcr, String lpString, Long nCount, &
   ref os_size size ) Library "GDI32.DLL"
Function ULong SelectObject ( &
   ULong hdc, ULong hWnd ) Library "GDI32.DLL"
Function ULong GetDC ( &
   ULong hWnd ) Library "USER32.DLL"
Function Integer ReleaseDC ( &
   ULong hWnd, ULong hDC ) Library "USER32.DLL"

Here's the of_GetTextSize function:

//////////////////////////////////////////////////////////////////////////////
// Public Function: of_GetTextSize
//
// Arguments:
//   Window  aw_obj (by reference)    Window where temporary text will be created
//   String  as_Text                  The text to be sized.
//   String  as_FontFace              The font used.
//   Integer ai_FontSize              The point size of the font.
//   Boolean ab_Bold                  True - Bold, False - Normal.
//   Boolean ab_Italic                True - Yes, False - No.
//   Boolean ab_Underline             True - Yes, False - No.
//   Integer ai_Height (by reference) The height of the object in pixels
//   Integer ai_Width (by reference)  The width of the object in pixels
//
// Returns: Integer                   1 if successful, -1 if an error occurrs
//
// Description:
//   Calculates the size of a text object in pixels
//////////////////////////////////////////////////////////////////////////////
// Rev. History  Version
//               5.0    Initial version
//               5.0.03 Changed Uint variables to Ulong for NT4.0 compatibility
//               8.0    Not deleting statictext object under certain conditions.
//////////////////////////////////////////////////////////////////////////////
/*
 * Open Source PowerBuilder Foundation Class Libraries
 *
 * Copyright (c) 2004-2017, All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted in accordance with the MIT License
 *
 * https://opensource.org/licenses/MIT
 *
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals and was originally based on software copyright (c) 
 * 1996-2004 Sybase, Inc. http://www.sybase.com.  For more
 * information on the Open Source PowerBuilder Foundation Class
 * Libraries see https://github.com/OpenSourcePFCLibraries
*/
//////////////////////////////////////////////////////////////////////////////
Integer li_Size, li_Len, li_Return, &
        li_WM_GETFONT = 49   //  hex 0x0031
ULong   lul_Hdc, lul_Handle, lul_hFont
StaticText lst_Temp
os_size lstr_Size

// Datawindow syntax specifies font point size is negative
li_Size = -1 * ai_FontSize

if IsNull(aw_obj) Or Not IsValid (aw_obj) then
   return -1
end if

// Create a dummy StaticText Object on the window
// containing text with the desired characteristics
li_Return = aw_obj.OpenUserObject(lst_Temp)
If li_Return = 1 Then
   lst_Temp.FaceName = as_FontFace
   lst_Temp.TextSize = li_Size
   If ab_Bold Then
      lst_Temp.Weight = 700
   Else
      lst_Temp.Weight = 400
   End If
   lst_Temp.Italic = ab_Italic
   lst_Temp.Underline = ab_Underline

   li_Len = Len(as_Text)

   // Get the handle of the StaticText Object and create a Device Context
   lul_Handle = Handle(lst_Temp)
   lul_Hdc = GetDC(lul_Handle)

   // Get the font in use on the Static Text
   lul_hFont = Send(lul_Handle, li_WM_GETFONT, 0, 0)

   // Select it into the device context
   SelectObject(lul_Hdc, lul_hFont)

   // Get the size of the text.
   If Not GetTextExtentpoint32W(lul_Hdc, as_Text, li_Len, lstr_Size ) Then 
      aw_obj.CloseUserObject(lst_Temp)
      Return -1
   End If

   ai_Height = lstr_Size.l_cy
   ai_Width = lstr_Size.l_cx

   ReleaseDC(lul_Handle, lul_Hdc)

   li_Return = aw_obj.CloseUserObject(lst_Temp)
End if

Return li_Return

That should get you started, if you want.

Comment
  1. John Fauss
  2. Tuesday, 27 October 2020 02:11 AM UTC
So what is the solution? Given the constraints, I think the only reasonable answer is for Sachi to develop a parsing algorithm specifically for the problem he wants to address. I've toyed with a variation of the of_GetTextSize function where you give it the width of the available space, all of the font characteristics and the text string and it returns the number of leading characters of the text that will fit in that amount of space. That part is doable. If you're concerned about spacing disparities between screen and printer fonts {which I agree can exist), then you could specify a slightly narrower available width. Another possible approach that might help would be to reduce the font size (within reason, of course) with longer strings.
  1. Helpful
  1. Andrew Barnes
  2. Friday, 30 October 2020 23:46 PM UTC
You may be right. I have a font metrics object, not easily extracted from my libraries into anything standalone that handles printer fonts as easily as screen ones. Basically the difference is specifying the printer name and "WINSPOOL" in the CreateDC command instead of "DISPLAY" and NULL. The idea is that you get a DC with CreateDC(), get a font with CreateFont(), select the font, then get the character width data using GetCharABCWidthsFloat() which is then saved in the object for calculating any string width or iterating through a string to calculate the line breaks. Of course, while the DC is still alive, the GetTextExtentPoint32 can be used as well.
  1. Helpful
  1. Andrew Barnes
  2. Friday, 30 October 2020 23:57 PM UTC
The other gotcha, I see with the PFC of_GetTextSize() function, is just that when specifying the font's point size, you need to specify it as a positive value. So if you use the function with a font size that has been dynamically read from the DataWindow's computed field, you need to either multiply by -1 or the Abs() function to make the font size a positive number.
  1. Helpful
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Thursday, 22 October 2020 14:30 PM UTC
  2. PowerBuilder
  3. # 4

Hi, Sachi -

By your own admission "...we can't predict that what will be there in between...", so what action do you believe Appeon should take to "resolve the problem" when they also have absolutely no idea what your data contains? Please consider asking for advice on creating your own solution instead of asking for a turnkey solution. Chris has already offered you some.

Here's another suggestion for you to consider: There exists a WinAPI function named GetTextExtentPoint32W that can be used from PowerBuilder to determine the rendered width and height, in pixels, of a text string based on the font typeface, point size and other font attributes (weight/boldness, italics, underlining, etc.) and you can use this to determine the maximum amount of text that can fit into the available space (based on content) you have before a space would need to be inserted to produce a line break. Then scan the text backwards from that point for an acceptable "line-breakable" character (you determine what chars are acceptable) and insert a space in front of it. If no preceding "breakable" characters exist, then insert the space regardless. Is this a super-trivial thing to accomplish? No, but it's not rocket science, either. It's doable.

Don't know how to call this API function? The Integrated STD framework that Chris publishes probably uses this API function in some fashion. I have verified there is at least one free code sample on Roland Smith's TopWizProgramming web site that uses it (the web page for each free code sample program lists the API functions used in that sample application), so there are examples available to you to learn from. Never coded/called a Windows API function from PowerBuilder? Look in the Tutorials section of the Appeon Community.

Regards, John

Comment
There are no comments made yet.
Chris Pollach @Appeon Accepted Answer Pending Moderation
  1. Wednesday, 21 October 2020 13:37 PM UTC
  2. PowerBuilder
  3. # 5

Hi Sachi;

   You can use a Global Function as the source of any DWO's computed column. So if it was me, I would use the GF and pass in the long name string to the GF. The GF in turn would parse the long name and if no spaces found, would then locate the last hyphen (-) and then add the extra space right after the hyphen and return the adjusted name to the caller.

Food for thought.

Regards ... Chris

Comment
  1. Miguel Leeuwe
  2. Thursday, 7 January 2021 03:53 AM UTC
"hyphen is not the only character" ... so the line break might have to occur on any character that's not between [a-z][A-Z] ? That's should be not too difficult.

Also, maybe if you use a monospaced font like Courier, you could determine the maximum length that fits on the line a little bit easier.

Just my 2cts,

regards.
  1. Helpful
  1. John Fauss
  2. Thursday, 7 January 2021 14:11 PM UTC
FYI - The "String Break" sample application and NVO now posted on CodeXchange (see my recent response to this post) does support, as you suggest, MIguel, the recognition of multiple characters (that the developer specifies) and also whether the simulated line break is to occur before or after the break character(s). It works with all fonts, proportional and monospaced.
  1. Helpful
  1. Miguel Leeuwe
  2. Thursday, 7 January 2021 16:12 PM UTC
John your work and help on this forum is awesome!
  1. Helpful
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.