A Standard Form with Barcodes and Custom Entries

From Scribus Wiki
Jump to navigation Jump to search
This article is part of the Scripts series.

Here are the Scribus operations you will find examples for in this script:

  • Creating a new document
  • Creating a number of lines at various locations, one example using a loop for lines spaced at intervals
  • Creating a new layer, then making that layer active
  • Using valueDialog for user input, plus showing the Python logic (split) to convert a single entry separated by space into two values
  • Some limited testing for appropriateness of user input (encodable barcode characters)
  • Creating text frames at specified page locations, including one on a new layer
  • Setting fonts, and font characteristics, such as font, its size, alignment of text in the frame
  • Selecting text within a frame
  • Making barcodes using a function makebars based on the script code39.py
  • Using messageBox for user feedback

About This Script

Having made a script for generating Code 39 barcodes, I wanted to take this one step further, and use that script inside a larger script that creates a form that I use which has barcodes on it.

Here it is:

Standard form.png As you can see, this is something designed for a hospital chart, which was the intended use. When I first began doing this, the idea was to begin to generate my notes for charts using Scribus, so I went about creating a template form with Scribus. Since I wanted to have this blend in with existing notes in the chart, I faithfully measured, created, and edited the basic features of the form so that it would be indistinguishable from the stock forms that the hospital makes itself, except for the fact that I wanted to make the notes in the right hand column with Scribus instead of my variably legible handwriting.

The initial faithful rendering had the lines running all the way across the page. Technically, they're still there, but now covered with a text frame having a white background, so that the Scribus text did not have to compete visually with unnecessary lines.

The information in the upper right hand corner is specific to the patient, even this fictitious one, so the template does not have that. This comes from a script with a series of valueDialogs, after which the text frame is generated and the contents entered, once again to duplicate the hospital's computer-generated forms. After that script ran, then I needed to run Barcode Generator in Scribus, then place the barcode and size it properly.

This is where the Code 39 barcode script came in, since I wanted to create the entire label and barcode with the script.

The final step, the topic of this wiki article, involves taking those parts and now simply generating the entire page from scratch. This required going back to my template, taking down dimensions, positions, font sizes to be able to do all of what you see with a script. As you can see, there are two barcodes, the one on the upper left simply indicating the name of the form, since once a patient is discharged, their paper chart is scanned into the hospital's electronic record, so all of this kind of form ends up in the same section in the record. The patient's barcode in the upper right makes sure that it ends up not only in the right patient's chart but the right admission for that patient.

To avoid repetition, I transformed the barcode creation into a function, makebars which you see near the beginning of the script. I also wanted to make sure that I did not mess up my basic layout while editing the notes frame, so the frame with the heading NEUROLOGY CONSULTATON is generated on a newly created layer, separate from all the other content.

I might add that I'm getting feedback from the nursing staff amazed at how legible my notes are. I've also had other doctors ask me how I did this. With enough interest I may work on the hospital to officially add Scribus to the hospital's desktop computers – I've managed to do this for my own use even though technically I don't have administrative rights to save programs.

Something else I've done in selected situations is to take screengrabs of selected brain scan images, then add them with image frames to the page, when this seems useful. Very easy of course with Scribus.

consultation.py

One change you might consider in your own form script compared with this one is to not exit when a "bad" character is entered for the barcode. For my purposes, I felt that if I did make a mistake, I would just delete the page and start all over. Exiting the script will leave you with a blank form with lines, minus the information in the upper right hand corner, and minus the text frame with NEUROLOGY CONSULTATION in it, so it still could be usable.

If you happen to try out this script, notice that the valueDialogs ask for 2 bits of info each, separated by white space, and also make sure these fonts are on your system.

#!/usr/bin/env python
# -*- coding: utf-8  -*-

# ****************************************************************************
#  This program is free software; you can redistribute it and/or modify 
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# 
# ****************************************************************************

# consultation.py
# created 2010.08.10   © Gregory Pittman, 2010

