Printing to Dot Matrix

RPaps

New Member
We are creating code to print ticket values on a dot matrix printer.

The values being printed come from database fields.

However, one of the fields can have multiple lines in it, thereby throwing off all the alignment of the fields after the multiple lines are printed.

How can i set it up so that, if there are multiple lines in one field, that it will not affect all lines coming after it?

Is there a way to use Put Unformatted to apply to ROWS as well as COLUMNS??

Please Advise, cheers.
 
How about counting the number of lines in the database field using NUM-ENTRIES(table.field, chr(10)) and then output the required blank lines following the field to get everything lined up again.

RPaps said:
We are creating code to print ticket values on a dot matrix printer.


The values being printed come from database fields.

However, one of the fields can have multiple lines in it, thereby throwing off all the alignment of the fields after the multiple lines are printed.

How can i set it up so that, if there are multiple lines in one field, that it will not affect all lines coming after it?

Is there a way to use Put Unformatted to apply to ROWS as well as COLUMNS??

Please Advise, cheers.
 

RPaps

New Member
Simon Sweetman said:
How about counting the number of lines in the database field using NUM-ENTRIES(table.field, chr(10)) and then output the required blank lines following the field to get everything lined up again.

All the fields are displaying properly. But the content in the field can change from ticket to ticket. Sometimes one line only, sometimes two or three.

When it prints one line everything prints out aligned. It's when there are more than one line that the alignment below it is wrong.

Line 1: Hello
Line 2: How are you?
Line 3: Good Thanks.


Error:

Line 1: Hello
Line 2: How are you?
Line 3: I am fine.
Good thanks.

Say line 2 is now 2 lines. Good Thanks in Line 3 is moved down a line. I have to ensure that it STAYS aligned with the label (for example).
 

cecsno

Member
Are the labels preprinted on the ticket? If so why are you putting a "PUT SKIP" in to cause a new line, Progress will not do it by it's self. Is the data in an array? Show the code.

RPaps said:
All the fields are displaying properly. But the content in the field can change from ticket to ticket. Sometimes one line only, sometimes two or three.

When it prints one line everything prints out aligned. It's when there are more than one line that the alignment below it is wrong.

Line 1: Hello
Line 2: How are you?
Line 3: Good Thanks.


Error:

Line 1: Hello
Line 2: How are you?
Line 3: I am fine.
Good thanks.

Say line 2 is now 2 lines. Good Thanks in Line 3 is moved down a line. I have to ensure that it STAYS aligned with the label (for example).
 

RPaps

New Member
Yes, the labels are pre-printed on the paper.

/* Delivery Instructions */
PUT UNFORMATTED SKIP FILL (' ', 2) + cInst SKIP (5).


/* Lower Box */

PUT UNFORMATTED SKIP FILL (' ',11) + cGross + ' ' + cUnit SKIP.
PUT UNFORMATTED SKIP FILL (' ',11) + cNet + ' ' + cUnit SKIP.
cNetGross = STRING(DEC(cGross) - DEC(cNet)).
PUT UNFORMATTED SKIP FILL (' ', 11) + cNetGross + ' ' + cUnit SKIP (3).

PUT UNFORMATTED SKIP FILL (' ', 11) + cQty SKIP (3).

PUT UNFORMATTED SKIP FILL (' ', 10) + cPMName SKIP (5).


cInst are the Delivery Instructions that have to be printed. In some cases, they are multiline, hence screwing up the alignment of the items in the Lower Box.
 

cecsno

Member
Is cInst an array? Do you want to print cInst with multiple lines?

PUT UNFORMATTED SKIP FILL (' ', 2) + cInst[1] SKIP.
PUT UNFORMATTED SKIP FILL (' ', 2) + cInst[2] SKIP.
PUT UNFORMATTED SKIP FILL (' ', 2) + cInst[3] SKIP(3).

There are better ways to do it, but the format of the data coming in needs to be know.


RPaps said:
Yes, the labels are pre-printed on the paper.

/* Delivery Instructions */
PUT UNFORMATTED SKIP FILL (' ', 2) + cInst SKIP (5).


/* Lower Box */

PUT UNFORMATTED SKIP FILL (' ',11) + cGross + ' ' + cUnit SKIP.
PUT UNFORMATTED SKIP FILL (' ',11) + cNet + ' ' + cUnit SKIP.
cNetGross = STRING(DEC(cGross) - DEC(cNet)).
PUT UNFORMATTED SKIP FILL (' ', 11) + cNetGross + ' ' + cUnit SKIP (3).

