Posted on 2009-12-12 15:17
啥都寫點 閱讀(469)
評論(0) 編輯 收藏 所屬分類:
J2SE
本例實現了一個Web瀏覽器,類似于Windows的Internet Explorer,但是功能相對簡單一些,能顯示HTML網頁、前進、后退、刷新、訪問主頁和新建窗口,當所有窗口關閉時,程序結束。

javax.swing.JEditorPane文本控件支持純文本、HTML文本、RTF文本的顯示,可以用它來顯示HTML網頁。

JEditorPane的setPage方法加載URL,當加載完畢后,觸發PropertyChangeListener事件,通過addPropertyChangeListener方法為JEditorPane注冊屬性改變事件處理器。

為了使得網頁上的超鏈接生效,必須通過addHyperlinkListener為JEditorPane注冊超鏈接事件處理器。

/** *//**---------------------------------WebBrowser.java----------------------------------------*/

package book.net.url;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;


/** *//**
* 實現一個簡單的Web瀏覽器,支持HTML和HTM頁面的顯示。使用了JEditorPane組件
**/
public class WebBrowser extends JFrame implements HyperlinkListener,

PropertyChangeListener
{

/** *//**下面是使用的Swing組件**/
// 顯示HTML的面板
JEditorPane textPane;
// 最底下的狀態欄
JLabel messageLine;
// 網址URL輸入欄
JTextField urlField;
// 文件選擇器,打開本地文件時用
JFileChooser fileChooser;
// 后退和前進 按鈕
JButton backButton;
JButton forwardButton;

// 保存歷史記錄的列表
java.util.List history = new ArrayList();
// 當前頁面的在歷史記錄列表中位置
int currentHistoryPage = -1;
// 當歷史記錄超過MAX_HISTORY時,清除舊的歷史
public static final int MAX_HISTORY = 50;

// 當前已經打開的瀏覽器窗口數
static int numBrowserWindows = 0;
// 標識當所有瀏覽器窗口都被關閉時,是否退出應用程序
static boolean exitWhenLastWindowClosed = false;

// 默認的主頁
String home = "http://www.google.com";


/** *//**
* 構造函數
*/

public WebBrowser()
{
super("WebBrowser");

// 新建顯示HTML的面板,并設置它不可編輯
textPane = new JEditorPane();
textPane.setEditable(false);

// 注冊事件處理器,用于超連接事件。
textPane.addHyperlinkListener(this);
// 注冊事件處理器,用于處理屬性改變事件。當頁面加載結束時,觸發該事件
textPane.addPropertyChangeListener(this);

// 將HTML顯示面板放入主窗口,居中顯示
this.getContentPane().add(new JScrollPane(textPane),
BorderLayout.CENTER);

// 創建狀態欄標簽,并放在主窗口底部
messageLine = new JLabel(" ");
this.getContentPane().add(messageLine, BorderLayout.SOUTH);

// 初始化菜單和工具欄
this.initMenu();
this.initToolbar();
// 將當前打開窗口數增加1
WebBrowser.numBrowserWindows++;
// 當關閉窗口時,調用close方法處理

this.addWindowListener(new WindowAdapter()
{

public void windowClosing(WindowEvent e)
{
close();
}
});
}

/** *//**
* 初始化菜單欄
*/

private void initMenu()
{
// 文件菜單,下面有四個菜單項:新建、打開、關閉窗口、退出
JMenu fileMenu = new JMenu("文件");
fileMenu.setMnemonic('F');
JMenuItem newMenuItem = new JMenuItem("新建");
newMenuItem.setMnemonic('N');
// 當“新建”時打開一個瀏覽器窗口

newMenuItem.addActionListener(new ActionListener()
{

public void actionPerformed(ActionEvent e)
{
newBrowser();
}
});
JMenuItem openMenuItem = new JMenuItem("打開");
openMenuItem.setMnemonic('O');
// 當“打開”是打開文件選擇器,選擇待打開的文件

openMenuItem.addActionListener(new ActionListener()
{

public void actionPerformed(ActionEvent e)
{
openLocalPage();
}
});
JMenuItem closeMenuItem = new JMenuItem("關閉窗口");
closeMenuItem.setMnemonic('C');
// 當“關閉窗口”時關閉當前窗口

closeMenuItem.addActionListener(new ActionListener()
{

public void actionPerformed(ActionEvent e)
{
close();
}
});
JMenuItem exitMenuItem = new JMenuItem("退出");
exitMenuItem.setMnemonic('E');
// 當“退出”時退出應用程序

exitMenuItem.addActionListener(new ActionListener()
{

public void actionPerformed(ActionEvent e)
{
exit();
}
});
fileMenu.add(newMenuItem);
fileMenu.add(openMenuItem);
fileMenu.add(closeMenuItem);
fileMenu.add(exitMenuItem);
//幫助菜單,就一個菜單項:關于
JMenu helpMenu = new JMenu("幫助");
fileMenu.setMnemonic('H');
JMenuItem aboutMenuItem = new JMenuItem("關于");
aboutMenuItem.setMnemonic('A');
helpMenu.add(aboutMenuItem);
JMenuBar menuBar = new JMenuBar();
menuBar.add(fileMenu);
menuBar.add(helpMenu);
// 設置菜單欄到主窗口
this.setJMenuBar(menuBar);
}

/** *//**
* 初始化工具欄
*/

private void initToolbar()
{
// 后退按鈕,退到前一頁面。初始情況下該按鈕不可用
backButton = new JButton("后退");
backButton.setEnabled(false);

backButton.addActionListener(new ActionListener()
{

public void actionPerformed(ActionEvent e)
{
back();
}
});
// 前進按鈕,進到前一頁面。初始情況下該按鈕不可用
forwardButton = new JButton("前進");
forwardButton.setEnabled(false);

forwardButton.addActionListener(new ActionListener()
{

public void actionPerformed(ActionEvent e)
{
forward();
}
});
// 前進按鈕,進到前一頁面。初始情況下該按鈕不可用
JButton refreshButton = new JButton("刷新");

refreshButton.addActionListener(new ActionListener()
{

public void actionPerformed(ActionEvent e)
{
reload();
}
});
// 主頁按鈕,打開主頁
JButton homeButton = new JButton("主頁");

homeButton.addActionListener(new ActionListener()
{

public void actionPerformed(ActionEvent e)
{
home();
}
});
JToolBar toolbar = new JToolBar();
toolbar.add(backButton);
toolbar.add(forwardButton);
toolbar.add(refreshButton);
toolbar.add(homeButton);

// 輸入網址的文本框
urlField = new JTextField();
// 當用戶輸入網址、按下回車鍵時,觸發該事件

urlField.addActionListener(new ActionListener()
{

public void actionPerformed(ActionEvent e)
{
displayPage(urlField.getText());
}
});

// 地址標簽
toolbar.add(new JLabel(" 地址:"));
toolbar.add(urlField);

// 將工具欄放在主窗口的北部
this.getContentPane().add(toolbar, BorderLayout.NORTH);
}


/** *//**
* 設置瀏覽器是否在所有窗口都關閉時退出
* @param b
*/

public static void setExitWhenLastWindowClosed(boolean b)
{
exitWhenLastWindowClosed = b;
}


/** *//**
* 設置主頁
* @param home 新主頁
*/

public void setHome(String home)
{
this.home = home;
}

/** *//**
* 獲取主頁
*/

public String getHome()
{
return home;
}


/** *//**
* 訪問網址URL
*/

private boolean visit(URL url)
{

try
{
String href = url.toString();
// 啟動動畫,當網頁被加載完成時,觸發propertyChanged事件,動畫停止。
startAnimation("加載 " + href + "
");
// 設置顯示HTML面板的page屬性為待訪問的URL,
// 在這個方法里,將打開URL,將URL的流顯示在textPane中。
// 當完全打開后,該方法才結束。
textPane.setPage(url);
// 頁面打開后,將瀏覽器窗口的標題設為URL
this.setTitle(href);
// 網址輸入框的內容也設置為URL
urlField.setText(href);
return true;

} catch (IOException ex)
{
// 停止動畫
stopAnimation();
// 狀態欄中顯示錯誤信息
messageLine.setText("不能打開頁面:" + ex.getMessage());
return false;
}
}


/** *//**
* 瀏覽器打開URL指定的頁面,如果成功,將URL放入歷史列表中
*/

public void displayPage(URL url)
{
// 嘗試訪問頁面

if (visit(url))
{
// 如果成功,則將URL放入歷史列表中。
history.add(url);
int numentries = history.size();

if (numentries > MAX_HISTORY+10)
{
history = history.subList(numentries-MAX_HISTORY, numentries);
numentries = MAX_HISTORY;
}
// 將當前頁面下標置為numentries-1
currentHistoryPage = numentries - 1;
// 如果當前頁面不是第一個頁面,則可以后退,允許點擊后退按鈕。

if (currentHistoryPage > 0)
{
backButton.setEnabled(true);
}
}
}


/** *//**
* 瀏覽器打開字符串指定的頁面
* @param href 網址
*/

public void displayPage(String href)
{

try
{
// 默認為HTTP協議

if (!href.startsWith("http://"))
{
href = "http://" + href;
}
displayPage(new URL(href));
}

catch (MalformedURLException ex)
{
messageLine.setText("錯誤的網址: " + href);
}
}


/** *//**
* 打開本地文件
*/

public void openLocalPage()
{
// 使用“懶創建”模式,當需要時,才創建文件選擇器。

if (fileChooser == null)
{
fileChooser = new JFileChooser();
// 使用文件過濾器限制只能夠HTML和HTM文件

FileFilter filter = new FileFilter()
{

public boolean accept(File f)
{
String fn = f.getName();

if (fn.endsWith(".html") || fn.endsWith(".htm"))
{
return true;

}else
{
return false;
}
}

public String getDescription()
{
return "HTML Files";
}
};
fileChooser.setFileFilter(filter);
// 只允許選擇HTML和HTM文件
fileChooser.addChoosableFileFilter(filter);
}

// 打開文件選擇器
int result = fileChooser.showOpenDialog(this);
// 如果確定打開文件,則在當前窗口中打開選擇的文件

if (result == JFileChooser.APPROVE_OPTION)
{
File selectedFile = fileChooser.getSelectedFile( );

try
{
displayPage(selectedFile.toURL());

} catch (MalformedURLException e)
{
e.printStackTrace();
}
}
}

/** *//**
* 后退,回到前一頁
*/

public void back()
{

if (currentHistoryPage > 0)
{
// 訪問前一頁
visit((URL)history.get(--currentHistoryPage));
}
// 如果當前頁面下標大于0,允許后退
backButton.setEnabled((currentHistoryPage > 0));
// 如果當前頁面下標不是最后,允許前進
forwardButton.setEnabled((currentHistoryPage < history.size()-1));
}

/** *//**
* 前進,回到后一頁
*/

public void forward()
{

if (currentHistoryPage < history.size( )-1)
{
visit((URL)history.get(++currentHistoryPage));
}
// 如果當前頁面下標大于0,允許后退
backButton.setEnabled((currentHistoryPage > 0));
// 如果當前頁面下標不是最后,允許前進
forwardButton.setEnabled((currentHistoryPage < history.size()-1));
}

/** *//**
* 重新加載當前頁面
*/

public void reload()
{

if (currentHistoryPage != -1)
{
// 先顯示為空白頁
textPane.setDocument(new javax.swing.text.html.HTMLDocument());
// 再訪問當前頁
visit((URL)history.get(currentHistoryPage));
}
}

/** *//**
* 顯示主頁
*/

public void home()
{
displayPage(getHome());
}

/** *//**
* 打開新的瀏覽器窗口
*/

public void newBrowser()
{
WebBrowser b = new WebBrowser();
// 新窗口大小和當前窗口一樣大
b.setSize(this.getWidth(), this.getHeight());
b.setVisible(true);
}

/** *//**
* 關閉當前窗口,如果所有窗口都關閉,則根據exitWhenLastWindowClosed屬性,
* 判斷是否退出應用程序
*/

public void close()
{
// 先隱藏當前窗口,銷毀窗口中的組件。
this.setVisible(false);
this.dispose();
// 將當前打開窗口數減1。
// 如果所有窗口都已關閉,而且exitWhenLastWindowClosed為真,則退出
// 這里采用了synchronized關鍵字,保證線程安全

synchronized(WebBrowser.class)
{
WebBrowser.numBrowserWindows--;

if ((numBrowserWindows==0) && exitWhenLastWindowClosed)
{
System.exit(0);
}
}
}

/** *//**
* 退出應用程序
*/

public void exit()
{
// 彈出對話框,請求確認,如果確認退出,則退出應用程序
if ((JOptionPane.showConfirmDialog(this, "你確定退出Web瀏覽器?", "退出",

JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
{
System.exit(0);
}
}

/** *//**
* 實現HyperlinkListener接口。處理超連接事件
*/

public void hyperlinkUpdate(HyperlinkEvent e)
{
// 獲取事件類型
HyperlinkEvent.EventType type = e.getEventType();
// 如果是點擊了一個超連接,則顯示被點擊的連接

if (type == HyperlinkEvent.EventType.ACTIVATED)
{
displayPage(e.getURL());
}
// 如果是鼠標移動到超連接上,則在狀態欄中顯示超連接的網址

else if (type == HyperlinkEvent.EventType.ENTERED)
{
messageLine.setText(e.getURL().toString());
}
// 如果是鼠標離開了超連接,則狀態欄顯示為空

else if (type == HyperlinkEvent.EventType.EXITED)
{
messageLine.setText(" ");
}
}


/** *//**
* 實現PropertyChangeListener接口。處理屬性改變事件。
* 顯示HTML面板textPane的屬性改變時,由該方法處理。
* 當textPane調用完setPage方法時,page屬性便改變了。
*/

public void propertyChange(PropertyChangeEvent e)
{

if (e.getPropertyName().equals("page"))
{
// 頁面加載完畢時,textPane的page屬性發生改變,此時停止動畫。
stopAnimation();
}
}

// 動畫消息,顯示在最底下狀態欄標簽上,用于反饋瀏覽器的狀態
String animationMessage;
// 動畫當前的幀的索引
int animationFrame = 0;
// 動畫所用到的幀,是一些字符。

String[] animationFrames = new String[]
{
"-", "\\", "|", "/", "-", "\\", "|", "/",
",", ".", "o", "0", "O", "#", "*", "+"
};


/** *//**
* 新建一個Swing的定時器,每個125毫秒更新一次狀態欄標簽的文本
*/
javax.swing.Timer animator =

new javax.swing.Timer(125, new ActionListener()
{

public void actionPerformed(ActionEvent e)
{
animate();
}
});


/** *//**
* 顯示動畫的當前幀到狀態欄標簽上,并將幀索引后移
*/

private void animate()
{
String frame = animationFrames[animationFrame++];
messageLine.setText(animationMessage + " " + frame);
animationFrame = animationFrame % animationFrames.length;
}


/** *//**
* 啟動動畫
*/

private void startAnimation(String msg)
{
animationMessage = msg;
animationFrame = 0;
// 啟動定時器
animator.start();
}


/** *//**
* 停止動畫
*/

private void stopAnimation()
{
// 停止定時器
animator.stop();
messageLine.setText(" ");
}

public static void main(String[] args) throws IOException
{
// 設置瀏覽器,當所有瀏覽器窗口都被關閉時,退出應用程序
WebBrowser.setExitWhenLastWindowClosed(true);
// 創建一個瀏覽器窗口
WebBrowser browser = new WebBrowser();
// 設置瀏覽器窗口的默認大小
browser.setSize(800, 600);
// 顯示窗口
browser.setVisible(true);

// 打開主頁
browser.displayPage(browser.getHome());
}
}
--
學海無涯