-
ContainerEvent
: Container加入或移除Component, 也很少用
-
FocusEvent
: Gain or Lose Focus
-
InputEvent
: 有兩個子類別
-
PaintEvent
: 供AWT內部使用, 不用管他
-
WindowEvent
: 視窗狀態改變
-
HierarchyEvent
: AWT自動處理, 不用管他
-
InputMethodEvent
-
InvocationEvent
: 由AWT event dispatcher thread呼叫Runnable物件裡的run()
-
ItemEvent
: an item was selected or deselected
-
TextEvent
: an object's text changed
以上的Event都有相對應的Listener Interface來處理, 如ActionEvent相對應的是
ActionListener
import
java.awt.*;
import
java.awt.event.*;
public class
OXMain
extends
Frame
implements
ActionListener
{
private
OX oxBoard;
private
OXMain() {
super
("井字遊戲");
Menu
m;
MenuBar
mb;
oxBoard =
new
OX(this);
this
.add(oxBoard);
CloseWindow close = new CloseWindow(
this
, true);
this
.setMenuBar(mb = new
MenuBar
());
mb.add(m =
new
Menu
("遊戲")).add(
new
MenuItem
("新遊戲")).addActionListener(
this
);
m.add(
new
MenuItem
("結束")).addActionListener(close);
mb.add(
new
Menu
("說明")).add(
new
MenuItem
("關於本遊戲")).addActionListener(
this
);
this
.addWindowListener(close);
pack();
setVisible(true);
public static void
main(
String
argv[]) {
new
OXMain();
// implements the ActionListener interface
public void
actionPerformed(
ActionEvent
e) {
String
command = e.getActionCommand();
if
(command.equals("關於本遊戲")) {
new
ErrorDialog(
this
,"俞旭昇寫好玩的");
}
else if
(command.equals("新遊戲")) {
oxBoard.newGame();
class
OX
extends
Component
implements
MouseListener
{
public static final byte
EMPTY = 0;
public static final byte
CIRCLE = 1;
public static final byte
CROSS = 2;
private byte
[] board = new byte[9];
private byte
playing = CIRCLE;
private
Dimension
mySize =
new
Dimension
(300,300);
private
Frame
parent;
private byte
[][] directions = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
public
OX(
Frame
p) {
this
.addMouseListener(
this
);
parent = p;
// The following 5 functions implement the MouseListener interface
public void
mouseClicked(
MouseEvent
e) {}
public void
mouseEntered(
MouseEvent
e) {}
public void
mouseExited(
MouseEven
t e) {}
public void
mouseReleased(
MouseEvent
e) {}
public void
mousePressed(
MouseEvent
e) {
int
row = e.getY()/100;
int
col = e.getX()/100;
if
(row >= 3 || col >= 3)
return
;
// 超過邊界
if
(board[row*3+col] == EMPTY) {
// 此位置可以下
board[row*3+col] = playing;
repaint();
// notify Window Manager
// Anyone Win?
for
(
int
i=0; i < directions.length; i++) {
int
j;
for
(j = 0; j < 3 && board[directions[i][j]]==playing; j++) ;
if
(j==3) {
if
(playing == CIRCLE) {
new
ErrorDialog(parent,"圓圈贏了");
}
else if
(playing == CROSS) {
new
ErrorDialog(parent,"叉叉贏了");
this
.newGame();
return
;
playing ^= 0x03;
// override paint() defined in Component
public void
paint(
Graphics
g) {
g.drawLine(0,100,300,100); g.drawLine(0,200,300,200);
g.drawLine(100,0,100,300); g.drawLine(200,0,200,300);
for
(
int
i = 0; i < 3; i++) {
for
(
int
j = 0; j < 3; j++) {
if
(board[i*3+j] == CIRCLE) {
g.drawOval(50+j*100-25,50+i*100-25,50,50);
}
else if
(board[i*3+j] == CROSS) {
g.drawLine(25+j*100,25+i*100,75+j*100,75+i*100);
g.drawLine(75+j*100,25+i*100,25+j*100,75+i*100);
public void
newGame() {
for
(
int
i = 0; i < 3; i++) {
for
(
int
j = 0; j < 3; j++) {
board[i*3+j] = EMPTY;
playing = CIRCLE;
repaint();
// override getPreferredSize defined in Component,
// so that the Component has proper size on screen
public
Dimension
getPreferredSize() {
return
mySize;
// WindowAdapter implements the WindowLister interface
// We extends WindowAdapter to reduce the line numer of code
class
CloseWindow
extends
WindowAdapter
implements
ActionListener
{
private
Window
target;
private boolean
exit;
public
CloseWindow(
Window
target,
boolean
exit) {
this
.target = target;
this
.exit = exit;
public
CloseWindow(
Window
target) {
this
.target = target;
public void
windowClosing(
WindowEvent
e) {
target.dispose();
if
(exit)
System
.exit(0);
public void
actionPerformed(
ActionEvent
e) {
target.dispose();
if
(exit)
System
.exit(0);
class
AddConstraint {
public static void
addConstraint(
Container
container,
Component
component,
int
grid_x,
int
grid_y,
int
grid_width,
int
grid_height,
int
fill,
int
anchor,
double
weight_x,
double
weight_y,
int
top,
int
left,
int
bottom,
int
right) {
GridBagConstraints
c =
new
GridBagConstraints
();
c.gridx = grid_x; c.gridy = grid_y;
c.gridwidth = grid_width; c.gridheight = grid_height;
c.fill = fill; c.anchor = anchor;
c.weightx = weight_x; c.weighty = weight_y;
c.insets = new Insets(top,left,bottom,right);
((
GridBagLayout
)container.getLayout()).setConstraints(component,c);
container.add(component);
class
ErrorDialog
extends
Dialog
{
public
ErrorDialog(
Frame
parent,
String
all[]) {
this
(parent, all, null);
public
ErrorDialog(
Frame
parent,
String
all[],
String
msg) {
super
(parent,"",true);
StringBuffer
sb =
new
StringBuffer
();
for
(
int
i=0; i < all.length; i++) {
sb.append(all[i]);
sb.append('\n');
if
(msg!=null) {
sb.append(msg);
setup(parent, sb.toString());
public
ErrorDialog(
Frame
parent,
String
message) {
super
(parent,"",true);
setup(parent, message);
private void
setup(
Frame
parent,
String
message) {
this
.setLayout(
new
GridBagLayout());
int
row=0, col=0, i, width=0;
Font
font =
new
Font
("Serif", Font.PLAIN, 16);
char c=' ';
for
(i = 0; i < message.length(); i++) {
c = message.charAt(i);
if
(c=='\n') {
row++;
if
(width > col) {
col = width;
width=0;
}
else if
(c == '\t') {
width += 7-width%7;
}
else
{
if
(c > 0x00FF) {
width+=2;
}
else
{
width++;
if
(c!='\n') {
row++;
if
(width > col) {
col = width;
col++;
// 希望視窗出來不要太大或太小
row = (row > 24) ? 24 : row;
if
(row < 5) {
row=5;
if
(col < 20) {
col = 20;
TextArea
tx =
new
TextArea
(message,row,col);
tx.setEditable(false);
tx.setFont(font);
AddConstraint.addConstraint(
this
, tx, 0, 0, 1, 1,
GridBagConstraints
.BOTH,
GridBagConstraints
.NORTHWEST,
1,1,0,0,0,0);
Button
b =
new
Button
("確定");
b.setFont(font);
AddConstraint.addConstraint(
this
, b, 0, 1, 1, 1,
GridBagConstraints
.HORIZONTAL,
GridBagConstraints
.CENTER,
1,0,0,0,0,0);
CloseWindow cw =
new
CloseWindow(
this
);
this
.addWindowListener(cw);
b.addActionListener(cw);
pack();
setVisible(true);
井字遊戲的Swing版本
GUI簡介
GUI是由Component,LayoutManager以及Listener所組成的。Component是畫面的主要組成成分,本身並沒有可見的實體,其子類別才有顯現的效果。如果Component可以放入其他的Component,則這種Component就稱為是Container。Container裡面的Component的排放位置,可以用絕對座標,也可以透過LayoutManager加以調整。使用者以Mouse,Keyboard等操作GUI時,會產生相對應的Event,並由視窗系統將該Event傳遞給程式設計者所指定的Listener。例如使用者以Mouse的左鍵按下Button(一種Component)時,視窗系統會將ActionEvent傳給該Button的ActionListener(設計者實作的物件),由ActionListener決定採取的步驟。這種由使用者觸發的執行動作,和程序式語言由主程式開始呼叫其他程序的模式不同,我們稱之為事件驅動(Event Driven)模式。
AWT(Abstract Window Toolkit, java.awt.*)是JDK 1.0所提出來有關GUI的函式庫,在JDK 1.1時又修改了Event Handling的機制, 成為現在的樣子。當初為了快速開發出AWT, 以符合Java出版的時程, 因此在設計上, 是利用視窗系統已有的GUI元件為主。由於Java原始的設計理念具有跨平台的性質, 因此AWT只好取各家視窗系統(Windows,Open Look, Motif, Machintosh)上元件的交集, 因此AWT頗為陽春。
為了彌補AWT的不足, JDK自1.2以後提供新的JFC(Java Foundation Class)/Swing的程式庫(javax.swing)。Swing是以Java語言所寫出來的, 因此提供了更多樣化而複雜的元件, 如Image JButton, Image JLabel, JTree, JTable, JTabbedPane, JPopupMenu等等。而且由於Swing並不依靠底層的視窗系統畫出元件的外觀, 因此Swing可以讓使用者自行選定其所喜愛的look and feel。
為了讓原先使用AWT的應用程式能改用Swing的程式庫, AWT內所有的元件都有相對應以J開頭的Swing元件, 如Button對應JButton, TextField對應JTextField。原先AWT的程式只要把Source Code裡面的AWT元件前面加上J即可, 其餘Event Handling和LayoutManager均可沿用(除了JFrame, JDialog, JApplet, JWindow等最上層的Container不能直接加入元件, 必須透過getContentPane()取得放置的地方)。
在以下的範例中, 我們主要採用AWT, 並在最後面給一個Swing的範例, 以說明兩者間的相似性。
AWT中直接繼承Component的子類別有
Button
Canvas:空白的方形區域
Checkbox:勾選
Choice:拉下式表單
Container:裡面還可以放入其他Component
Label:可以顯示文字
List:捲軸表單
Scrollbar:捲軸
TextComponent:可用以編輯文字,其子類別有
TextField(單行)
TextArea(多行)
Container的子類別有
Window:最上層的視窗,又有Frame(可以設定MenuBar的獨立視窗), Dialog(必須依附在Frame下的視窗), FileDialog等子類別。
Panel:沒有顯示的容器
ScrollPane: 具有ScrollBar的容器
AWT提供的LayoutManager有
BorderLayout:
CardLayout
FlowLayout:
GridBagLayout:
GridLayout:
AWT定義的Event主要是java.awt.AWTEvent, 其下又有許多子類別(java.awt.event.*)
ActionEvent: component-defined action occured
AdjustmentEvent: ScrollBar被拉動
ComponentEvent:一般不直接使用, 其子類別有
ContainerEvent: Container加入或移除Component, 也很少用
FocusEvent: Gain or Lose Focus
InputEvent: 有兩個子類別
KeyEvent
MouseEvent
PaintEvent: 供AWT內部使用, 不用管他
WindowEvent: 視窗狀態改變
HierarchyEvent: AWT自動處理, 不用管他
InputMethodEvent
InvocationEvent: 由AWT event dispatcher thread呼叫Runnable物件裡的run()
ItemEvent: an item was selected or deselected
TextEvent: an object's text changed
以上的Event都有相對應的Listener Interface來處理, 如ActionEvent相對應的是ActionListener
import java.awt.*;
import java.awt.event.*;
public class OXMain extends Frame implements ActionListener {
private OX oxBoard;
private OXMain() {
super("井字遊戲");
Menu m;
MenuBar mb;
oxBoard = new OX(this);
this.add(oxBoard);
CloseWindow close = new CloseWindow(this, true);
this.setMenuBar(mb = new MenuBar());
mb.add(m = new Menu("遊戲")).add(new MenuItem("新遊戲")).addActionListener(this);
m.add(new MenuItem("結束")).addActionListener(close);
mb.add(new Menu("說明")).add(new MenuItem("關於本遊戲")).addActionListener(this);
this.addWindowListener(close);
pack();
setVisible(true);
public static void main(String argv[]) {
new OXMain();
// implements the ActionListener interface
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("關於本遊戲")) {
new ErrorDialog(this,"俞旭昇寫好玩的");
} else if (command.equals("新遊戲")) {
oxBoard.newGame();
class OX extends Component implements MouseListener {
public static final byte EMPTY = 0;
public static final byte CIRCLE = 1;
public static final byte CROSS = 2;
private byte[] board = new byte[9];
private byte playing = CIRCLE;
private Dimension mySize = new Dimension(300,300);
private Frame parent;
private byte[][] directions = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
public OX(Frame p) {
this.addMouseListener(this);
parent = p;
// The following 5 functions implement the MouseListener interface
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mousePressed(MouseEvent e) {
int row = e.getY()/100;
int col = e.getX()/100;
if (row >= 3 || col >= 3) return; // 超過邊界
if (board[row*3+col] == EMPTY) { // 此位置可以下
board[row*3+col] = playing;
repaint(); // notify Window Manager
// Anyone Win?
for (int i=0; i < directions.length; i++) {
int j;
for (j = 0; j < 3 && board[directions[i][j]]==playing; j++) ;
if (j==3) {
if (playing == CIRCLE) {
new ErrorDialog(parent,"圓圈贏了");
} else if (playing == CROSS) {
new ErrorDialog(parent,"叉叉贏了");
this.newGame();
return;
playing ^= 0x03;
// override paint() defined in Component
public void paint(Graphics g) {
g.drawLine(0,100,300,100); g.drawLine(0,200,300,200);
g.drawLine(100,0,100,300); g.drawLine(200,0,200,300);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i*3+j] == CIRCLE) {
g.drawOval(50+j*100-25,50+i*100-25,50,50);
} else if (board[i*3+j] == CROSS) {
g.drawLine(25+j*100,25+i*100,75+j*100,75+i*100);
g.drawLine(75+j*100,25+i*100,25+j*100,75+i*100);
public void newGame() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i*3+j] = EMPTY;
playing = CIRCLE;
repaint();
// override getPreferredSize defined in Component,
// so that the Component has proper size on screen
public Dimension getPreferredSize() {
return mySize;
// WindowAdapter implements the WindowLister interface
// We extends WindowAdapter to reduce the line numer of code
class CloseWindow extends WindowAdapter implements ActionListener {
private Window target;
private boolean exit;
public CloseWindow(Window target, boolean exit) {
this.target = target;
this.exit = exit;
public CloseWindow(Window target) {
this.target = target;
public void windowClosing(WindowEvent e) {
target.dispose();
if (exit) System.exit(0);
public void actionPerformed(ActionEvent e) {
target.dispose();
if (exit) System.exit(0);
class AddConstraint {
public static void addConstraint(Container container, Component component,
int grid_x, int grid_y, int grid_width, int grid_height,
int fill, int anchor, double weight_x, double weight_y,
int top, int left, int bottom, int right) {
GridBagConstraints c = new GridBagConstraints();
c.gridx = grid_x; c.gridy = grid_y;
c.gridwidth = grid_width; c.gridheight = grid_height;
c.fill = fill; c.anchor = anchor;
c.weightx = weight_x; c.weighty = weight_y;
c.insets = new Insets(top,left,bottom,right);
((GridBagLayout)container.getLayout()).setConstraints(component,c);
container.add(component);
class ErrorDialog extends Dialog {
public ErrorDialog(Frame parent, String all[]) {
this(parent, all, null);
public ErrorDialog(Frame parent, String all[], String msg) {
super(parent,"",true);
StringBuffer sb = new StringBuffer();
for (int i=0; i < all.length; i++) {
sb.append(all[i]);
sb.append('\n');
if (msg!=null) {
sb.append(msg);
setup(parent, sb.toString());
public ErrorDialog(Frame parent, String message) {
super(parent,"",true);
setup(parent, message);
private void setup(Frame parent, String message) {
this.setLayout(new GridBagLayout());
int row=0, col=0, i, width=0;
Font font = new Font("Serif", Font.PLAIN, 16);
char c=' ';
for (i = 0; i < message.length(); i++) {
c = message.charAt(i);
if (c=='\n') {
row++;
if (width > col) {
col = width;
width=0;
} else if (c == '\t') {
width += 7-width%7;
} else {
if (c > 0x00FF) {
width+=2;
} else {
width++;
if (c!='\n') {
row++;
if (width > col) {
col = width;
col++;
// 希望視窗出來不要太大或太小
row = (row > 24) ? 24 : row;
if (row < 5) {
row=5;
if (col < 20) {
col = 20;
TextArea tx = new TextArea(message,row,col);
tx.setEditable(false);
tx.setFont(font);
AddConstraint.addConstraint(this, tx, 0, 0, 1, 1,
GridBagConstraints.BOTH,
GridBagConstraints.NORTHWEST,
1,1,0,0,0,0);
Button b = new Button("確定");
b.setFont(font);
AddConstraint.addConstraint(this, b, 0, 1, 1, 1,
GridBagConstraints.HORIZONTAL,
GridBagConstraints.CENTER,
1,0,0,0,0,0);
CloseWindow cw = new CloseWindow(this);
this.addWindowListener(cw);
b.addActionListener(cw);
pack();
setVisible(true);
井字遊戲的Swing版本
* Program Name: SwingOXMain.java
* Purpose: Showing how to Swing to write 井字遊戲
* Modify Date: 2005/03/29
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SwingOXMain extends JFrame implements ActionListener {
private OX oxBoard;
private SwingOXMain() {
super("井字遊戲");
JMenu m;
JMenuBar mb;
oxBoard = new OX(this);
this.getContentPane().add(oxBoard);
CloseWindow close = new CloseWindow(this, true);
this.setJMenuBar(mb = new JMenuBar());
mb.add(m = new JMenu("遊戲")).add(new JMenuItem("新遊戲")).addActionListener(this);
m.add(new JMenuItem("結束")).addActionListener(close);
mb.add(new JMenu("說明")).add(new JMenuItem("關於本遊戲")).addActionListener(this);
this.addWindowListener(close);
pack();
setVisible(true);
public static void main(String argv[]) {
new SwingOXMain();
// implements the ActionListener interface
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("關於本遊戲")) {
new ErrorDialog(this,"俞旭昇寫好玩的");
} else if (command.equals("新遊戲")) {
oxBoard.newGame();
class OX extends Component implements MouseListener {
public static final byte EMPTY = 0;
public static final byte CIRCLE = 1;
public static final byte CROSS = 2;
private byte[] board = new byte[9];
private byte playing = CIRCLE;
private Dimension mySize = new Dimension(300,300);
private JFrame parent;
private byte[][] directions = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
public OX(JFrame p) {
this.addMouseListener(this);
parent = p;
// The following 5 functions implement the MouseListener interface
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mousePressed(MouseEvent e) {
int row = e.getY()/100;
int col = e.getX()/100;
if (row >= 3 || col >= 3) return; // 超過邊界
if (board[row*3+col] == EMPTY) { // 此位置可以下
board[row*3+col] = playing;
repaint(); // notify Window Manager
// Anyone Win?
for (int i=0; i < directions.length; i++) {
int j;
for (j=0; j &tl; 3 && board[directions[i][j]]==playing; j++) ;
if (j==3) {
if (playing == CIRCLE) {
new ErrorDialog(parent,"圓圈贏了");
} else if(playing == CROSS) {
new ErrorDialog(parent,"叉叉贏了");
this.newGame();
return;
playing ^= 0x03;
// override paint() defined in Component
public void paint(Graphics g) {
g.drawLine(0,100,300,100); g.drawLine(0,200,300,200);
g.drawLine(100,0,100,300); g.drawLine(200,0,200,300);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i*3+j] == CIRCLE) {
g.drawOval(50+j*100-25,50+i*100-25,50,50);
} else if (board[i*3+j] == CROSS) {
g.drawLine(25+j*100,25+i*100,75+j*100,75+i*100);
g.drawLine(75+j*100,25+i*100,25+j*100,75+i*100);
public void newGame() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i*3+j] = EMPTY;
playing = CIRCLE;
repaint();
// override getPreferredSize defined in Component,
// so that the Component has proper size on screen
public Dimension getPreferredSize() {
return mySize;
// WindowAdapter implements the WindowLister interface
// We extends WindowAdapter to reduce the line numer of code
class CloseWindow extends WindowAdapter implements ActionListener {
private Window target;
private boolean exit;
public CloseWindow(Window target, boolean exit) {
this.target = target;
this.exit = exit;
public CloseWindow(Window target) {
this.target = target;
public void windowClosing(WindowEvent e) {
target.dispose();
if (exit) System.exit(0);
public void actionPerformed(ActionEvent e) {
target.dispose();
if (exit) System.exit(0);
class AddConstraint {
public static void addConstraint(Container container, Component component,
int grid_x, int grid_y, int grid_width, int grid_height,
int fill, int anchor, double weight_x, double weight_y,
int top, int left, int bottom, int right) {
GridBagConstraints c = new GridBagConstraints();
c.gridx = grid_x; c.gridy = grid_y;
c.gridwidth = grid_width; c.gridheight = grid_height;
c.fill = fill; c.anchor = anchor;
c.weightx = weight_x; c.weighty = weight_y;
c.insets = new Insets(top,left,bottom,right);
((GridBagLayout)container.getLayout()).setConstraints(component,c);
container.add(component);
文字編輯器
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
public class Editor extends WindowAdapter implements ActionListener {
JFrame topWindow;
JTextArea jta;
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("Open")) {
JFileChooser fd = new JFileChooser(".");
fd.setDialogType(JFileChooser.OPEN_DIALOG);
int returnVal = fd.showOpenDialog(topWindow);
if (returnVal == JFileChooser.APPROVE_OPTION) {
try {
File file = fd.getSelectedFile();
BufferedReader fin = new BufferedReader(new FileReader(file));
StringBuffer sb = new StringBuffer();
String x;
while ((x=fin.readLine()) != null) {
sb.append(x);
sb.append("\n");
jta.setText(sb.toString());
} catch(Exception epp) {}
jta.setCaretPosition(0);
} else if (command.equals("Save")) {
JFileChooser fd = new JFileChooser(".");
fd.setDialogType(JFileChooser.SAVE_DIALOG);
int returnVal = fd.showSaveDialog(topWindow);
if (returnVal == JFileChooser.APPROVE_OPTION) {
try {
File file = fd.getSelectedFile();
FileWriter fout = new FileWriter(file);
fout.write(jta.getText());
fout.close();
} catch(Exception epp) {}
} else if (command.equals("Find")) {
String x = jta.getText();
int at = x.indexOf("int", jta.getCaretPosition());
if (at >= 0) {
jta.setCaretPosition(at);
jta.setSelectionStart(at);
jta.setSelectionEnd(at+3);
} else {
System.out.println("Unknown "+command);
public void windowClosing(WindowEvent e) {
topWindow.dispose();
System.exit(0);
public Editor() {
Font myFont = new Font("細明體", Font.PLAIN, 20);
topWindow = new JFrame("My IDE");
// get the root container of JFrame
Container c = topWindow.getContentPane();
c.setLayout(new GridLayout(1,1));
JMenuBar jmb = new JMenuBar();
JMenu m = new JMenu("File");
m.setFont(myFont);
JMenuItem mi = new JMenuItem("Open");
mi.setFont(myFont);
mi.addActionListener(this);
m.add(mi);
mi = new JMenuItem("Save");
mi.setFont(myFont);
mi.addActionListener(this);
m.add(mi);
mi = new JMenuItem("Find");
mi.setFont(myFont);
mi.addActionListener(this);
m.add(mi);
jmb.add(m);
topWindow.setJMenuBar(jmb);
jta = new JTextArea(24,80);
jta.setFont(myFont);
jta.setCursor(new Cursor(Cursor.HAND_CURSOR));
JScrollPane jsp = new JScrollPane(jta);
c.add(jsp);
topWindow.addWindowListener(this);
topWindow.pack(); // 壓縮到最適當的大小
topWindow.show(); // 顯示JFrame
public static void main(String[] argv) {
new Editor();
鍵盤事件處理範例
/* Program Name: Field.java
Subject: 單一欄位輸入
Author: 俞旭昇 Shiuh-Sheng Yu
National ChiNan University
Department of Information Management
Since 1997/08/17
Last Update Date: 08/23/1998
2003/12/17, fix delete, tab
2004/04/26, 支援jdk1.2以後版本使用Ctrl-C,Ctrl-V複製貼上功能
ToolKit: JDK1.1.6
package ncnu.gui;
import java.awt.*;
import java.awt.event.*;
import java.sql.Types;
import java.awt.datatransfer.*;
import java.io.IOException;
public class Field implements ActionListener, KeyListener, Transferable, ClipboardOwner {
static {
try {
if (System.getProperty("java.version").startsWith("1.1")) {
checkCopy = false;
} else {
checkCopy = true;
} catch(Exception ex) {
public DataFlavor[] getTransferDataFlavors() {
DataFlavor[] myFlavors = new DataFlavor[1];
myFlavors[0] = DataFlavor.stringFlavor;
return myFlavors;
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DataFlavor.stringFlavor);
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return myData;
public void lostOwnership(Clipboard clipboard, Transferable contents) {
static String myData;
static boolean checkCopy;
public static final int OVR=0;
public static final int INS=1;
TextField t;
int limit;
int type;
int decimalDigits;
int mode=0;
KeyJump parent;
public Field(KeyJump parent, TextField t, int limit, int type, int decimalDigits) {
this.t = t;
this.limit = limit;
this.type = type;
this.decimalDigits = decimalDigits;
this.parent = parent;
this.mode = OVR;
t.addActionListener((ActionListener)this);
t.addKeyListener((KeyListener)this);
public void keyPressed(KeyEvent e) {
String s;
int pos,sstart,send;
StringBuffer sb;
switch(e.getKeyCode()) {
case KeyEvent.VK_PASTE:
case KeyEvent.VK_COPY:
case KeyEvent.VK_UNDO:
case KeyEvent.VK_CUT:
case KeyEvent.VK_FIND:
return;
case KeyEvent.VK_INSERT:
if (mode==OVR) {
mode = INS;
} else {
mode = OVR;
e.consume();
break;
case KeyEvent.VK_TAB:
case KeyEvent.VK_ENTER:
case KeyEvent.VK_DOWN:
parent.next(t);
e.consume();
break;
case KeyEvent.VK_UP:
parent.previous(t);
e.consume();
break;
case KeyEvent.VK_LEFT:
case KeyEvent.VK_RIGHT:
case KeyEvent.VK_HOME:
case KeyEvent.VK_END:
return;
case KeyEvent.VK_PAGE_UP:
parent.pageUp(t);
e.consume();
break;
case KeyEvent.VK_PAGE_DOWN:
parent.pageDown(t);
e.consume();
break;
case KeyEvent.VK_DELETE:
e.consume();
if (!t.isEditable()) {
return;
s = t.getText();
pos = t.getCaretPosition();
sstart=t.getSelectionStart();
send=t.getSelectionEnd();
if (send>sstart) {
sb = new StringBuffer(s.substring(0,sstart));
if (send!=s.length()) {
sb.append(s.substring(send));
if ((type==Types.NUMERIC||type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(sstart);
} else {
if (pos==s.length()) {
return;
sb = new StringBuffer(s.substring(0,pos));
sb.append(s.substring(pos+1));
if ((type==Types.NUMERIC || type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(pos);
return;
case KeyEvent.VK_BACK_SPACE:
e.consume();
if (!t.isEditable()) {
return;
s = t.getText();
pos = t.getCaretPosition();
sstart=t.getSelectionStart();
send=t.getSelectionEnd();
if (send>sstart) {
sb = new StringBuffer(s.substring(0,sstart));
if (send!=s.length()) {
sb.append(s.substring(send));
if ((type==Types.NUMERIC||type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(sstart);
} else {
if (pos==0) {
return;
if (pos<=1) {
sb = new StringBuffer();
} else {
sb = new StringBuffer(s.substring(0,pos-1));
sb.append(s.substring(pos));
if ((type==Types.NUMERIC||type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(pos-1);
return;
public void keyTyped(KeyEvent e) {
String s;
int pos,sstart,send;
StringBuffer sb;
if (!t.isEditable()) {
e.consume();
return;
char ch = e.getKeyChar();
// 3copy, 22 paste,127 delete,8 backspace
if (checkCopy) {
if (ch==3) {
e.consume();
s = t.getText();
pos = t.getCaretPosition();
sstart=t.getSelectionStart();
send=t.getSelectionEnd();
if (send>sstart) {
myData = s.substring(sstart,send);
} else {
myData = "";
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(this,this);
if (ch==22) {
e.consume();
Transferable tt = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(this);
if (tt != null) {
String data;
try {
data = (String)tt.getTransferData(DataFlavor.stringFlavor);
} catch(Exception eppp) {
System.out.println(eppp);
return;
s = t.getText();
pos = t.getCaretPosition();
sstart=t.getSelectionStart();
send=t.getSelectionEnd();
if (send>sstart) { // 有選起來
sb = new StringBuffer(s.substring(0,sstart));
sb.append(data);
if (send!=s.length()) {
sb.append(s.substring(send));
if ((type==Types.NUMERIC||type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(sstart);
} else {
sb = new StringBuffer(s.substring(0,pos));
sb.append(data);
if (pos < s.length()) {
sb.append(s.substring(pos));
if ((type==Types.NUMERIC || type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(pos);
if (ch==3 || ch==22 || ch==8 || ch==127 || ch=='\t' || ch=='\n') {
e.consume();
return;
if (ch!=KeyEvent.CHAR_UNDEFINED) {
s = t.getText();
sstart=t.getSelectionStart();
send=t.getSelectionEnd();
if (send > sstart) {
sb = new StringBuffer(s.substring(0,sstart));
sb.append(ch);
if (send!=s.length()) {
sb.append(s.substring(send));
} else {
pos = t.getCaretPosition();
sb = new StringBuffer(s.substring(0,pos));
sb.append(ch);
if (pos!=s.length()) {
if (mode==INS) {
sb.append(s.substring(pos));
} else {
sb.append(s.substring(pos+1));
if ((type==Types.NUMERIC||type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
pos = t.getCaretPosition();
t.setText(inputTruncate(sb.toString()));
t.setCaretPosition(pos+1);
e.consume();
public void keyReleased(KeyEvent e) {
return;
public void actionPerformed(ActionEvent e) {
int currentIndex, i;
TextComponent next;
switch(e.getID()) {
case ActionEvent.ACTION_PERFORMED:
parent.next(t);
break;
default:
break;
protected String inputTruncate(String s) {
int i,j=limit;
if (type==Types.NUMERIC||type==Types.DECIMAL) {
int k=0, leading;
if (decimalDigits==0) {
leading = limit;
} else {
leading = limit-decimalDigits;
if (s.charAt(0)=='-') {
for (; k < leading && k < s.length(); k++) {
if (!(s.charAt(k) >='0' && s.charAt(k) <='9')) {
break;
if (decimalDigits!=0) {
k += decimalDigits+1;
j = k;
if (s.getBytes().length>j) {
for (i=s.length()-1; i > 0 ;i--) {
if (s.substring(0,i).getBytes().length<=j) {
break;
return (s.substring(0,i));
return s;
protected boolean legalNumber(String s) {
int leading;
int i=0,j=0;
if (s.length()==0) {
return true;
if (decimalDigits == 0) {
leading = limit;
} else {
leading = limit - decimalDigits;
if (s.charAt(i)=='-') {
for (;(j < s.length()) && (j < leading); j++) {
if (!(s.charAt(j) >='0' && s.charAt(j) <='9')) {
break;
if (j==s.length()) {
return true;
if (decimalDigits==0) {
return false;
} else {
if (s.charAt(j)=='.') {
for (i=j; i!=s.length() && i-j < decimalDigits; i++) {
if (!(s.charAt(i) >='0' && s.charAt(i) <='9')) {
break;
if (i==s.length()) {
return true;
return false;
文字編輯器
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
public class Editor extends WindowAdapter implements ActionListener {
JFrame topWindow;
JTextArea jta;
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("Open")) {
JFileChooser fd = new JFileChooser(".");
fd.setDialogType(JFileChooser.OPEN_DIALOG);
int returnVal = fd.showOpenDialog(topWindow);
if (returnVal == JFileChooser.APPROVE_OPTION) {
try {
File file = fd.getSelectedFile();
BufferedReader fin = new BufferedReader(new FileReader(file));
StringBuffer sb = new StringBuffer();
String x;
while ((x=fin.readLine()) != null) {
sb.append(x);
sb.append("\n");
jta.setText(sb.toString());
} catch(Exception epp) {}
jta.setCaretPosition(0);
} else if (command.equals("Save")) {
JFileChooser fd = new JFileChooser(".");
fd.setDialogType(JFileChooser.SAVE_DIALOG);
int returnVal = fd.showSaveDialog(topWindow);
if (returnVal == JFileChooser.APPROVE_OPTION) {
try {
File file = fd.getSelectedFile();
FileWriter fout = new FileWriter(file);
fout.write(jta.getText());
fout.close();
} catch(Exception epp) {}
} else if (command.equals("Find")) {
String x = jta.getText();
int at = x.indexOf("int", jta.getCaretPosition());
if (at >= 0) {
jta.setCaretPosition(at);
jta.setSelectionStart(at);
jta.setSelectionEnd(at+3);
} else {
System.out.println("Unknown "+command);
public void windowClosing(WindowEvent e) {
topWindow.dispose();
System.exit(0);
public Editor() {
Font myFont = new Font("細明體", Font.PLAIN, 20);
topWindow = new JFrame("My IDE");
// get the root container of JFrame
Container c = topWindow.getContentPane();
c.setLayout(new GridLayout(1,1));
JMenuBar jmb = new JMenuBar();
JMenu m = new JMenu("File");
m.setFont(myFont);
JMenuItem mi = new JMenuItem("Open");
mi.setFont(myFont);
mi.addActionListener(this);
m.add(mi);
mi = new JMenuItem("Save");
mi.setFont(myFont);
mi.addActionListener(this);
m.add(mi);
mi = new JMenuItem("Find");
mi.setFont(myFont);
mi.addActionListener(this);
m.add(mi);
jmb.add(m);
topWindow.setJMenuBar(jmb);
jta = new JTextArea(24,80);
jta.setFont(myFont);
jta.setCursor(new Cursor(Cursor.HAND_CURSOR));
JScrollPane jsp = new JScrollPane(jta);
c.add(jsp);
topWindow.addWindowListener(this);
topWindow.pack(); // 壓縮到最適當的大小
topWindow.show(); // 顯示JFrame
public static void main(String[] argv) {
new Editor();
鍵盤事件處理範例
/* Program Name: Field.java
Subject: 單一欄位輸入
Author: 俞旭昇 Shiuh-Sheng Yu
National ChiNan University
Department of Information Management
Since 1997/08/17
Last Update Date: 08/23/1998
2003/12/17, fix delete, tab
2004/04/26, 支援jdk1.2以後版本使用Ctrl-C,Ctrl-V複製貼上功能
ToolKit: JDK1.1.6
package ncnu.gui;
import java.awt.*;
import java.awt.event.*;
import java.sql.Types;
import java.awt.datatransfer.*;
import java.io.IOException;
public class Field implements ActionListener, KeyListener, Transferable, ClipboardOwner {
static {
try {
if (System.getProperty("java.version").startsWith("1.1")) {
checkCopy = false;
} else {
checkCopy = true;
} catch(Exception ex) {
public DataFlavor[] getTransferDataFlavors() {
DataFlavor[] myFlavors = new DataFlavor[1];
myFlavors[0] = DataFlavor.stringFlavor;
return myFlavors;
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DataFlavor.stringFlavor);
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return myData;
public void lostOwnership(Clipboard clipboard, Transferable contents) {
static String myData;
static boolean checkCopy;
public static final int OVR=0;
public static final int INS=1;
TextField t;
int limit;
int type;
int decimalDigits;
int mode=0;
KeyJump parent;
public Field(KeyJump parent, TextField t, int limit, int type, int decimalDigits) {
this.t = t;
this.limit = limit;
this.type = type;
this.decimalDigits = decimalDigits;
this.parent = parent;
this.mode = OVR;
t.addActionListener((ActionListener)this);
t.addKeyListener((KeyListener)this);
public void keyPressed(KeyEvent e) {
String s;
int pos,sstart,send;
StringBuffer sb;
switch(e.getKeyCode()) {
case KeyEvent.VK_PASTE:
case KeyEvent.VK_COPY:
case KeyEvent.VK_UNDO:
case KeyEvent.VK_CUT:
case KeyEvent.VK_FIND:
return;
case KeyEvent.VK_INSERT:
if (mode==OVR) {
mode = INS;
} else {
mode = OVR;
e.consume();
break;
case KeyEvent.VK_TAB:
case KeyEvent.VK_ENTER:
case KeyEvent.VK_DOWN:
parent.next(t);
e.consume();
break;
case KeyEvent.VK_UP:
parent.previous(t);
e.consume();
break;
case KeyEvent.VK_LEFT:
case KeyEvent.VK_RIGHT:
case KeyEvent.VK_HOME:
case KeyEvent.VK_END:
return;
case KeyEvent.VK_PAGE_UP:
parent.pageUp(t);
e.consume();
break;
case KeyEvent.VK_PAGE_DOWN:
parent.pageDown(t);
e.consume();
break;
case KeyEvent.VK_DELETE:
e.consume();
if (!t.isEditable()) {
return;
s = t.getText();
pos = t.getCaretPosition();
sstart=t.getSelectionStart();
send=t.getSelectionEnd();
if (send>sstart) {
sb = new StringBuffer(s.substring(0,sstart));
if (send!=s.length()) {
sb.append(s.substring(send));
if ((type==Types.NUMERIC||type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(sstart);
} else {
if (pos==s.length()) {
return;
sb = new StringBuffer(s.substring(0,pos));
sb.append(s.substring(pos+1));
if ((type==Types.NUMERIC || type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(pos);
return;
case KeyEvent.VK_BACK_SPACE:
e.consume();
if (!t.isEditable()) {
return;
s = t.getText();
pos = t.getCaretPosition();
sstart=t.getSelectionStart();
send=t.getSelectionEnd();
if (send>sstart) {
sb = new StringBuffer(s.substring(0,sstart));
if (send!=s.length()) {
sb.append(s.substring(send));
if ((type==Types.NUMERIC||type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(sstart);
} else {
if (pos==0) {
return;
if (pos<=1) {
sb = new StringBuffer();
} else {
sb = new StringBuffer(s.substring(0,pos-1));
sb.append(s.substring(pos));
if ((type==Types.NUMERIC||type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(pos-1);
return;
public void keyTyped(KeyEvent e) {
String s;
int pos,sstart,send;
StringBuffer sb;
if (!t.isEditable()) {
e.consume();
return;
char ch = e.getKeyChar();
// 3copy, 22 paste,127 delete,8 backspace
if (checkCopy) {
if (ch==3) {
e.consume();
s = t.getText();
pos = t.getCaretPosition();
sstart=t.getSelectionStart();
send=t.getSelectionEnd();
if (send>sstart) {
myData = s.substring(sstart,send);
} else {
myData = "";
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(this,this);
if (ch==22) {
e.consume();
Transferable tt = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(this);
if (tt != null) {
String data;
try {
data = (String)tt.getTransferData(DataFlavor.stringFlavor);
} catch(Exception eppp) {
System.out.println(eppp);
return;
s = t.getText();
pos = t.getCaretPosition();
sstart=t.getSelectionStart();
send=t.getSelectionEnd();
if (send>sstart) { // 有選起來
sb = new StringBuffer(s.substring(0,sstart));
sb.append(data);
if (send!=s.length()) {
sb.append(s.substring(send));
if ((type==Types.NUMERIC||type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(sstart);
} else {
sb = new StringBuffer(s.substring(0,pos));
sb.append(data);
if (pos < s.length()) {
sb.append(s.substring(pos));
if ((type==Types.NUMERIC || type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
t.setText(sb.toString());
t.setCaretPosition(pos);
if (ch==3 || ch==22 || ch==8 || ch==127 || ch=='\t' || ch=='\n') {
e.consume();
return;
if (ch!=KeyEvent.CHAR_UNDEFINED) {
s = t.getText();
sstart=t.getSelectionStart();
send=t.getSelectionEnd();
if (send>sstart) {
sb = new StringBuffer(s.substring(0,sstart));
sb.append(ch);
if (send!=s.length()) {
sb.append(s.substring(send));
} else {
pos = t.getCaretPosition();
sb = new StringBuffer(s.substring(0,pos));
sb.append(ch);
if (pos!=s.length()) {
if (mode==INS) {
sb.append(s.substring(pos));
} else {
sb.append(s.substring(pos+1));
if ((type==Types.NUMERIC||type==Types.DECIMAL) && !legalNumber(sb.toString())) {
return;
pos = t.getCaretPosition();
t.setText(inputTruncate(sb.toString()));
t.setCaretPosition(pos+1);
e.consume();
public void keyReleased(KeyEvent e) {
return;
public void actionPerformed(ActionEvent e) {
int currentIndex, i;
TextComponent next;
switch(e.getID()) {
case ActionEvent.ACTION_PERFORMED:
parent.next(t);
break;
default:
break;
protected String inputTruncate(String s) {
int i,j=limit;
if (type==Types.NUMERIC||type==Types.DECIMAL) {
int k=0, leading;
if (decimalDigits==0) {
leading = limit;
} else {
leading = limit-decimalDigits;
if (s.charAt(0)=='-') {
for (; k < leading && k < s.length(); k++) {
if (!(s.charAt(k) >='0' && s.charAt(k) <='9')) {
break;
if (decimalDigits!=0) {
k += decimalDigits+1;
j = k;
if (s.getBytes().length>j) {
for (i=s.length()-1; i > 0 ;i--) {
if (s.substring(0,i).getBytes().length<=j) {
break;
return (s.substring(0,i));
return s;
protected boolean legalNumber(String s) {
int leading;
int i=0,j=0;
if (s.length()==0) {
return true;
if (decimalDigits == 0) {
leading = limit;
} else {
leading = limit - decimalDigits;
if (s.charAt(i)=='-') {
for (;(j < s.length()) && (j < leading); j++) {
if (!(s.charAt(j) >='0' && s.charAt(j) <='9')) {
break;
if (j==s.length()) {
return true;
if (decimalDigits==0) {
return false;
} else {
if (s.charAt(j)=='.') {
for (i=j; i!=s.length() && i-j < decimalDigits; i++) {
if (!(s.charAt(i) >='0' && s.charAt(i) <='9')) {
break;
if (i==s.length()) {
return true;
return false;