Predavanje br. index|1|2|3|4|5|6|7|8|9|10|11|12|13|14|HOME
u
pripremi
Java 1.1 implements printing through the java.awt.PrintGraphics
interface and the abstract java.awt.Printjob
class.
To begin a print job you call the static method Toolkit.getPrintJob()
.
This returns a platform specific instance of the abstract PrintJob
class. (Platform specific details are hidden inside the sun classes.)
The PrintJob
object gives you information about the page size and the printer resolution. It
also has a getGraphics()
method that returns a Graphics
object that implements the PrintGraphics
interface. Often you'll draw the page by passing this object to your paint()
method. Other times you'll want to specialize for printing. For example, you
might want to draw in black and white instead of color. (Regrettably Java does
not provide a method to determine the available colors on the printer.)
A page is sent to the printer when you invoke its Graphics
's
object's dispose()
method. You can print multiple pages by repeatedly calling getGraphics()
and the disposing each Graphics
object.
As a general rule applets are not allowed to initiate print jobs. Only applications can do that. You wouldn't want a malicious applet to churn your printer with many pages of pure black, wasting all your toner, for example.
The checkPrintJobAccess()
method of the SecurityManager
class is used to determine whether or not printing is allowed.
public void checkPrintJobAccess()
For example,
try {
SecurityManager sm = System.getSecurityManager();
if (sm != null) sm.checkPrintJobAccess();
// print...
}
catch (SecurityException e) {
System.err.println("Sorry. Printing is not allowed.");
}
The
abstract java.awt.PrintJob
class has a single public norags constructor, PrintJob()
.
However because it's an abstract class you can't instatiate it. Instead you must
call the getPrintJob()
method in the java.awt.Toolkit
class.
public abstract PrintJob getPrintJob(Frame parent, String title,
Properties props)
The
Frame
will
hold the platform specific print dialog. The title
string
identifies this job in the print queue and on the cover page. The props
arguments is a java.awt.Properties
object You can use to request different printing options on Unix. However this
doesn't work on Windows, and in any case printing options are platform specific.
A PrintJob dialog
For example:
PrintJob pj =
Toolkit.getDefaultToolkit().getPrintJob(new Frame(),
"Hello World", null);
This
returns a platform specific subclass of the PrintJob
class. If the user cancels the PrintJob in the dialog box, then this method
should return null
. (This
may be a little buggy under Windows, though.)
java.awt.PrintJob
classFor example:
PrintJob pj =
Toolkit.getDefaultToolkit().getPrintJob(new Frame(),
"Hello World", null);
This
returns a platform specific subclass of the PrintJob
class. The first thing you'll want to do with this object is determine the
characteristics of the printer. There are three methods for this:
public abstract int getPageResolution()
public abstract Dimension getPageDimension()
public abstract boolean lastPageFirst()
The
getPageResolution()
method returns the number of dots per inch of thee printer, typically 300 or 600
for most laser printers. getPageDimension()
returns a java.awt.Dimension
object giving the size of the printable area of the page in pixels (not
inches!). For example, the following code fragment prints the total number of
pixels on the page:
PrintJob pj = Toolkit.getPrintJob();
int resolution = pj.getPageResolution();
Dimension d = pg.getPageDimension();
System.out.println("There are " + (resolution * d.width * d.height)
+ " pixels on a page.");
Finally
lastPageFirst()
returns true if the last page will be printed first, false otherwise.
You
use this information to prepare your image to be drawn on the page. depending on
the size of the page and the type of the image, you may need to spilt it across
multiple pages. Sometimes it's easier to just draw the entire image on each
page, but use clipRect()
to
set the fraction of the image to actually be drawn.
The
drawing itself is done with a java.awt.Graphics
object like the one you use in the paint()
method
of an applet. This is returned by getGraphics()
,
and has all the usual method of the Graphics
class, drawLine()
,
drawString()
,
and so on.
public abstract Graphics getGraphics()
There's
one important caveat: Unilke the Graphics objects passed as arguments to a
paint()
method, this object does not intially have a font set. You'll generally want to
set its font before using it like this:
Font courier = new Font("Courier", Font.PLAIN, 12);
g.setFont(courier);
When
you're done with a PrintJob
call
its end()
method
to perform any necessary flushing and clean up.
public abstract void end()
The following simple program prints some circles:
import java.awt.*;
public class PrintableBullseye extends Canvas {
public static void main(String[] args) {
PrintableFrame pf = new PrintableFrame("Printable Frame");
pf.add("Center", new PrintableBullseye());
pf.setVisible(true);
}
public Dimension getPreferredSize() {
return new Dimension(250, 250);
}
public Dimension getMinimumSize() {
return new Dimension(50, 50);
}
public void paint(Graphics g) {
int rectLeft, rectTop, rectHeight, rectWidth;
int height = this.getSize().height;
int width = this.getSize().width;
Color red = Color.red;
if (g instanceof PrintGraphics) {
red = Color.black;
}
for (int i=8; i >= 0; i--) {
if ((i % 2) == 0) g.setColor(red);
else g.setColor(Color.white);
rectHeight = height*i/8;
rectWidth = width*i/8;
rectLeft = width/2 - i*width/16;
rectTop = height/2 - i*height/16;
g.fillOval(rectLeft, rectTop, rectWidth, rectHeight);
}
}
}
The
trick to printing text is to measure it and compare it to the page size and
resolution in a given font. You do this with the java.awt.FontMetrics
class.
// This example is from the book _Java AWT Reference_ by John Zukowski.
// Written by John Zukowski. Copyright (c) 1997 O'Reilly & Associates.
// You may study, use, modify, and distribute this example for any purpose.
// This example is provided WITHOUT WARRANTY either expressed or
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.Properties;
public class TestPrint extends Frame {
TextArea textArea;
Label statusInfo;
Button loadButton, printButton, closeButton;
Properties p = new Properties();
public TestPrint() {
super ("File Loader");
add (statusInfo = new Label(), "North");
Panel p = new Panel ();
p.add (loadButton = new Button ("Load"));
loadButton.addActionListener( new LoadFileCommand() );
p.add (printButton = new Button ("Print"));
printButton.addActionListener( new PrintCommand() );
p.add (closeButton = new Button ("Close"));
closeButton.addActionListener( new CloseCommand() );
add (p, "South");
add (textArea = new TextArea (10, 40), "Center");
pack();
}
public static void main (String args[]) {
TestPrint f = new TestPrint();
f.show();
}
// Bail Out
class CloseCommand implements ActionListener {
public void actionPerformed (ActionEvent e) {
System.exit (0);
}
}
// Load a file into the text area.
class LoadFileCommand implements ActionListener {
public void actionPerformed (ActionEvent e) {
int state;
String msg;
FileDialog file = new FileDialog (TestPrint.this, "Load File", FileDialog.LOAD);
file.setFile ("*.java"); // Set initial filename filter
file.show(); // Blocks
String curFile;
if ((curFile = file.getFile()) != null) {
String filename = file.getDirectory() + curFile;
char[] data;
setCursor (Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
File f = new File (filename);
try {
FileReader fin = new FileReader (f);
int filesize = (int)f.length();
data = new char[filesize];
fin.read (data, 0, filesize);
} catch (FileNotFoundException exc) {
String errorString = "File Not Found: " + filename;
data = errorString.toCharArray ();
} catch (IOException exc) {
String errorString = "IOException: " + filename;
data = errorString.toCharArray ();
}
statusInfo.setText ("Load: " + filename);
textArea.setText (new String (data));
setCursor (Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}
// Print a file into the text area.
class PrintCommand implements ActionListener {
public void actionPerformed (ActionEvent e) {
PrintJob pjob = getToolkit().getPrintJob(TestPrint.this, "Cool Stuff", p);
if (pjob != null) {
Graphics pg = pjob.getGraphics();
if (pg != null) {
String s = textArea.getText();
printLongString (pjob, pg, s);
pg.dispose();
}
pjob.end();
}
}
}
// Print string to graphics via printjob
// Does not deal with word wrap or tabs
void printLongString (PrintJob pjob, Graphics pg, String s) {
int pageNum = 1;
int linesForThisPage = 0;
int linesForThisJob = 0;
// Note: String is immutable so won't change while printing.
if (!(pg instanceof PrintGraphics)) {
throw new IllegalArgumentException ("Graphics context not PrintGraphics");
}
StringReader sr = new StringReader (s);
LineNumberReader lnr = new LineNumberReader (sr);
String nextLine;
int pageHeight = pjob.getPageDimension().height;
Font helv = new Font("Helvetica", Font.PLAIN, 12);
//have to set the font to get any output
pg.setFont (helv);
FontMetrics fm = pg.getFontMetrics(helv);
int fontHeight = fm.getHeight();
int fontDescent = fm.getDescent();
int curHeight = 0;
try {
do {
nextLine = lnr.readLine();
if (nextLine != null) {
if ((curHeight + fontHeight) > pageHeight) {
// New Page
System.out.println ("" + linesForThisPage + " lines printed for page " + pageNum);
pageNum++;
linesForThisPage = 0;
pg.dispose();
pg = pjob.getGraphics();
if (pg != null) {
pg.setFont (helv);
}
curHeight = 0;
}
curHeight += fontHeight;
if (pg != null) {
pg.drawString (nextLine, 0, curHeight - fontDescent);
linesForThisPage++;
linesForThisJob++;
} else {
System.out.println ("pg null");
}
}
} while (nextLine != null);
} catch (EOFException eof) {
// Fine, ignore
} catch (Throwable t) { // Anything else
t.printStackTrace();
}
System.out.println ("" + linesForThisPage + " lines printed for page " + pageNum);
System.out.println ("pages printed: " + pageNum);
System.out.println ("total lines printed: " + linesForThisJob);
}
}
You
don't draw most buttons, lists, scrollbars, panels, and so on in your
paint()
method. You don't have to print them there either. The java.awt.Component
class has print()
and
printAll()
methods
public void print(Graphics g)
public void printAll(Graphics g)
java.awt.Container
adds a printComponents()
method that prints all components in the container:
public void printComponents(Graphics g)
For
example, to print a Frame f
, you
might do this:
Toolkit tk = f.getToolkit();
Printjob pj = tk.getPrintJob(this, getTitle(), null);
if (pj != null) {
Graphics pg = pj.getGraphics();
f.printComponents(pg);
pg.dispose();
pj.end();
}
However
this isn't always what you want since printComponents()
only prints the visible area. for example, in the text editing application the
TextArea
may
only show part of the text at one time, but you really want to print all the
text.
The following simple program prints itself when you press the print button:
import java.awt.*;
public class PrintableFrame extends Frame
implements ActionListener {
Button printButton;
public static void main(String[] args) {
PrintableFrame pf = new PrintableFrame("Printable Frame");
Label quote = new Label(
"Now is the time for all good men to come to the aid of their country.");
pf.add("North", quote);
}
public PrintableFrame(String s) {
super(s);
setSize(350, 200);
setLocation(100, 100);
printButton = new Button("Print Me!");
printButton.addActionListener(this);
Panel p = new Panel();
p.add(printButton);
add("South", p);
}
public void actionPerformed(ActionEvent e) {
PrintJob pj = getToolkit().getPrintJob(this, getTitle(), null);
if (pj != null) {
Graphics pg = pj.getGraphics();
printComponents(pg);
pg.dispose();
pj.end();
}
}
}
Modern, multitasking operating systems and graphical user interfaces allow you to transfer data between programs at the request of the user through a system facility called a clipboard. In general, clipboards can contain text, pictures, sound, formatted text, data in particular formats and more. However, not all programs know how to interpret all data formats.
Most of the time the user somehow selects the data to be placed on the clipboard. The data may then be copied to the clipboard, generally by selecting "Copy" from the Edit menu or by using the C shortcut key. Alternately data can be cut out of the running program and placed on the clipboard. Copied data remains in the original document while cut data is deleted from the original document. The data is then placed back into the same document or into a different documnent by pasting it from the clipboard. On most operating systems (though OpenWindows is a notable exception) pasting does not remove the data from the clipboard.
As well as the system clipboard many applications have private clipboards that are used for intra-application data transfer. The system clipboard is used for inter-application data transfer.
java.awt.datatransfer
PackageThe
java.awt.datatransfer
package provides classes to support transfer of data to and from the system
clipboard. Support for the clipboard is still in its infancy in Java 1.1. Only
string data is supported, and only cut, copy, and paste. Other data types and
drag and drop will be added in the future.
The
java.awt.datatransfer.Transferable
interface is implementod by classes that represent data to be transferred. It
includes methods to determine the possible data flavors of the object and to
retrieve the data itself.
The
java.awt.datatransfer.DataFlavor
class provides a MIME type based system for determining the type of data on the
clipboard. For example, flavors include "text/plain; charset=unicode" and
"application/x-java-serialized-object"
A
java.awt.datatransfer.UnsupportedFlavorException
is thrown when you ask a Transferable
object to return its contents in an incompatible flavor.
The
java.awt.datatransfer.Clipboard
class allows the transfer of data through cut, copy, and paste operations.
Although there's only one system clipboard, your program may create many
different Clipboard
objects for internal use.
For
synchronization purposes each clipboard must be the exclusive property of one
object. This object must implement the java.awt.datatransfer.ClipboardOwner
interface. This interface declaes a single method, lostOwnership()
,
which is which is used to warn an object that it no longer owns the
clipboard.
The
java.awt.datatransfer.StringSelection
class is the one concrete implementation of Transferable
and ClipboardOwner
included in Java 1.1. It allows you to transfer plain text to and from the
system clipboard.
There
are a few methods and classes outside the java.awt.datatransfer
package that are relevant to copy and paste.
The
getSystemClipboard()
method of the java.awt.Toolkit
class returns a Clipboard
object which represents the system clipboard:
public abstract Clipboard getSystemClipboard()
The
java.lang.SecurityManager
class includes a checkSystemClipboardAccess()
method that determines whether or not this program is allowed to access the
system clipboard. The method is void but throws a SecurityException
if access is not allowed.
public void checkSystemClipboardAccess()
The concern is that the clipboard may contain private data which the user would not want revealed to the server. As a general rule, applets loaded from web servers will not be allowed to access the system clipboard. This does not, however, apply to private clipboards you create. For example,
try {
SecurityManager sm = SecurityManager.getSecurityManager();
if (sm != null) sm.checkSystemClipboardAccess();
Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
//... handle clipboard
}
catch (SecurityException e) {
System.err.println("Cannot access the system clipboard");
}
The
java.awt.TextComponent
class, which both TextArea
and
TextField
extend, has a getSelectedText()
method that returns the current value of the selection as a String:
public synchronized String getSelectedText()
You'll
often use this method to decide what to copy or cut. Several other TextComponent
methods are also useful for manipulating the selection:
public synchronized int getSelectionStart()
public synchronized void setSelectionStart(int selectionStart)
public synchronized void setSelectionEnd(int selectionEnd)
public synchronized void select(int selectionStart, int selectionEnd)
public synchronized void selectAll()
public void setCaretPosition(int position)
public int getCaretPosition()
The
TextArea
class
(but not the TextField
class) also has insert()
and
replaceRange()
methods you can use for pasting:
public synchronized void insert(String s, int pos)
public synchronized void replaceRange(String s, int start, int end)
What's
the difference between these two methods? When would you use insert()
and
when would you use replaceRange()
?
getSystemClipboard()
method of the java.awt.Toolkit
class.
StringSelection
,
which implements the transferable interface and contains the data you want to
copy.
setContents()
method of the Clipboard class. For example,
public void copy(TextField tf) {
StringSelection data = new StringSelection(tf.getText());
Clipboard clipboard = Toolkit().getDefaultToolkit().getSystemClipboard();
clipboard.setContents(data, data);
}
getSystemClipboard()
method of the java.awt.Toolkit
class.
getContents()
method of the Clipboard class.
getTransferData()
.
For example,
public void paste(TextField tf) {
Clipboard clipboard = Toolkit().getDefaultToolkit().getSystemClipboard();
Transferable data = clipboard.getContents(this);
String s;
try {
s = (String) (data.getTransferData(DataFlavor.stringFlavor));
}
catch (Exception e) {
s = data.toString();
}
tf.setText(s);
}
// This example is based on one from
// the book _Java AWT Reference_ by John Zukowski.
// You may study, use, modify, and distribute this example for any purpose.
import java.io.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
public class ClipMe extends Frame
implements ActionListener {
TextField tf;
TextArea ta;
public static void main (String args[]) {
new ClipMe().show();
}
public ClipMe() {
super("Clipping Example");
add(tf = new TextField("Welcome"), "North");
add(ta = new TextArea(), "Center");
MenuBar mb = new MenuBar();
mb.add(makeEditMenu());
setMenuBar(mb);
setSize(250, 250);
}
Menu makeEditMenu() {
Menu editMenu = new Menu("Edit");
MenuItem mi = new MenuItem("Cut");
mi.addActionListener(this);
editMenu.add(mi);
mi = new MenuItem("Copy");
mi.addActionListener(this);
editMenu.add(mi);
mi = new MenuItem("Paste");
mi.addActionListener(this);
editMenu.add(mi);
mi = new MenuItem("Clear");
mi.addActionListener(this);
editMenu.add(mi);
return editMenu;
}
public void actionPerformed (ActionEvent evt) {
Clipboard clipboard = getToolkit().getSystemClipboard();
String cmd = evt.getActionCommand();
if (cmd.equalsIgnoreCase("copy")) {
StringSelection data = new StringSelection(tf.getText());
clipboard.setContents(data, data);
}
else if (cmd.equalsIgnoreCase("clear")) {
tf.setText("");
}
else if (cmd.equalsIgnoreCase("paste")) {
Transferable clipData = clipboard.getContents(this);
String s;
try {
s = (String)(clipData.getTransferData(DataFlavor.stringFlavor));
}
catch (Exception e) {
s = e.toString();
}
ta.setText(s);
}
else if (cmd.equalsIgnoreCase("cut")) {
StringSelection data = new StringSelection(tf.getText());
clipboard.setContents(data, data);
tf.setText("");
}
}
}
Different applications understand data differently, even the same kind of data. For example most word processors support some form of formatted text with different fonts, styles, sizes and so on. However Microsoft Word 6.0 for the Mac is not able to read formatted text produced by ClarisWorks and vice versa. Pictures from Photoshop can be copied and pasted into many programs, but the layers tend to get flattened when you do that.
The
clipboard only really understands raw bytes. It does not inherently know how
whether those bytes are text or a picture or a table or something else. The
java.awt.datatransfer.DataFlavor
class uses MIME types and subtypes to identify the kind of data stored in the
clipboard.
MIME, the Multipurpose Internet Mail Extensions, is an Internet standard defined in RFCs 2045 through 2049 for transferring multimedia, binary data through 7-bit ASCII email. RFC 2046 in particular specifies the MIME type system and defines the base set of media types. New MIME types are registoered with and approved by the Internet Assigned Numbers Authority (IANA). The current list of standardized types is available from ftp://ftp.isi.edu/in-notes/iana/assignments/media-types/media-types.
A MIME type has a type and a subtype. For example, text/plain, application/x-java-serialized-object, or image/gif. There are five defined types: text, image, audio, video, multipart, message, model, and application. The first seven are self-explanatory. The last is used for arbitrary binary data. Subtypes that begin with an x such as "x-java-serialized-object" are unofficial, application specific extensions. Two different programs are not guaranteed to interpret the same x type as representing the same kind of data.
java.awt.datatransfer.DataFlavor
classThe
java.awt.datatransfer.DataFlavor
class encapsulates a MIME type to represent the data format of an object stored
on the clipboard as raw bytes. Each data flavor has a representation
class
, a MIME type, and a human presentable name. The
representation class is the Java class which approximates the data. For example,
the plain text flavor uses the representation class java.io.InputStream
and the MIME type "text/plain; charset=unicode". The human presentable name is
just a slightly more reader-friendly variant of the MIME type like "JPEG
picture" instead of "image/jpeg".
Currently
two specific data flavors are defined, DataFlavor.plainTextFlavor
and DataFlavor.stringFlavor
.
There are two constructors that allow you to create new data flavors:
public DataFlavor(Class representationClass,
String humanPresentableName)
public DataFlavor(String mimeType, String humanPresentableName)
The
first constructor specifies the representation class and the human presentable
name. However the MIME type is normally set to
"application/x-java-serialized-object". The second constructor lets you set the
MIME type but uses the representation class InputStream
.
Given a data flavor, the following methods retreive and set information about the flavor:
public String getMimeType()
public Class getRepresentationClass()
public String getHumanPresentableName()
public void setHumanPresentableName(String humanPresentableName)
public boolean equals(DataFlavor dataFlavor)
public boolean isMimeTypeEqual(String mimeType)
public final boolean isMimeTypeEqual(DataFlavor dataFlavor)
java.awt.datatransfer.Clipboard
classThe
java.awt.datatransfer.Clipboard
class represents an object onto which you can put transferable objects and from
which you can get transferable objects.
There's one constructor you can use to create private clipboards. However most of thhe time you'll just get the system clipboard instead:
public Clipboard(String name)
There are also three methods that allow you to get the name of the object currently on the clipboard (only one object can be on a clipboard at a time), to get the contents of the clipboard (paste), or to set the contents of the clipboard (cut or copy):
public String getName()
public synchronized void setContents(Transferable contents,
ClipboardOwner owner)
public synchronized Transferable getContents(Object requestor)
java.awt.datatransfer.ClipboardOwner
interfaceFor
synchronization purposes each clipboard must be the exclusive property of one
object. This object must implement the java.awt.datatransfer.ClipboardOwner
interface. This interface declaes a single method, lostOwnership()
,
which is which is used to warn an object that it no longer owns the clipboard.
public abstract void lostOwnership(Clipboard clipboard,
Transferable contents)
java.awt.datatransfer.Transferable
interfaceThe
java.awt.datatransfer.Transferable
interface must be implemented by any class that will represent the data to be
cut or pasted. It defines three methods:
public abstract boolean isDataFlavorSupported(DataFlavor flavor)
public abstract DataFlavor[] getTransferDataFlavors()
public abstract Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException
You
can ask a Transferable
object whether it supports a particular data flavor you want with isDataFlavorSupported()
or you can ask it to list all the data flavors it supports with getTransferDataFlavors()
.
Note especially that one object may support multiple data flavors. For example, most objects should provide a plain text flavor as a lowest common denominator all applications can handle. However, the same data may also be available in an HTML flavor for applications that can handle the additonal formatting.
Finally
you request an object of a particular flavor with getTransferData()
.
If the flavor you request is not available an UnsupportedFlavorException
is thrown.
java.awt.datatransfer.StringSelection
classThe
java.awt.datatransfer.StringSelection
class is the only concrete implementation of the java.awt.datatransfer.Transferable
interface and the java.awt.datatransfer.ClipboardOwner
interface in Java 1.1. It lets you transfer a string in plain text format.
It has the four methods it must implement to support its interfaces:
public abstract boolean isDataFlavorSupported(DataFlavor flavor)
public abstract DataFlavor[] getTransferDataFlavors()
public abstract Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException
public void lostOwnership(Clipboard clipboard, Transferable contents)
It
also has a constructor you use to create a new StringSelection
object:
public StringSelection(String data)