Announcement

Collapse
No announcement yet.

Formatting a print output with commas and decimal points

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Formatting a print output with commas and decimal points

    A beginner's question on how to display an amount on an output file that looks like $ 160,000.65
    from a number 160000.65 and be right adjusted ?

  • #2
    FORMAT$ in Help
    Dale

    Comment


    • #3
      Dale answers the formatting part of the question:

      Originally posted by Mannish Bhandari View Post
      ... and be right adjusted ?
      I presume you mean "right justified"

      1. Use fixed length strings ( either use (W)STRING * x or SPACE$(x) with a dynamic string)
      2. Use RSET or RSET$ (see Help)
      (3. Use a monospaced font to view the output file.)

      Comment


      • #4
        Mannish (oh, poor thing)
        Try this

        Code:
        #COMPILE EXE
        #DIM ALL
        
        #INCLUDE "win32api.inc"
        
        
        
        
        '===================================
        FUNCTION PBMAIN () AS LONG
        
          ' Display the formatted number
           LOCAL  dpStr AS STRING
           LOCAL myNumber AS EXT
           myNumber = 160000.65##
        
           dpStr = RSET$(FORMAT$(myNumber,"$###,###,##0.00"),15)
        
            ?  " Formatted number entry : " +  dpStr
        
        
        END FUNCTION​

        Comment


        • #5
          > dpStr = RSET$(FORMAT$(myNumber,"$###,###,##0.00"),15)
          correction .:
          dpStr = RSET$(FORMAT$(myNumber,"$ ###,###,##0.00"),15)

          (OP has a space between the currency sign and the amount)

          Also note that using "?" in PBWin will use a messagebox to illustrate the concept, that is sub-optimal since it doesn't use a mono-spaced font so will not show the desired alignement.
          '
          Code:
          #COMPILE EXE
          #DIM ALL
          FUNCTION PBMAIN() AS LONG
             LOCAL  dpStr,dpstr2 AS STRING
             LOCAL myNumber AS EXT
             myNumber = 160000.65##
             dpStr = RSET$(FORMAT$(myNumber,"$ ###,###,##0.00"),15)
              myNumber = 1600.65##
             dpStr2 = RSET$(FORMAT$(myNumber,"$ ###,###,##0.00"),15)
              ?  " Formatted number entry : " &   dpStr & $LF & _
                  " Formatted number entry : " &  dpstr2
          END FUNCTION
          '


          Messagebox:

          Click image for larger version

Name:	rjust.jpg
Views:	180
Size:	11.5 KB
ID:	823654


          However, if you copy that message and paste it into a text editor that uses a mono-spaced font, you can see what actually happens"

          Click image for larger version

