Preface In our actual work, printing is often required. However, due to historical reasons, the printing function provided by Java has always been weak. In fact, the original JDK does not support printing at all. It was not until jdk1.1 that a lightweight printing support was introduced. Therefore, in the previous programs designed using Java/applet/JSP/servlet, more complex printing is implemented by calling ActiveX/OCX controls or Vb/VC programs, which is very troublesome. In fact, Sun has been committed to improving the Java printing function, and the Java2 Platform has finally begun a robust printing mode, which is fully integrated with the java2d graphics package. Even more encouraging is that the newly released jdk1.4 provides a complete set of "JAVA print service APIs", which are a positive supplement to the existing printing functions. With this, we can achieve most of the actual application requirements, including printing text, graphics, files, and print preview. This article describes how to design a JAVA print program to implement these functions through a specific program instance, and analyzes and compares implementation methods of different versions, I hope you can get some useful tips. Printing in Java 1. Java printing API Java printing APIs mainly exist in Java. AWT. print packages. The classes added by jdk1.4 mainly exist in the javax. Print package and its corresponding sub-packages javax. Print. Event and javax. Print. attribute. Javax. the print package mainly contains the printing service-related classes, while javax. print. event contains the definition of the printed event, javax. print. attribute includes the list of available attributes of the Print Service. 2. How to print To generate a print, you must consider at least two: A print service object is required. This can be implemented in three ways: Java must be implemented in versions earlier than jdk1.4. AWT. print. printable interface or through toolkit. getdefatooltoolkit (). getprintjob to get the print service object. In jdk1.4, you can use javax. print. printserivcelookup is used to locate a printing service object. You need to start a printing job. There are also several implementation methods: Before jdk1.4, you can use Java. AWT. print. printjob (provided by jdk1.1, which is rarely used now) calls the print or printall method to start printing. You can also use Java. AWT. print. the printdialog of printerjob displays the Print dialog box and starts printing using the print method. In jdk1.4, you can use javax. print. the printdialog of serviceui displays the Print dialog box, and then calls the print method to start printing. 3. Printer dialog box 3.1 printing dialog box of printable Before printing, you can use printerjob. printdialog to display a Print dialog box. It gives the user a chance to select the page number range to be printed and allows the user to change the printing settings. It is a local dialog box. In fact, when printing from a printable object, the print object does not know how many pages need to be printed. It just keeps calling the print method. As long as the print method returns the printable. page_exists value, the printing operation will generate printing pages continuously until the print method returns printable. no_such_page. Since the page number is calculated accurately only after the printing is completed, the page number range on the dialog box is not initialized []. We can build a java. AWT. print. the book object is passed to the print object. You can also calculate the number of pages to be printed and pass it to the print object in the specified format so that it can accurately know how many pages to print. 3.2 print serviceui dialog box Unlike the printable dialog box, the default behavior of the printer dialog box that provides serviceui in jdk1.4 has been changed using a new API: by default, the dialog box is not displayed. You must use the serviceui class to call the printdialog method to create the following Print dialog box. JAVA print program design example 1. Print text 1.1 application scenarios Suppose we need to print a text editing field of a form (which may contain only a few lines or multiple pages) and print up to 54 lines per page. How can this problem be achieved? 1.2 Solution The basic idea is as follows: first we need to implement the printable interface, and then calculate the total number of pages to be printed based on the format of up to 54 lines per page. When the button for printing text is clicked, execute the corresponding print action. You can use the drawstring method of graphics2d to print text. 1) Implement the printable Interface /* Graphic indicates the graphic environment for printing. pageformat indicates the format of the printed page (the page size is measured by points, 1 inch of 1 point, 1/72 is 1 inch. A4 paper is roughly 595 × 842 points); page indicates the page number */ Public int print (Graphics g, pageformat PF, int page) throws printerexception { Graphics2d g2 = (graphics2d) g; G2.setpaint (color. Black); // set the print color to black. If (page> = pages) // when the print page number is greater than the total number of pages to be printed, the printing process ends. Return printable. no_such_page; G2.translate (PF. getimageablex (), PF. getimageabley (); // convert coordinates to determine the print Boundary Drawcurrentpagetext (G2, PF, page); // print the current page text Return printable. page_exists; // If a page is printed, continue printing. } /* Print the specific text of the specified page number */ Private void drawcurrentpagetext (graphics2d G2, pageformat PF, int page ){ String S = getdrawtext (printstr) [Page]; // obtain the content of the text to be printed on the current page. // Obtain the default font and corresponding size Fontrendercontext context = g2.getfontrendercontext (); Font F = area. getfont (); String drawtext; Float ascent = 16; // specify the character lattice Int K, I = f. getsize (), lines = 0; While (S. Length ()> 0 & lines <54) // each page is limited to 54 rows { K = S. indexof ('/N'); // obtain the location of each carriage return. If (K! =-1) // There Is A carriage return. { Lines + = 1; // calculate the number of rows Drawtext = S. substring (0, k); // obtain each line of text G2.drawstring (drawtext, 0, ascent); // print each line of text and shift the text at the same time. If (S. substring (k + 1). Length ()> 0 ){ S = S. substring (k + 1); // extract unprinted text Ascent + = I; } } Else // The carriage return does not exist. { Lines + = 1; // calculate the number of rows Drawtext = s; // obtain each line of text G2.drawstring (drawtext, 0, ascent); // print each line of text and shift the text at the same time. S = ""; // text ended } } } /* Save the printed target text as a string array by page */ Public String [] getdrawtext (string s ){ String [] drawtext = new string [Pages]; // initializes an array based on the number of pages For (INT I = 0; I <pages; I ++) Drawtext [I] = ""; // array element Initialization is an empty string Int K, suffix = 0, lines = 0; While (S. Length ()> 0 ){ If (lines <54) // when one page is insufficient { K = S. indexof ('/N '); If (K! =-1) // There Is A carriage return. { Lines + = 1; // accumulate the number of rows // Calculate the specific text content of the page and store it to the corresponding array element Drawtext [suffix] = drawtext [suffix] + S. substring (0, k + 1 ); If (S. substring (k + 1). Length ()> 0) S = S. substring (k + 1 ); } Else { Lines + = 1; // accumulate the number of rows // Store text content to corresponding array elements Drawtext [suffix] = drawtext [suffix] + S; S = ""; } } Else // when the page is full { Lines = 0; // The number of rows is cleared. Suffix ++; // Add 1 to the array subscript } } Return drawtext; } 2) calculate the total number of pages to be printed Public int getpagescount (string curstr ){ Int page = 0; Int position, Count = 0; String STR = curstr; While (Str. Length ()> 0) // The text has not been calculated. { Position = Str. indexof ('/N'); // calculates the location of the carriage return. Count + = 1; // count the number of rows If (position! =-1) STR = Str. substring (Position + 1); // extract uncomputed text Else STR = ""; // The text has been calculated } If (count> 0) Page = count/54 + 1; // divide the total number of rows by 54 to obtain the total number of pages Return page; // return the total number of pages to be printed. } Use a previous version of jdk1.4 to implement the print action button monitoring and complete the specific print operations. Private void printtextaction (){ Printstr = area. gettext (). Trim (); // obtain the target text to be printed. If (printstr! = NULL & printstr. Length ()> 0) // when the printed content is not empty { Pages = getpagescount (printstr); // obtain the total number of printed pages Printerjob myprtjob = printerjob. getprinterjob (); // get the default print job Pageformat = myprtjob. defaultpage (); // obtain the default print page format Myprtjob. setprintable (this, pageformat); // set the printing job If (myprtjob. printdialog () // display the Print dialog box { Try { Myprtjob. Print (); // print each page } Catch (printerexception PE ){ PE. printstacktrace (); } } } Else {// If the printed content is empty, the system prompts that the printing will be canceled. Joptionpane. showconfirmdialog (null, "Sorry, printer job is empty, print cancelled! "," EMPTY ", joptionpane. default_option, joptionpane. warning_message ); } } Use the APIS provided by the new version of jdk1.4 to implement printing action button listening and complete specific printing operations. Private void printtext2action (){ Printflag = 0; // print the flag to be cleared Printstr = area. gettext (). Trim (); // obtain the target text to be printed. If (printstr! = NULL & printstr. Length ()> 0) // when the printed content is not empty { Pages = getpagescount (printstr); // obtain the total number of printed pages // Specify the Print Output Format Docflavor flavor = docflavor. service_formatted.printable; // Locate the default Print Service Printservice = printservicelookup. lookupdefaprintprintservice (); // Create a print job Docprintjob job = printservice. createprintjob (); // Set print attributes Printrequestattributeset pras = new hashprintrequestattributeset (); Docattributeset DAS = new hashdocattributeset (); // Specify the printed content Doc = new simpledoc (this, flavor, das ); // Print without displaying the Print dialog box Try { Job. Print (Doc, pras); // print each page } Catch (printexception PE ){ PE. printstacktrace (); } } Else {// If the printed content is empty, the system prompts that the printing will be canceled. Joptionpane. showconfirmdialog (null, "Sorry, printer job is empty, print cancelled! "," EMPTY ", joptionpane. default_option, joptionpane. warning_message ); } } Print preview 1. application scenarios Many commercial applications require a print preview mechanism, which allows us to see the page on the screen, so that we don't waste paper because we don't like the print results. Suppose we need to print the preview before printing the text mentioned in the previous section. How can this problem be achieved? The following figure shows the interface implementation: (preview next page, preview previous page, and close) 2. Solution Basic Idea: although the printing API of the Java2 Platform does not provide a standard print preview dialog box, it is not complicated to design it by yourself. Under normal circumstances, the print method draws the page environment to a printer graphic environment for printing. In fact, the print method does not actually produce printed pages. It just draws the content to be printed to the graphic environment. Therefore, we can ignore the screen graphics environment and adjust the ratio to make the entire print page fit in a screen rectangle to achieve accurate print preview. In the design and implementation of print preview, two problems need to be solved. First, how to draw the printed content to the screen in a proper proportion; Second, how to implement front-and-back paging. The following describes how to implement these two problems. For the complete implementation, see the printpreviewdialog. Java file in the attachment. /* Draw the content to be printed to the screen proportionally */ Public void paintcomponent (Graphics g ){ Super. paintcomponent (g ); Graphics2d g2 = (graphics2d) g; Pageformat pF = printerjob. getprinterjob (). defaultpage (); // get the page format Double xoff; // horizontal offset of the initial position of the page on the screen Double yoff; // vertical offset of the initial position of the page on the screen Double scale; // The ratio that fits the page on the screen Double PX = PF. getwidth (); // page width Double py = PF. getheight (); // page height Double SX = getwidth ()-1; Double Sy = getheight ()-1; If (PX/Py <SX/SY ){ Scale = SY/Py; // calculate the ratio Xoff = 0.5 * (SX-scale * px); // horizontal offset Yoff = 0; } Else { Scale = SX/PX; // calculate the ratio Xoff = 0; Yoff = 0.5 * (sy-scale * Py); // vertical offset } G2.translate (float) xoff, (float) yoff); // convert coordinates G2.scale (float) scale, (float) scale ); Rectangle2d page = new rectangle2d. Double (0, 0, PX, Py); // draw the page rectangle G2.setpaint (color. White); // set the page background to white. G2.fill (PAGE ); G2.setpaint (color. Black); // set the page text to black. G2.draw (PAGE ); Try { Preview. Print (G2, PF, currentpage); // display the specified preview page } Catch (printerexception PE ){ G2.draw (New line2d. Double (0, 0, PX, Py )); G2.draw (New line2d. Double (0, PX, 0, Py )); } } /* Preview the specified page */ Public void viewpage (int pos ){ Int Newpage = currentpage + Pos; // specifies that the page is within the actual range. If (0 <= Newpage & Newpage <preview. getpagescount (printstr )){ Currentpage = Newpage; // assign the specified page to the current page Repaint (); } } In this way, when you press the "Next" button, you only need to call canvas. viewpage (1). When you press the "preview" button, you only need to call canvas. viewpage (-1) allows you to preview pages. Print Image 1. application scenarios In practical applications, we also need to print images. For example, we sometimes need to print out the complete interface of a Java applet or an application form and all its components. How can we achieve this? 2. Solution The basic idea is as follows: the print and printall methods are provided in the component class of Java and Its Derived classes. You only need to set the attributes to call these two methods directly to print components and images. /* Print the specified form and its components */ Private void printframeaction (){ Toolkit kit = toolkit. getdefatooltoolkit (); // get the Toolkit Properties props = new properties (); Props. Put ("AWT. Print. Printer", "Durango"); // set print attributes Props. Put ("AWT. Print. numcopies", "2 "); If (kit! = NULL ){ // Obtain the printed object that comes with the toolbox Printjob = kit. getprintjob (this, "Print frame", props ); If (printjob! = NULL ){ Graphics Pg = printjob. getgraphics (); // obtain the graphic environment of the Print Object If (PG! = NULL ){ Try { This. printall (PG); // print the form and all its components } Finally { Pg. Dispose (); // deregister the graphic environment } } Printjob. End (); // ends the print job. } } } Print files 1. application scenarios In many practical scenarios, we may need to print a specified file. This file may be a graphic file, such as GIF or JPEG, a text file, such as a TXT or Java file, or a complex PDF or DOC file. So how should we implement this printing requirement? 2. Solution Basic Idea: In versions earlier than jdk1.4, it would be very troublesome and complicated to implement such a printing function, or even hard to imagine. Fortunately, the Print Service API of jdk1.4 provides a complete set of classes and methods for Printing file streams. With these features, we can easily and quickly print different types of files. A general processing method is provided below. /* Print the specified file */ Private void printfileaction (){ // Construct a file selector. The default value is the current directory. Jfilechooser filechooser = new jfilechooser (systemproperties. user_dir ); Int state = filechooser. showopendialog (this); // The file selection dialog box is displayed. If (State = filechooser. approve_option) // if the user selects a file { File file = filechooser. getselectedfile (); // obtain the selected file // Construct the print request property set Printrequestattributeset pras = new hashprintrequestattributeset (); // Set the print format. Because the file type is not determined, select autosense. Docflavor flavor = docflavor. input_stream.autosense; // Find all available printing services Printservice [] = printservicelookup. lookupprintservices (flavor, pras ); // Locate the default Print Service Printservice defaultservice = printservicelookup. lookupdefaprintprintservice (); // Display the Print dialog box Printservice service = serviceui. printdialog (null, 200,200, printservice, defaultservice, flavor, pras ); If (service! = NULL ){ Try { Docprintjob job = service. createprintjob (); // create a print job Fileinputstream FCM = new fileinputstream (File); // construct the file stream to be printed Docattributeset DAS = new hashdocattributeset (); Doc = new simpledoc (FCM, flavor, das); // create a print file format Job. Print (Doc, pras); // print the file } Catch (exception e ){ E. printstacktrace (); } } } } In the preceding example, because the file type has not been determined, the print format of the specified file is defined as docflavor. input_stream.autosense. In fact, if the file format is clearly known before printing, such as GIF, it should be defined as docflavor. input_stream.gif; if it is a PDF file, it should be defined as docflavor. input_streamcompute; for example, a pure ASCII file can be defined as docflavor. input_stream.text_html_us_ascii. And so on. Jdk1.4's javax. Print. docflavor provides an extremely rich array of file stream types. You can make appropriate choices based on specific application requirements. For specific api reference documents, see reference 3 in this article. Conclusion I have summarized some of my experiences in Printing Program Design Using Java during J2EE application development over the past two years. I hope this will give you some inspiration and benefits. Although it is more difficult to implement the printing function using Java than using Microsoft's mfc api. However, the launch of jdk1.4 is an excellent supplement to the weak printing functions of Java in the past. I believe that if you can understand the print program design examples described above and apply and expand them, you can solve the actual programming problems of most applications. With the further development and improvement of Java, it is bound to better enrich its basic class library and print API. I believe that the use of Java to implement advanced printing functions will become a headache for our Java fans. |