PUT UNFORMATTED SKIP FILL (' ', 11) + cQty SKIP (3).

PUT UNFORMATTED SKIP FILL (' ', 10) + cPMName SKIP (5).


cInst are the Delivery Instructions that have to be printed. In some cases, they are multiline, hence screwing up the alignment of the items in the Lower Box.
 

RPaps

New Member
cecsno said:
Is cInst an array? Do you want to print cInst with multiple lines?

PUT UNFORMATTED SKIP FILL (' ', 2) + cInst[1] SKIP.
PUT UNFORMATTED SKIP FILL (' ', 2) + cInst[2] SKIP.
PUT UNFORMATTED SKIP FILL (' ', 2) + cInst[3] SKIP(3).

There are better ways to do it, but the format of the data coming in needs to be know.

No, cInst is the field name.
The presence of multiple lines is dependent on what the user enters.
 

cecsno

Member
Enters into what and editor widget a field widget? Is the problem with the length of cInst being to long and cause a line wrap, or there actually multiple lines?

look at substring or num-line function to make it fit. If you want to print multiple cInst lines assign a interger variable appropriatly and SKIP(intVar).

If you only want to print 1 line then
put cInst format "x(70)" at 2 skip 5.
"x(70)" is just an example.

RPaps said:
No, cInst is the field name.
The presence of multiple lines is dependent on what the user enters.
 

RPaps

New Member
cecsno said:
Enters into what and editor widget a field widget? Is the problem with the length of cInst being to long and cause a line wrap, or there actually multiple lines?

look at substring or num-line function to make it fit. If you want to print multiple cInst lines assign a interger variable appropriatly and SKIP(intVar).

If you only want to print 1 line then
put cInst format "x(70)" at 2 skip 5.
"x(70)" is just an example.


cInst is a database field. The field represents a text box within our program.
The user may enter one long line, or they may enter multiple lines. It is up to the user.

I"m trying to solve two problems at once:
1) if the user types one long line, I want the line to continue on the next line at at pre-determined position.

2) if the user enters multiple lines, I want to print the lines in the same way they were typed in.

All of the above is also dependent on the fact that ... I have other data which will print out BELOW cInst. Multiple lines moves down their position on the print out.

Is there a way to set the row that a field value will print on??
I know you can determine a column position using AT, but can you use something similar for ROW position?
 
How about this code - the replace used to indent every line by 2 spaces (so they line up with your first line). The Max ensures a blank cInst still has 5 blank lines following it.

Code:
PUT UNFORMATTED SKIP FILL (' ', 2) +
	REPLACE( cInst, CHR(10), CHR(10) + FILL(' ', 2))
	SKIP (6 - MAX(1, NUM-ENTRIES(cInst, CHR(10)))).

You man need to adjust this slightly, but it should give you and idea of what can be done.
 

RPaps

New Member
Another good solution.
I have been working on it and come up with something like this, which so far seems to be solving one of my issues:

cInst1 = trim(SUBSTRING(string(cInst) ,1, 50)).
cInst2 = trim(SUBSTRING(STRING(cInst), 51, 50)).
cInst3 = trim(SUBSTRING(STRING(cInst), 101, 50)).
cInst4 = trim(SUBSTRING(STRING(cInst), 151, 50)).

PUT UNFORMATTED SKIP FILL (' ', 2) + cInST1 SKIP.
PUT UNFORMATTED SKIP FILL (' ', 2) + cInst2 SKIP.
PUT UNFORMATTED SKIP FILL (' ', 2) + cInst3 SKIP.
PUT UNFORMATTED SKIP FILL (' ', 2) + cInst4 SKIP.

I've set the limit of 50 characters per line. It seems to be working fine, with some minor glitches (it goes to the next line at the 50th character, sometimes spilitting a word in two).

But aside, from that it seems to be placing rows in the desired position, without affecting the following lines.

I'm still perplexed of how I can allow the printer to skip a line if the user hits return in the cInst field. I know chr (10) represents the return, but how can i incorporate it in code?

I'm tackling it along the lines of :

DO j = 1 TO 4:
IF LENGTH(cInst) >= 50 THEN
cIn = SUBSTRING(cInst, k, 50).
ELSE
cIn = SUBSTRING(cInst, k, LENGTH(cInst)).
DO i = 1 TO 50:
IF SUBSTRING(cIn, i, 1) = CHR(10) THEN DO:
cInstE[j] = SUBSTRING(cIn, k, i - 1).
k = k + i + 1.
LEAVE.
END.
END.
END.


