|
12. Displaying text
Sometimes, you may want to show a table or a
number of text lines in an applet.
Suppose you want to show the days of the week in the form of a list. That could
be done quite simply in the following way:
/* simple program to show
the days of the week */
import java.applet.*;
import java.awt.*;
public class SimpleDays extends Applet {
public void init ( ) {
setBackground (Color.gray);
}
public void paint (Graphics g) {
Font large = new Font ("Arial", Font.BOLD, 20);
g.setFont (large);
g.setColor (Color.yellow);
g.drawString
("Monday", 50, 40);
g.drawString
("Tuesday", 50, 70);
g.drawString
("Wednesday", 50, 100);
g.drawString
("Thursday", 50, 130);
g.drawString
("Friday", 50, 160);
g.drawString
("Saturday", 50, 190);
g.drawString
("Sunday", 50, 220);
}
}
The program is not very complicated. It starts with comment -- which is marked
by
/*
and
*/:
/* simple program to show
the days of the week */
In the method paint, the
words
Monday through Sunday
are shown in yellow letters
on a gray background (which we turned on in
init), like this:
More efficient data
handling
The days-of-the-week program does work, but it's not very efficient.
Suppose we don't want to show seven but hundreds of data, we should really
organize our program differently.
It would be more efficient to put the days of the week in an array. In
that case the method paint
would start looking like this:
public void paint (Graphics g) {
String days[ ] = {"Mon",
"Tues", "Wednes",
"Thurs",
"Fri", "Satur", "Sun"};
Font large = new Font ("Arial", Font.BOLD, 20);
g.setFont (large);
g.setColor (Color.yellow);
for (int i=0; i<7; i++)
g.drawString (days[i] + "day", 50,
40 + i * 30);
}
The way in which the days are
displayed works like this: we use a for-lus to assign the
values 0 through 6 to the variable i.
The value of days[0]
is
"Mon", days[1]
is
"Tues", and so on to
days[6], which has the value
"Sun".
Each of the days
contains the part "day".
We don't store this part seven times, but prefer to "stick" it on to the
string by the time it's going to be displayed.
The program does not contain a lot of data. Still, we've managed to make it shorter than the first version. It's clear that the more data it
contains, the more program text we can save in this way.
But this program can be improved in more ways. But first something completely
different ...
Font size
Generally, there are two ways in which we can make a button. The first
was discussed in chapter
6, the prefab Java-Button:
The second way is by clicking certain parts of the applet window and make
the program interpret this in a certain way, for instance like this:
// a Button that can be 'read' with mouseListener
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class AboveOrBelow extends Applet
implements MouseListener {
int clickY=9999;
public void init () {
setBackground (Color.gray);
addMouseListener (this);
}
public void paint (Graphics g) {
Dimension d = getSize();
int height = d.height, width=d.width;
g.setColor (Color.yellow);
g.setFont (new Font
("Verdana",Font.BOLD, 16));
g.drawLine(0,height/2,width,height/2);
String tl = " de lijn.";
if (clickY==9999)
g.drawString ("click
above or below "+tl,20,height/4);
else if (clickY<height/2)
g.drawString
("Clicked above"+tl,20,height/4);
else if (clickY<height/2)
g.drawString
("Clicked below"+tl,20,3*height/4);
else
g.drawString
("Clicked on"+tl,20,height/2);
}
public void mousePressed (MouseEvent evt) {
clickY = evt.getY();
repaint();
}
public void mouseReleased (MouseEvent evt){}
public void mouseEntered (MouseEvent evt){}
public void mouseExited (MouseEvent evt){}
public void mouseClicked (MouseEvent evt){}
}
In paint, the window is divided by a straight
line
into a lower and a higher part.
Once the window is clicked, the method evt.getY in
mousePressed will capture the y-coordinate,
which is assigned to the global variable clickY.
Thus
in paint it can be determined whether the
click took place above or below the line. The working program looks like
this:
Often you will want to put a text on such a button. It goes without saying
that such a text should fit nicely -- so not anything like these
here:
It will usually look best if the text covers the greater part of the button
width.
We can write a method that will display such a button. This method should
have five arguments
- x-coordinate
- y-coordinate
- width
- height
- text
Apart from the method buttonClicked, a second
method would come in handy (buttonClicked),
which can be used to determine whether the button has actually been clicked:
// method to make a button with text // and how to display centered text
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class ButtonWithText extends Applet
implements MouseListener {
int clickX, clickY, winWi, winHi; // vensterbreedte, -hoogte
boolean putText = false;
public void init () {
setBackground (Color.pink);
addMouseListener (this);
}
void makeButton (int x, int y, int wi, int hi, String s) {
int fg=1, len;
FontMetrics fm;
Graphics g = getGraphics();
g.setColor (Color.gray);
g.fillRect (x+3, y+3, wi, hi);
g.setColor (Color.red);
g.fillRect (x-3, y-3, wi, hi);
g.setColor (Color.black);
g.drawRect (x-3, y-3, wi, hi);
do {
g.setFont (new Font ("Verdana",Font.BOLD, fg++));
} while (g.getFontMetrics().stringWidth(s)<wi-14);
fg--;
g.setFont (new Font ("Verdana",Font.BOLD, fg));
g.setColor (Color.yellow);
len = g.getFontMetrics().stringWidth(s);
g.drawString (s, x-3+wi/2-len/2, y-3+hi/2+fg/2);
}
boolean buttonClicked (int x, int y, int wi, int hi) {
if (clickX>x-3 && clickY<x-3+wi
&& clickY>y-3 && clickY<y+hi)
return true;
else
return false;
}
public void paint (Graphics g) {
Dimension d = getSize();
winHi = d.height; winWi=d.width;
int strW;
makeButton (winWi/4, winHi/4, winWi/2, winHi/3, "click here");
String txt[ ] = {"Demo of stringWidth", "(class: FontMetrics)"};
if (buttonClicked (winWi/4, winHi/4, winWi/2, winHi/3)
&& putText) {
for (int i=0; i<2; i++) {
g.setColor (Color.black);
g.setFont (new Font ("Verdana",Font.BOLD, 20));
strW = g.getFontMetrics().stringWidth(txt[i]);
g.drawString (txt[i], winWi/2-strW/2, (10+i*2)*winHi/13);
}
}
}
public void mousePressed (MouseEvent evt) {
clickX = evt.getX();
clickY = evt.getY();
putText = !putText;
repaint();
}
public void mouseReleased (MouseEvent evt){}
public void mouseEntered (MouseEvent evt){}
public void mouseExited (MouseEvent evt){}
public void mouseClicked (MouseEvent evt){}
}
Once
the mouse has been clicked, the program will go to
mousePressed, where the x and y coordinates will be assigned to the
(globally declared) clickX and
clickY.
The boolean variable
putText will assume its opposite value (the exclamation
mark means: not). In other words, if it is true,
it will become false, and vice versa.
When the program encounters repaint()
, it will go to
paint, where a new button is painted by
makeButton
and buttonClicked
will check whether the area of the button has been clicked.
Finally if putText equals true, two new texts
will be painted.
"Packing" a string-array
We return to our days-of-the-week program, which can be improved in at least
one more way. The data in the following program line consist of 51 characters,
22 of which are commas, quotes and curly braces. That's over
40% of the characters typed.
String days[ ] = {"Mon","Tues","Wednes","Thurs","Fri","Satur","Sun"};
We could "pack" the days into a string of which the words are
separated by just one character, for instance like this:
String s = "Mon-Tues-Wednes-Thurs-Fri-Satur-Sun";
It's possible to "unpack" this string to an array. For this end we
have the class StringTokenizer.
In order to use this class, we first have to insert the following line into
the beginning of our applet program:
import java.util.StringTokenizer;
First we have to define an object (in this case: st)
of this class, which needs two arguments: the name of the string to be
unpacked and the separator character (hyphen in this case).
StringTokenizer st = new StringTokenizer (s,
"-");
The elements are added to the array in the following way:
String days[ ] = new String [7];
int counter = 0;
while (st.hasMoreTokens( )) {
days[counter++] = st.nextToken( );
}
Displaying a whole text
As we have seen above, the method stringWidth
can be used to get text to fit into a certain space.
If you have to display a larger amount of text, it's useful to decide word by
word whether the text still fits into the available space.
We are going to do this in the last program of this chapter, in which text
consisting of a few hundred words is displayed inside the applet window:
// Demonstration of the class StringTokenizer
import java.util.StringTokenizer;
import java.applet.*;
import java.awt.*;
public class DisplayingText extends Applet {
public void init () {
setBackground (Color.gray);
}
public void paint (Graphics g) {
String s = "Of course, the machine language program (the "+
"executable) depends on the kind of system that we want "+
"to run it on: the program contains instructions to one "+
"specific processor and calls to one specific operating "+
"system. Such programs usually run on just one system; a "+
"program that runs well on Windows is useless on other sy"+
"stems, such as Unix or MacOS. It wouldn't make much sens"+
"e either to have these kinds of programs executed on the"+
" Internet. After all, the Internet is populated by all "+
"kinds of computer systems. If you would like to use such "+
"a (conventional) program to enliven your homepage, you "+
"would have to upload versions for Linux, Windows and va"+
"rious other systems. There is, however, another problem: "+
"Internet users can't risk downloading unknown programs "+
"and then allow them to run on their system. Who, for ins"+
"tance, will guarantee that a program downloaded from the "+
"Internet will not start formatting the hard-disk. To bot"+
"h problems Java offers a solution.";
String words[] = new String[500];
StringTokenizer st = new StringTokenizer (s," ");
int number = 0;
while (st.hasMoreTokens()) {
// begin
words[number++] = st.nextToken();
}
Dimension d = getSize();
int width = d.width, i = 0, height = 18;
g.setColor (Color.yellow);
g.setFont (new Font ("Arial", Font.PLAIN, 18));
String line = "";
FontMetrics fm = g.getFontMetrics();
while (i < number) {
if (fm.stringWidth(line+" "+words[i]) < width-width/10) {
line += " " + words[i];
i++;
}
else {
g.drawString (line, width/20, height+=25);
line = "";
}
}
g.drawString (line, width/20, height+=25);
// end
}
}
There is no technical objection why the string s
could not be written as one long line. But this might get outside the
boundaries of a program editor, which might be somewhat awkward.
The actual process of displaying text takes place between the lines marked
by //begin
and //end. Repeatedly, checks are made whether
a line including the next word still fits into 9/10 of the width of the
window.
If it does, we add this word to line.
But if it doesn't fit, we display the line (without the word checked last) , we
increase the height for the next line, after
which we start with an empty line.
What this looks like in practice, can be seen here:
Of course, it's also possible to align text on both
sides. A program that does that may be a little too complicated for
this tutorial. But for those who are interested, I'll give the program here
anyway:
// Demonstration of the class StringTokenizer
// and right and left side aligning of text
import java.applet.*;
import java.awt.*;
import java.util.StringTokenizer;
public class DisplayingText2 extends Applet {
public void init () {
setBackground (Color.gray);
}
public void paint (Graphics g) {
String s = "Of course, the machine language program (the "+
"executable) depends on the kind of system that we want "+
"to run it on: the program contains instructions to one "+
"specific processor and calls to one specific operating "+
"system. Such programs usually run on just one system; a "+
"program that runs well on Windows is useless on other sy"+
"stems, such as Unix or MacOS. It wouldn't make much sens"+
"e either to have these kinds of programs executed on the"+
" Internet. After all, the Internet is populated by all "+
"kinds of computer systems. If you would like to use such "+
"a (conventional) program to enliven your homepage, you "+
"would have to upload versions for Linux, Windows and va"+
"rious other systems. There is, however, another problem: "+
"Internet users can't risk downloading unknown programs "+
"and then allow them to run on their system. Who, for ins"+
"tance, will guarantee that a program downloaded from the "+
"Internet will not start formatting the hard-disk. To bot"+
"h problems Java offers a solution.";
String words[] = new String[200];
StringTokenizer st = new StringTokenizer (s," ");
int number = 0;
while (st.hasMoreTokens()) {
words[number++] = st.nextToken();
}
Dimension d = getSize();
int width = d.width, height = 30;
g.setColor (Color.yellow);
g.setFont (new Font ("Arial", Font.PLAIN, 18));
String line = words[0];
int first=0, last=0, w, pos[] = new int[20], p=1;
pos[0] = 0;
int space = 9*width/10;
FontMetrics fm = g.getFontMetrics();
int index = 1;
while (index < number) {
if (fm.stringWidth(line+" "+words[index]) <= space) {
pos[p++] = fm.stringWidth(line+" ");
line += " " + words[index];
last = index;
index++;
}
else {
int begin = 1;
for (int gap=space-fm.stringWidth(line); gap>0; gap--) {
if (pos[begin]==0)
begin = 1;
for (w=begin; pos[w]>0; w++)
pos[w]++;
begin++;
}
p = 0;
for (w=first; w<=last; w++) {
g.drawString (words[w], width/20+pos[p], height);
p++;
}
line = words[index];
first = index;
index++;
for (p=0; p<pos.length; p++)
pos[p]=0;
height+=25;
p = 1;
}
}
g.drawString (line, width/20, height);
}
}
Here too, I'll show you what it looks like:
Exercise 12.1
Write a program that displays a grey rectangle on a black background in the
center of the screen. In it, your name in yellow letters should be
displayed, which fits exactly oin the right and left. The width of your name
should be between 40 and 50 percent of the applet window (in any browser)
for instance like this:
Exercise 12.2
Copyright-notices are often found in small lettering in the bottom right
hand corner. Expand the previous program so that a copyright notice of about 140
by 160 pixels width comes into the bottom right hand corner, for instance
like this:
Exercise 12.3
Rewrite exercise 12.2 so that the font sizes of the large text and the small
one are determined in a method which finds out the maximum font size which
allows a certain text still fits into a certain available space, and which
may look like this:
int fixFontSize (Graphics
g, String text, int space)
Chapter 14
Menu Java Tutorial
home page
(c) 2003, Thomas J.H. Luif
| |