import scribus
import sys
import string

def makebars(relx, rely, height, S, humanread):
    origx = relx
    code = startstop

    for x in S[0:]:
        if x.isdigit():
            xnum = int(x)
            code = code + code39[xnum]
        elif ((ord(x) > 64) and (ord(x) < 91)):   # ord(character) yields the ascii value
	    xnum = ord(x) - 55
	    code = code + code39[xnum]
        elif (ord(x) == 32):                      #  space
            code = code + code39[36]
        elif ((ord(x) == 36) or (ord(x) == 37)):  #  $ and %
            xnum = ord(x) + 1
            code = code + code39[xnum]
        elif ((ord(x) > 44) and (ord(x) < 48)):   #  - . /
            xnum = ord(x) - 6
            code = code + code39[xnum]
        elif (ord(x) == 43):                      #  +
            code = code + code39[42]
        elif (ord(x) == 42):
            code = code + startstop               #  * (adding for completeness)
        else:
            scribus.messageBox('OOPS!',S + '\nCode 39 does not encode this character: '+x,scribus.ICON_NONE,button1=scribus.BUTTON_OK)
            sys.exit(1)

    code = code + startstop


    for y in code[0:]:
        if y == 'n':
            relx = relx + narrow/2
            d = scribus.createLine(relx,rely,relx,rely + height,) #narrow line
            scribus.setLineWidth(narrow, d)
            scribus.setLineColor(b, d)
            scribus.setFillColor(b, d)
            relx = relx + narrow + narrow/2
        elif y == 'w':
            relx = relx + wide/2
            d = scribus.createLine(relx,rely,relx,rely + height,) #wide line
            scribus.setLineWidth(wide, d)
            scribus.setLineColor(b, d)
            scribus.setFillColor(b, d)
            relx = relx + narrow + wide/2
        elif y == 's':                                      #for wide space
            relx = relx + wide

    if (humanread == 'Yes'):
        t = scribus.createText(origx, rely+height+3, relx - origx, 15)
        scribus.setText(S, t)
        scribus.setFont("DejaVu Sans Book", t)
        scribus.setFontSize(8, t)
        scribus.setTextAlignment(scribus.ALIGN_CENTERED, t)
    return

code39 = ['nnswwn','wnsnnw','nwsnnw','wwsnnn','nnswnw','wnswnn','nwswnn','nnsnww','wnsnwn','nwsnwn']
# I'm using 'n' to denote a narrow line, 'w' for wide line, 's' for wide space
# if a space is not wide then a narrow space is created
# next add the codes for A-Z
code39.extend(['wnnsnw','nwnsnw','wwnsnn','nnwsnw','wnwsnn','nwwsnn','nnnsww','wnnswn','nwnswn'])
code39.extend(['nnwswn','wnnnsw','nwnnsw','wwnnsn','nnwnsw','wnwnsn','nwwnsn','nnnwsw','wnnwsn'])
code39.extend(['nwnwsn','nnwwsn','wsnnnw','nswnnw','wswnnn','nsnwnw','wsnwnn','nswwnn'])

startstop = 'nsnwwn'
narrow = 1.0   # narrow line width
wide = 2.2    # wide line width
b="Black"     #line color
ypos = 205.68