PUT UNFORMATTED SKIP FILL (' ', 2) + cIn[1] SKIP.
PUT UNFORMATTED SKIP FILL (' ', 2) + cIn[2] SKIP.
PUT UNFORMATTED SKIP FILL (' ', 2) + cIn[3] SKIP.
PUT UNFORMATTED SKIP FILL (' ', 2) + cIn[4] SKIP.
What are your thoughts?

Please be gentle, I'm only a JUNIOR!!
ha ha
Cheers
 
Ok here we go this should do it i've defined a function WordWrap that wraps the line for you at a word break (if possible and at the width you specify otherwise). You can use it with the code I posted earlier as follows:
Code:
PUT UNFORMATTED SKIP FILL (' ', 2) +
 REPLACE( wordwrap(cInst, 20), CHR(10), CHR(10) + FILL(' ', 2))
 SKIP (6 - MAX(1, NUM-ENTRIES(wordwrap(cInst, 20), CHR(10)))).

The function is as follows (you need to define this before you use it). I don't know if you have used functions before but they help to make your code easier to read.
Code:
FUNCTION WordWrap RETURNS CHAR
  ( ipMessage AS CHAR, ipWidth AS INT) :
	DEF VAR iTmp AS INT NO-UNDO.
	DEF VAR iTmp2 AS INT NO-UNDO.
	DEF VAR cTmp AS CHAR NO-UNDO. 
	
	DEF VAR cNew AS CHAR NO-UNDO.
	DEF VAR cLine AS CHAR NO-UNDO.
	DEF VAR cWord AS CHAR NO-UNDO. 
	DEF VAR iWidth AS INT NO-UNDO.
	DEF VAR iLength AS INT NO-UNDO.
	DEF VAR iUsed AS INT NO-UNDO.
	DEF VAR iMpos AS INT NO-UNDO.
	
	iMpos = 1.
	
	REPEAT:
		cWord = SUBSTRING(ipMessage, iMpos).
	
		IF cWord = ''THEN LEAVE.
	
		ASSIGN
			iTmp = INDEX(cWord, ' ')
			iTmp2 = INDEX(cWord, CHR(10)).
	
		ASSIGN
			iTmp = iTmp2
				WHEN iTmp2 <> 0 and iTmp2 < iTmp.
		ASSIGN
			cWord = SUBSTRING(cWord, 1, iTmp - 1) WHEN iTmp > 1
			iLength = LENGTH(cWord).
	
		if iLength + iUsed + 1 < (ipWidth - 3)
		THEN ASSIGN
			iUsed = iUsed + (IF cLine = '' THEN 0 ELSE 1) + iLength
			cLine = cLine +
				(IF cLine = '' THEN '' ELSE ' ') + cWord.
		ELSE ASSIGN
			cNew = cNew + cLine
			iUsed = iLength
			cNew = cNew + CHR(10)
			cLine = cWord.
	
		ASSIGN
			iMpos = iMpos + iLength
			cTmp = SUBSTRING(ipMessage, iMpos, 1).
	
		REPEAT:
			IF ASC(cTmp) <> 32 AND ASC(cTmp) <> 10
			THEN LEAVE.
	
			IF LENGTH(cTmp) = 0 THEN LEAVE.
	
			IF ASC(cTmp) = 10
			THEN ASSIGN
				iUsed = 0
				cNew = cNew + cLine + CHR(10)
				cLine = "".
	
			ASSIGN
				iMpos = iMpos + 1
				cTmp = SUBSTRING(ipMessage, iMpos, 1).
		END.
	
		IF cTmp = "" THEN LEAVE.
		
	END.
	
	RETURN cNew + cLine.
END FUNCTION.
 

cecsno

Member
DEFINE VARIABLE StringPosition AS INTEGER NO-UNDO.
DEFINE VARIABLE SkipLine AS INTEGER NO-UNDO.
DEFINE VARIABLE StringLength AS INTEGER NO-UNDO.
DEFINE VARIABLE MaxLength AS INTEGER NO-UNDO.
DEFINE VARIABLE cInst AS CHARACTER NO-UNDO.
cInst = "This is a string longer than MaxLength that I want to represent as multiple lines using the PUT statement.".
MaxLength = 30.
StringPosition = 1.
SkipLine = 5.
StringLength = 1.
OUTPUT TO test.txt.
IF LENGTH(cInst) > MaxLength
THEN DO StringPosition = StringPosition to length(cInst):
IF SkipLine < 1
THEN
LEAVE.
/* wrap at space */
IF SUBSTRING(cInst,StringPosition + MaxLength,1) = " "
THEN DO:
PUT UNFORMATTED SUBSTRING(cInst,StringPosition,MaxLength) AT 2.
PUT SKIP.
SkipLine = SkipLine - 1.
/* Set starting position of next line */
StringPosition = StringPosition + MaxLength.
StringLength = MaxLength.
END.
ELSE DO:
/* find first space prior to MaxLength */
StringLength = R-INDEX(SUBSTRING(cInst,StringPosition,MaxLength)," ",MaxLength).
PUT UNFORMATTED SUBSTRING(cInst,StringPosition,StringLength) AT 2.
PUT SKIP.
SkipLine = SkipLine - 1.
/* Set starting position of next line */
StringPosition = StringPosition + StringLength - 1.
END.
END.