Name:	rjust2.jpg
Views:	168
Size:	50.1 KB
ID:	823655

          Comment


          • #6
            Hi,
            and is there some elegant way temporary to change font to fixed mono-spaced for every MessageBox API in PBCC program?

            Comment


            • #7
              In PBCC "?" is PRINT (current syntax CON.PRINT). There is no messagebox.

              ((added: He said API MESSAGEBOX))(((while I could have just deleted, the rest is true)))
              ((((more added: an API MESSAGEBOX will behave the same called from PBWin or PBCC))))

              Consoles are (fixed) mono-spaced always (AFAIK).

              TXT.WINDOW is either PBWin or PBCC are also mono-spaced.

              PRINT in TXT.WINDOW is TXT.PRINT, there is no shortcut syntax.

              Cheers,
              Dale

              Comment


              • #8
                Please no misunderstanding, just quote the previous post #5

                Comment


                • #9
                  > temporary to change font to fixed mono-spaced for every MessageBox API

                  Even with PB/Win, nothing simple. The MessageBox API is pretty much a monolith. I suppose you could do it with subclassing or something, but it would probably be easier to design your own dialog that acts like a MessageBox.
                  "Not my circus, not my monkeys."

                  Comment


                  • #10
                    Originally posted by Denis Gura View Post
                    Hi,
                    and is there some elegant way temporary to change font to fixed mono-spaced for every MessageBox API in PBCC program?
                    No.

                    A WIN32 Messagebox does not allow for customised fonts (regardless of what compiler it is used in i.e. not just in PBCC). You would need to create your own Dialog or Window from scratch to emulate a message box or get involved with hooks, intercepting various windows messages etc.

                    Comment


                    • #11
                      I keep these in my "skeleton" file.


                      Code:
                      MACRO fmt_Int(intval) = RSET$(FORMAT$(intval,"* #,"),7)
                      MACRO fmt_Bigint (X) = RSET$(FORMAT$(X,"#,"),14)
                      MACRO fmt_money (curval) = RSET$(FORMAT$(curval, "$#,.00"),12)
                      MACRO fmt_money2 (curval)= RSET$(FORMAT$(curval, "$#,.00 ;$#,.00-"),12) ' gives '0' in dollar position
                      MACRO fmt_money3 (curval)= RSET$(FORMAT$(curval, "$#,.00 ;$#,.00-; "),12) ' gives 'blank when zero'
                      usage 'PRINT fmt_money ([email protected])


                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        Hi guys,

                        Code:
                        GLOBAL hHook AS DWORD, change AS BYTE
                        
                        %HCBT_CREATEWND  = 3
                        %HCBT_DESTROYWND = 4
                        %HCBT_ACTIVATE   = 5
                        %WM_SETFONT      = &H30
                        %WH_CBT          = 5
                        %ANSI_FIXED_FONT = 11
                        
                        TYPE LOGFONT
                         lfHeight         AS LONG
                         lfWidth          AS LONG
                         lfEscapement     AS LONG
                         lfOrientation    AS LONG
                         lfWeight         AS LONG
                         lfItalic         AS BYTE
                         lfUnderline      AS BYTE
                         lfStrikeOut      AS BYTE
                         lfCharSet        AS BYTE
                         lfOutPrecision   AS BYTE
                         lfClipPrecision  AS BYTE
                         lfQuality        AS BYTE
                         lfPitchAndFamily AS BYTE
                         lfFaceName       AS ASCIIZ * 32
                        END TYPE
                        
                        DECLARE FUNCTION GetObject LIB "GDI32.DLL" ALIAS "GetObjectA" (BYVAL hObject AS DWORD, BYVAL nCount AS LONG, lpObject AS ANY) AS LONG
                        DECLARE FUNCTION GetStockObject LIB "GDI32.DLL" ALIAS "GetStockObject" (BYVAL nIndex AS LONG) AS DWORD
                        DECLARE FUNCTION CreateFontIndirect LIB "GDI32.DLL" ALIAS "CreateFontIndirectA" (lpLogFont AS LOGFONT) AS DWORD
                        DECLARE FUNCTION SendMessage LIB "USER32.DLL" ALIAS "SendMessageA" (BYVAL hWnd AS DWORD, BYVAL dwMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
                        DECLARE FUNCTION DeleteObject LIB "GDI32.DLL" ALIAS "DeleteObject" (BYVAL hObject AS DWORD) AS LONG
                        DECLARE FUNCTION UnhookWindowsHookEx LIB "USER32.DLL" ALIAS "UnhookWindowsHookEx" (BYVAL hHook AS DWORD) AS LONG
                        DECLARE FUNCTION CallNextHookEx LIB "USER32.DLL" ALIAS "CallNextHookEx" (BYVAL hHook AS DWORD, BYVAL ncode AS LONG, BYVAL wParam AS DWORD, lParam AS ANY) AS LONG
                        DECLARE FUNCTION SetWindowsHookEx LIB "USER32.DLL" ALIAS "SetWindowsHookExA" (BYVAL idHook AS LONG, BYVAL lpfn AS DWORD, BYVAL hMod AS DWORD, BYVAL dwThreadId AS DWORD) AS LONG
                        DECLARE FUNCTION GetModuleHandle LIB "KERNEL32.DLL" ALIAS "GetModuleHandleA" (lpModuleName AS ASCIIZ) AS DWORD
                        DECLARE FUNCTION GetCurrentThreadId LIB "KERNEL32.DLL" ALIAS "GetCurrentThreadId" () AS DWORD
                        DECLARE FUNCTION GetClassName LIB "User32.dll" ALIAS "GetClassNameA"(BYVAL hwnd AS DWORD, lpClassName AS ASCIIZ, BYVAL nMaxCount AS LONG) AS LONG
                        DECLARE FUNCTION MessageBox LIB "USER32.DLL" ALIAS "MessageBoxA" (BYVAL hWnd AS DWORD, lpText AS ASCIIZ, lpCaption AS ASCIIZ, BYVAL dwType AS DWORD) AS LONG
                        
                        FUNCTION MsgBoxProc(BYVAL nCode AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                         LOCAL  LF      AS LOGFONT
                         LOCAL  zClass  AS ASCIIZ * %MAX_PATH
                         STATIC hFont   AS DWORD
                         STATIC hStatic AS DWORD
                         IF nCode = %HCBT_CREATEWND THEN
                          GetClassName(wParam, zClass, %MAX_PATH)
                          IF zClass = "Static" THEN hStatic = wParam
                         END IF
                         IF nCode = %HCBT_ACTIVATE THEN
                          IF hFont = 0 THEN
                        '%OEM_FIXED_FONT
                        '%ANSI_FIXED_FONT
                        '%SYSTEM_FIXED_FONT
                           GetObject(GetStockObject(%ANSI_FIXED_FONT), SIZEOF(LF), BYVAL VARPTR(LF))
                           hFont = CreateFontIndirect(LF)
                          END IF
                          SendMessage(hStatic, %WM_SETFONT, hFont, 0)
                         END IF
                         IF nCode = %HCBT_DESTROYWND THEN
                          DeleteObject(hFont)
                          UnhookWindowsHookEx(hHook)
                         END IF
                         FUNCTION = CallNextHookEx(hHook, nCode, wParam, lParam)
                        END FUNCTION
                        
                        FUNCTION MSGBOX2&(lpText$, lpCaption$, uStyle&)
                         if change then hHook = SetWindowsHookEx(%WH_CBT, CODEPTR(MsgBoxProc), GetModuleHandle(""), GetCurrentThreadId)
                         FUNCTION = MessageBox(0, BYVAL STRPTR(lpText$), BYVAL STRPTR(lpCaption$), uStyle&)
                        END FUNCTION
                        
                        FUNCTION PBMAIN()
                         MSGBOX2 "This is the new message box." + $Cr + _
                                 "Nice isn't it?. Or it is no?" + $Cr + _
                                 "Third line. More text sense." + $Cr + _
                                 "Even loooooooooooooooooooooong lines.", "original",0
                         change = 1
                         MSGBOX2 "This is the new message box." + $Cr + _
                                 "Nice isn't it?. Or it is no?" + $Cr + _
                                 "Third line. More text sense." + $Cr + _
                                 "Even loooooooooooooooooooooong lines.", "changed",0
                        END FUNCTION
                        
                        ​
                        Can someone help me with resizing?

                        Some theoretical questions

                        1) in this case variable change AS BYTE or change AS LONG is more efficient?
                        2) it has about 10kB just simple hook of msgbox, another efficient idea for pbcc?

                        Comment


                        • #13
                          1) in this case variable change AS BYTE or change AS LONG is more efficient?​
                          You mean change hHook? No point. What makes you think a LONG is better than a DWORD? (BYTE is simply incorrect.)

                          Return from SetWindowsHookEx is defined in WinUser.inc as DWORD.

                          See:
                          SetWindowsHookExA function (winuser.h) - Win32 apps | Microsoft Learn
                          Handles are 32 bit unsigned.

                          Cheers,
                          Dale

                          Comment


                          • #14
                            Denis, Microsoft defines a Windows API to have certain types of parameters, in a certain order, passed in a certain way. The DECLARE FUNCTION statement tells PowerBASIC how to talk to the API. You must never change the length (in bytes) of the data type in a DECLARE. Specifically a BYTE is 1 byte and a LONG is 4 bytes, and the API is expecting 4 bytes. It is usually ok to switch a LONG to a DWORD or vice versa because they are both 4 bytes, but 1) don't do it for no reason and 2) you have to be aware of the possible code/math implications of LONG vs. DWORD.

                            The docs do say that a LONG is the fastest PowerBASIC data type, but a DWORD is so close that it would be hard to measure the difference. The PB functions natively expect the data types shown in the docs -- usually LONGs -- and any deviation from that may require PB to do extra math.
                            Last edited by Eric Pearson; 19 May 2023, 05:21 AM. Reason: Because I can.
                            "Not my circus, not my monkeys."

                            Comment


                            • #15
                              Originally posted by Denis Gura View Post
                              Hi guys,
                              Code:
                              GLOBAL ..., change AS BYTE
                              ​...
                              if change then
                              ...
                              change = 1
                              ...

                              1) in this case variable change AS BYTE or change AS LONG is more efficient?
                              From PB Help:
                              Long integers are the most efficient data type in PowerBASIC and should be used in all cases where speed is important and a greater numeric range is not required. (Using Byte and Integer variables in FOR/NEXT loops is actually slower than using a Long integer.)


                              Comment


                              • #16
                                Denis,

                                Still interested in why you thought BYTE or LONG might be more efficient for a handle. It might suggest a change or addition in PB's Help.

                                Cheers,
                                Dale

                                Comment


                                • #17
                                  Originally posted by Dale Yarker View Post
                                  Still interested in why you thought BYTE or LONG might be more efficient for a handle. It might suggest a change or addition in PB's Help.
                                  He didn't. He was asking about his global flag* variable which he named change

                                  >1) in this case variable change AS BYTE or change AS LONG is more efficient?​
                                  (See the trimmed code in my previous post)

                                  Confusion arises when programmers don't use a sensible, consistent naming convention.
                                  Personally, I would have named it gflgChange rather than just change

                                  * See: techterms.com/definition/flag
                                  "In computer science, a flag is a value that acts as a signal for a function or process. The value of the flag is used to determine the next step of a program. Flags are often binary flags, which contain a boolean value (true or false). However, not all flags are binary, meaning they can store a range of values.​"

                                  Comment


                                  • #18
                                    From code in post 12:
                                    GLOBAL hHook AS DWORD, change AS BYTE
                                    Yes, confusing. Especially with:
                                    1) in this case variable change AS BYTE or change AS LONG is more efficient?
                                    after scrolling down.

                                    Then what Eric and you said (and me reversed) still holds. Do not change variable types defined in API includes.
                                    Dale

                                    Comment


                                    • #19
                                      Resizing can become complicated, because you will have to resize both messagebox dialog (GetWindowRect and SetWindowPos..), textlabel and move button(s), etc. A problem there is the long word "loooooooooooooooooooooong", but if you add 2-3 $CR to last line, long text may show up on extra lines. Nice work with the font, there, BTW. But creating your own messagebox can give more options and flexibility. CreateWindowEx...

                                      Comment


                                      • #20
                                        'Ref back to Posts 6 and 7, though post 12 is Denis' solution.
                                        'Tested in PBWin10 and PBCC6, so can be compiled to SLL for either.
                                        '
                                        Code:
                                        #compile exe
                                        #dim all
                                        %UNICODE = 1
                                        '########################### mono-spaced messagebox ############################
                                        'A more generalized (with more options) message box will need more code.
                                        '
                                        function TxtMessageBox (TxtCaption as wstring, TxtMessage as wstring) as long
                                          local hTWin as dword
                                          local NumOfLines, Counter, TmpLen as long
                                          local A_Key, TmpStr() as wstring
                                          NumOfLines = parsecount(txtMessage)
                                          dim TmpStr(1 to NumOfLines)
                                          TmpLen = len(txtCaption)  + 2
                                          for Counter = 1 to NumOfLines
                                            TmpStr(Counter) = parse$(txtMessage, $$crlf ,Counter)
                                            if len(TmpStr(Counter)) > TmpLen then
                                              TmpLen = len(TmpStr(Counter))
                                            end if
                                          next
                                          txt.window (TxtCaption, 100, 100, NumOfLines + 2, TmpLen + 1) to hTWin
                                          txt.print "Press ESC to close."
                                          for Counter = 1 to NumOfLines
                                            txt.print TmpStr(Counter)
                                          next
                                          do
                                            A_Key = txt.waitkey$
                                            if A_Key = $$esc then
                                              exit do
                                            end if
                                          loop
                                          txt.end
                                        end function
                                        '======= brute force to demo the messagebox with right justified numbers =======
                                        function pbmain () as long
                                          local MyNumber as ext
                                          local NumStr as wstring
                                          local LenLbl as long
                                          NumStr = "Formatted number entry : "
                                          LenLbl = len(NumStr)
                                          MyNumber = 160000.65##
                                          NumStr += rset$(format$(myNumber,"$ ###,###,##0.00"), 18) + $$crlf
                                          MyNumber = 16000.65##
                                          NumStr += rset$(format$(myNumber,"$ ###,###,##0.00"), lenLbl + 18) + $$crlf
                                          MyNumber = 9876543210.21##
                                          NumStr += rset$(format$(myNumber,"$ ###,###,##0.00"), lenLbl + 18)
                                          TxtMessageBox "Show right justified in a messagebox.", NumStr
                                        end function '
                                        ​Hope someone finds something useful.

                                        Cheers,
                                        Dale

                                        Comment

                                        Working...
                                        X