if (scribus.newDocument(scribus.PAPER_LETTER,(10,10,10,10),scribus.PORTRAIT,1,scribus.UNIT_POINTS,scribus.PAGE_1,0,1)):
    #first, we'll make the basic layout for the page
    L1 = scribus.createLine(25.51,161.57,578.27,161.57)
    scribus.setLineWidth(0.6,L1)
    scribus.setLineColor(b,L1)
    L2 = scribus.createLine(25.51,183.42,578.27,183.42)
    scribus.setLineWidth(0.6,L2)
    scribus.setLineColor(b,L2)
    L4 = scribus.createLine(298.64,161.57,298.64,747.43)
    scribus.setLineWidth(0.6,L4)
    scribus.setLineColor(b,L4)
    while (ypos<750):
        L3 = scribus.createLine(25.51,ypos,578.27,ypos)
        scribus.setLineWidth(0.2,L3)
        scribus.setLineColor(b,L3)
        ypos=ypos+20.84
    T1 = scribus.createText(28,96,120,15)
    scribus.setText("SCRIBUS MEDICAL CENTER", T1)
    scribus.setTextAlignment(scribus.ALIGN_LEFT, T1)
    scribus.setFont("DejaVu Sans Book", T1)
    scribus.setFontSize(8, T1)
    T2 = scribus.createText(28,124,148,25)
    scribus.setText("PHYSICIAN'S ORDERS", T2)
    scribus.setTextAlignment(scribus.ALIGN_LEFT, T2)
    scribus.setFont("DejaVu Sans Book", T2)
    scribus.setFontSize(12, T2)
    T3 = scribus.createText(25.22,168.29,272.28,16.71)
    scribus.setText("PHYSICIAN'S ORDERS", T3)
    scribus.setTextAlignment(scribus.ALIGN_CENTERED, T3)
    scribus.setFont("DejaVu Sans Book", T3)
    scribus.setFontSize(11, T3)
    T4 = scribus.createText(297.75,168.29,279.78,16.71)
    scribus.setText("PROGRESS NOTES", T4)
    scribus.setTextAlignment(scribus.ALIGN_CENTERED, T4)
    scribus.setFont("DejaVu Sans Book", T4)
    scribus.setFontSize(11, T4)
    makebars(34,44,30,"5800A",'Yes')
    # next we get down to getting info about the particular patient
    names = scribus.valueDialog('Last Name + First Name','Last and first names are\n(Separate with white space only) ')
    name = names.split()
    last_name = string.upper(name[0])
    first_name = string.upper(name[1])
    age_DOB = scribus.valueDialog('Age + DOB','Age and DOB (MM/DD/YYYY) are \n(Separate with white space only)')
    ageDOB = age_DOB.split()
    age = ageDOB[0]
    DOB = ageDOB[1]
    adm_hospnum = scribus.valueDialog('Admit Date + Hospital Number','Admission Date (MM/DD/YYYY) and\n 10-digit Hospital No.\n(Separate with white space only)')
    adm_hosp = adm_hospnum.split()
    adm_Date = adm_hosp[0]
    hosp_number = adm_hosp[1]
    MRN = hosp_number[:-3]

    L = scribus.createText(400, 83, 182, 47)
    scribus.setText(last_name+", "+first_name+"\n"+hosp_number+"          "+adm_Date+"\n"+DOB+"   "+age+"Y     "+MRN, L)
    scribus.setTextAlignment(scribus.ALIGN_LEFT, L)
    scribus.setFont("DejaVu Sans Book", L)
    scribus.setLineSpacing(10,L)
    scribus.setFillColor("White",L)
    scribus.setFontSize(8, L)
    scribus.setTextDistances(5,0,7,0,L)
    textLength = len(last_name)+len(first_name)+2
    scribus.selectText(0,textLength,L)
    scribus.setFont("DejaVu Sans Bold",L)
    makebars(401,125,24,hosp_number,"No")
    scribus.createLayer("Notes")
    scribus.setActiveLayer("Notes")
    N = scribus.createText(299.01, 191.3, 280.36, 557.2)
    scribus.setText("NEUROLOGY CONSULTATION", N)
    scribus.setTextAlignment(scribus.ALIGN_LEFT, N)
    scribus.setFont("DejaVu Sans Book", N)
    scribus.setLineSpacing(15,N)
    scribus.setFillColor("White",N)
    scribus.setFontSize(11, N)
    scribus.setTextDistances(5,0,0,0,N)
    scribus.setRedraw(1)
    scribus.redrawAll()

else:
    scribus.messageBox('OOPS!','Failed to open a new document',scribus.ICON_NONE,button1=scribus.BUTTON_OK)
    sys.exit(1)