IF SkipLine > 0
THEN
PUT SKIP(skipLine).
PUT UNFORMATTED "Other Stuff" AT 5.
OUTPUT CLOSE.
 
cecsno, your posted solution dosn't work if string contains new-line chars -RPaps mentioned the data entry is via an editor widget and the string sometimes contains multi lines.

Code:
cInst = "This is a string" + chr(10) + "longer than MaxLength that I want to represent as multiple lines using the PUT statement.".

Here is a new wordwrap function - made it a little easier to read - the original was chopped from a function that also did justification (center, left, right or full) and was over-complex.

Code:
FUNCTION WordWrap RETURNS CHAR
	( ipMessage AS CHAR, ipWidth AS INT) :
	DEF VAR iLineStart AS INT INIT 1 NO-UNDO.
	DEF VAR cRemains AS CHAR NO-UNDO.
	DEF VAR cAnswer AS CHAR NO-UNDO.
	DEF VAR iLineEnd AS INT NO-UNDO.
 
	REPEAT:
		cRemains = SUBSTRING(ipMessage, iLineStart, ipWidth).
		iLineEnd = R-INDEX(cRemains, CHR(10)).
 
		IF iLineEnd = 0
		THEN REPEAT:
			/*
			 * If no newline or newline > width then
			 * Search backwards for first word that 
			 * starts before width.
			 */
			iLineEnd = R-INDEX(cRemains, ' ', iLineEnd).
 
			IF iLineEnd = 0 THEN iLineEnd = ipWidth - 1.
 
			IF iLineEnd < ipWidth THEN LEAVE.
 
			iLineEnd = iLineEnd - 1.
		END.
 
		/* Add this line to answer */
		cAnswer = cAnswer + CHR(10) +
			SUBSTRING(ipMessage, iLineStart, iLineEnd - 1).
 
		/* Prepare for next line */
		iLineStart = iLineStart + iLineEnd.
 
		IF iLineStart >= LENGTH(ipMessage)
		THEN RETURN SUBSTRING(cAnswer, 2). /* chop of leading chr(10) */
	END.
END FUNCTION.
 

RPaps

New Member
There seems to be a little confusion, and I take the blame for that, and I apologize.

I cannot create a Function, the code is written in a .p procedure which is called on the click of the print button.

I have taken all your suggestions to heart, and have come up with a solution, with help from my team leader. the following works:

cInst = cInst + ' '.
DO WHILE TRUE:
iLineLengh = MIN (LENGTH (cInst), 51).
i = INDEX (cInst, CHR (10)).
IF i > 0 AND
i <= 51 THEN
iLineLengh = i.

i = iLineLengh.
IF i = 0 OR
TRIM (cInst) = '' THEN
LEAVE.

cSub = SUBSTRING (cInst, 1, i).

DO WHILE (SUBSTRING (cSub, i, 1) <> ' ' AND
SUBSTRING (cSub, i, 1) <> CHR (10)):
i = i - 1.
IF i = 0 THEN DO:
i = iLineLengh.
LEAVE.
END.
END.

cSub = SUBSTRING (cSub, 1, i - 1).

/* print cSub */
iLineNum = iLineNum + 1.
IF iLineNum > 3 THEN
LEAVE.

PUT UNFORMATTED SKIP FILL (' ', 2) + cSub.

IF SUBSTRING (cInst, i, 1) = ' ' OR
SUBSTRING (cInst, i, 1) = CHR (10) THEN
cInst = SUBSTRING (cInst, i + 1).
ELSE
cInst = SUBSTRING (cInst, i).
END.

It maynot look beautiful or glamorous, but it seems to be working fine, dependent on some more testing.

Let's keep our fingers crossed and once again, thank u all for your help!!
 
Top