精简版web浏览器

import javax.swing.JFrame;
import javax.swing.JEditorPane;
import javax.swing.event.HyperlinkListener;
import java.beans.PropertyChangeListener;
import javax.swing.event.HyperlinkEvent;
import java.beans.PropertyChangeEvent;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JFileChooser;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import java.util.ArrayList;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.filechooser.FileFilter;
import java.io.File;
import javax.swing.JOptionPane;
import javax.swing.JMenuBar;
import javax.swing.text.html.HTMLDocument;
import javax.swing.JToolBar;
import java.io.IOException;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.util.Date;
import java.text.SimpleDateFormat;
/*
【问题1】:点击"主页"按钮后,再次点击,下面文本提示一直在加载,没有返回结果,也没有返回超时
【问题2】:"打开"菜单功能未实现--is ok!
【问题3】:页面链接的 输入类型(HyperlinkEvent.EventType.ENTERED)不起作用--可以支持http://www.baidu.com、http://www.hao123.com
【问题4】:菜单中的快捷键如何使用?--先使用Alt+快捷键进入菜单,接着使用菜单项快捷键打开菜单项
【问题5】:存放打开页面的队列满了是什么情况?
*/

/**
JFrame:顶级容器
JPanel:普通容器
JFrame的结构从里到外(按照图层的叠加顺序)依次为:frame->rootpane->layeredpane->contentpane->menuBar(optional)->glasspane
    frame
        rootpane
            layeredpane
                contentpane:默认是JPanel,一般的组件都放在JPanel
                menuBar
            glasspane:默认是透明的 
*/
public class WebBrowser extends JFrame implements HyperlinkListener,PropertyChangeListener{
    /**
    JEditorPane的最主要功能在于展现不同类型的文件格式内容
    第一种是纯文本类型,其类型的表示法为"text/plain",这种类型的文件就是我们最常使用的txt文件,这类型的文件可以用记事本或WordPad等文书编辑软件来编辑;
    第二种是RTF类型,其表示法为"text/rtf",这种类型的文件特色是能对文字内容做字体缩放、变形、上色等特殊效果;
    第三类是HTML类型,也就是我们在网络上所浏览的网页类型,其表示法为"text/html",这类文件的特色相信大家都非常的清楚,除了在对字体效果的表现之外还具有在文件
    内加入图片、超级链接等相关功能。但是JEditorPane并不是一个全功能的Web Browser,它仅能支持简单的HTML语法.JEditorPane支持HTML类型的文件最主要的用途是用来制作在线辅助说明文件。
    */
    
    /*javax.swing组件*/
    JEditorPane textPane;
    JLabel messageLable;        //contentPane的SOUTH
    JTextField urlField;        //URL单行输入框
    JFileChooser fileChooser;     //文件选择器
    
    /*前进和后退,在Button初始化要用到,在监听事件也要用到,所以作为成员变量*/
    JButton backButton;
    JButton farwardButton;
    
    java.util.List history = new ArrayList();        //保存历史记录的列表
    int currentHistoryPage = -1;                                //当前页面在历史记录列表中的位置
    //属于类仅有一个且为常量,类初始化时已经在内存中生成不可变,不管新建多少个浏览器对象实例,所有浏览器对象打开窗口的总数仅保留最新MAX_HISTORY条
    public static final int MAX_HISTORY = 50;        //历史记录列表超出该值时,按顺序清除多余的历史记录
    //属于类仅有一个,所有类对象实例共用同一个该静态变量
    static int numBrowserWindows = 0;                        //当前已经打开的浏览器窗口数
    
    //标识当所有浏览器窗口都关闭,是否退出程序
    private static boolean exitWhenLastWindowClosed = false ;
    String home = "http://www.google.cn/";            //默认的主页
    
    //构造函数
    public WebBrowser(){
        //super的调用必须是构造器中的第一个语句
        super("WebBrowser");        //构造一个具有指定标题的,默认最初不可见的Frame对象
        textPane = new JEditorPane();        //设置显示HTML的面板,并设置为不可编辑
        textPane.setEditable(false);
        textPane.addHyperlinkListener(this);                    //注册事件处理器,用于超链接事件
        textPane.addPropertyChangeListener(this);            //注册事件处理器,用于处理属性改变事件。当页面加载完成时,触发该事件
        
        this.getContentPane().add(new JScrollPane(textPane), BorderLayout.CENTER);
        messageLable = new JLabel();
        this.getContentPane().add(messageLable, BorderLayout.SOUTH);
        this.initMenu();
        this.initToolBar();
        //浏览器窗口加1
        //numBrowserWindows是属于类的,在创建WebBrowser对象实例前已经在内存中生成
        WebBrowser.numBrowserWindows++;
        //当关闭窗口时,调用close方法处理(Y)
        this.addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent e){
                close();
                }
            });
        }
    
    //初始化菜单栏,只允许子类继承和重写    
    public  void initMenu(){
        JMenu fileMenu = new JMenu("文件");
        //Alt+F
        fileMenu.setMnemonic('F');
        JMenuItem newMenuItem = new JMenuItem("新建");
        //先Alt+F,再N/Alt+N,快捷键有分层级,子菜单的快捷键不能直接使用
        newMenuItem.setMnemonic('N');
        //匿名内部类继承一个父类或者实现一个接口,ActionListener为接口(Y)
        newMenuItem.addActionListener(new ActionListener(){
            //实现该接口的抽象方法
                public void actionPerformed(ActionEvent e){
                    newBrowser();
                    }
            });
        
        JMenuItem openMenuItem = new JMenuItem("打开");
        //先Alt+F,再O/Alt+O,快捷键有分层级,子菜单的快捷键不能直接使用
//        openMenuItem.setMnemonic('O');
        openMenuItem.setMnemonic(KeyEvent.VK_O);
        //匿名内部类继承一个父类或者实现一个接口,ActionListener为接口(Y)
        openMenuItem.addActionListener(new ActionListener(){
            //实现该接口的抽象方法
                public void actionPerformed(ActionEvent e){
                    openLocalPage();
                    }
            });
        
        JMenuItem closeMenuItem = new JMenuItem("关闭");
        //先Alt+F,再C/Alt+C,快捷键有分层级,子菜单的快捷键不能直接使用
        closeMenuItem.setMnemonic('C');
        //匿名内部类继承一个父类或者实现一个接口,ActionListener为接口(Y)
        closeMenuItem.addActionListener(new ActionListener(){
            //实现该接口的抽象方法
                public void actionPerformed(ActionEvent e){
                    close();
                    }
            });
        
        JMenuItem exitMenuItem = new JMenuItem("退出");
        //先Alt+F,再E/Alt+E,快捷键有分层级,子菜单的快捷键不能直接使用
        exitMenuItem.setMnemonic('E');
        //匿名内部类继承一个父类或者实现一个接口,ActionListener为接口(Y)
        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("帮助");
        helpMenu.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 exit(){
        if(JOptionPane.    showConfirmDialog(this, "你确定退出Web浏览器?", "退出",     JOptionPane.YES_NO_OPTION)==JOptionPane.YES_OPTION){
            System.exit(0);
            }
        }
    
    @SuppressWarnings("deprecation")
    private void openLocalPage(){
        if(fileChooser==null){
            fileChooser = new JFileChooser();
            //FileFilter为抽象类,使用内部类创建一个子类实例,实现FileFilter类的抽象方法(Y)
            FileFilter fileFilter = new FileFilter(){
                //File参数是文件过滤器对应类型的文件
                public  boolean    accept(File f){
                    String fileName = f.getName();
                    if((fileName.endsWith("html"))||(fileName.endsWith("htm"))){
                        return true;
                        }else{return false;}
                    }
                public String    getDescription(){
                    return "HTML Files";
                    }
                };
            //设置当前页面默认的文件筛选器    
            fileChooser.setFileFilter(fileFilter);
            //当前页面的默认文件筛选器为系统默认的,仅表示把指定的文件筛选器添加到文件筛选器列表中
            fileChooser.addChoosableFileFilter(fileFilter);
            }
        //Pops up an "Open File" file chooser dialog,在"文件"选择器界面,如果点击"打开"按钮则返回0,如果点击"取消"或"X"按钮则返回1,其他异常返回-1
        int openResult = fileChooser.showOpenDialog(null);    //返回值为0
        System.out.println("openResult: "+openResult);
        if(openResult==JFileChooser.APPROVE_OPTION){
            //仅支持选择单个文件,支持选择多个文件使用getSelectedFiles()
            File selectFile = fileChooser.getSelectedFile();
            System.out.println(selectFile.toString());
            try{
                //选择的本地文件向网页文件一样打开
                displayPage(selectFile.toURL());
            }catch(MalformedURLException e){
                e.printStackTrace();
                }
            }
        }
    public void setHome(String home){
        this.home = home;
        }    
        
    public String getHome(){
//        return this.home;
        return home;
        }    
    
    //打开多个浏览器窗口,是否一个窗口最后一个页面关闭,所有窗口都会一并关闭??    
//    public static void setExitWhenLastWindowClosed(boolean b){
//        exitWhenLastWindowClosed = b;
//        }    
    private void newBrowser(){
        //构造函数递归调用
        WebBrowser b = new WebBrowser();
        //this指外层构造函数生成的对象实例
        b.setSize(this.getWidth(),this.getHeight());
        b.setVisible(true);
        }    
        
    //初始化工具栏,只允许子类继承和重写
    protected void initToolBar(){
        backButton = new JButton("后退");
        backButton.setEnabled(true);
        //匿名内部类为接口(Y)
        backButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                back();
                }
            });
            
        farwardButton = new JButton("前进");
        farwardButton.setEnabled(true);
        //(Y)
        farwardButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                forward();
                }
            });
            
        JButton refresh = new JButton("刷新");
        refresh.setEnabled(true);
        //(Y)
        refresh.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                refresh();
                }
            });
            
        JButton home = new JButton("主页");    
        home.setEnabled(true);
        //(Y)
        home.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                home();
                }
            });
        
        urlField = new JTextField();
        //(Y)
        urlField.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                displayPage(urlField.getText());
                }
            });
            
        JToolBar toolBar = new     JToolBar();
        toolBar.add(backButton);
        toolBar.add(farwardButton);
        toolBar.add(refresh);
        toolBar.add(home);
        toolBar.add(new JLabel("   地址:"));
        toolBar.add(urlField);
        this.getContentPane().add(toolBar,BorderLayout.NORTH);
        }
    
    private void home(){
        displayPage(getHome());
        }
    
    private void refresh(){
        if(currentHistoryPage != -1){
            //先展示一个默认的HTMLDocument页面
            textPane.setDocument(new HTMLDocument());
            }
        visit((URL)history.get(currentHistoryPage));
        }    
    
    private void forward(){
        if(currentHistoryPage < (history.size()-1)){
            visit((URL)history.get(++currentHistoryPage));
            }
        backButton.setEnabled((currentHistoryPage > 0));
        farwardButton.setEnabled((currentHistoryPage < (history.size()-1)));
        }    
    
    private void back(){
        if(currentHistoryPage > 0){
            visit((URL)history.get(--currentHistoryPage));
        }
        backButton.setEnabled((currentHistoryPage > 0));
        farwardButton.setEnabled((currentHistoryPage < (history.size()-1)));
        }
        
    private boolean visit(URL url){
        try{
            String href = url.toString();
            startAnimation("加载" + href + "...");
            textPane.setPage(href);        //Sets the current URL being displayed,加载完毕后触发addPropertyChangeListener事件
            this.setTitle(href);
            urlField.setText(href);
            return true;
        }catch(IOException e){
            stopAnimation();
            messageLable.setText("不能打开页面" + e.getMessage());
            return false;
            }
        }
    
    @SuppressWarnings("unchecked")    
    private void displayPage(URL url){
        if(visit(url)){
            this.history.add(url);
            int numentries = history.size();
            System.out.println("numentries:" + numentries);
            for(int i=0;i<numentries;i++){
                System.out.println("history["+i+"] : " + history.get(i));
                }
            if(numentries > (MAX_HISTORY + 10)){
                history = history.subList((numentries - MAX_HISTORY), numentries);
                currentHistoryPage = MAX_HISTORY;
                }
            currentHistoryPage =     (numentries - 1);
            //当前打开的页面会是最后一个吗?
            if(currentHistoryPage > 0){
                backButton.setEnabled(true);
                }
            }
        }    
        
    public void displayPage(String href){
        try{
            if(!href.startsWith("http://")){
            href = "http://"+href;
            }
            displayPage(new URL(href));
        }catch(MalformedURLException e){
            messageLable.setText("错误的网址:" + href);
            }
        }
        
    public void close(){
        //隐藏当前窗口
        this.setVisible(false);
        //销毁当前窗口的所有组件
        this.dispose();
        synchronized (WebBrowser.class){
            //浏览器窗口减1
            WebBrowser.numBrowserWindows--;
            //当Window监听器监听到关闭窗口事件,exitWhenLastWindowClosed标识默认为false,如果希望符合下面条件时关闭,则要提前通过setter设置
            if((numBrowserWindows==0) && (exitWhenLastWindowClosed==true)){
                System.exit(0);
                }
            }
        }
    //动画消息,显示在最底下的状态栏标签上,用于反馈浏览器状态    
    String animationMessage;
    //动画当前帧的索引
    int ainimationFrame = 0;
    //动画用到的帧,是一些字符
    String[] animationFrames = new String[]{"-", "\", "|", "/", "-", "\", "|", "/",",", ".", "o", "0", "O", "#", "*", "+"};
    //新建一个Swing的定时器,每125ms更新一次状态栏标签的文本(Y)
    javax.swing.Timer animator = new javax.swing.Timer(125,new ActionListener(){
        public void actionPerformed(ActionEvent e){
            animate();
            }
        });
    //定时器启动后就一直不间断的执行任务    
    private void animate(){
        String frame = animationFrames[ainimationFrame++];
        messageLable.setText(animationMessage + " "+ frame);
        //循环遍历动画用到的所有帧
        ainimationFrame = ainimationFrame % animationFrames.length;
        }    
    private void startAnimation(String message){
        animationMessage = message;
        ainimationFrame = 0;
        animator.start();
        }    
        
    private void stopAnimation(){
        System.out.println("信息标签停止播放动画!");
        animator.stop();
        messageLable.setText(" ");
        }
        
    public static void setExitWhenLastWindowClosed(boolean exitWhenLastWindowClosed){
        WebBrowser.exitWhenLastWindowClosed = exitWhenLastWindowClosed;
        }
        
    //实现HyperlinkListener接口的hyperlinkUpdate方法
    public void hyperlinkUpdate(HyperlinkEvent e){
        System.out.println("HyperlinkEvent.getURL(): " + e.getURL());
        HyperlinkEvent.EventType type = e.getEventType();
//        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
//        System.out.println(df.format(new Date())+" type: " + type);
        //激活类型--光标点击超链接位置
        if(type==HyperlinkEvent.EventType.ACTIVATED){
            displayPage(e.getURL());
            }
        //输入类型--光标放到超链接位置
        else if(type==HyperlinkEvent.EventType.ENTERED){
            messageLable.setText(e.getURL().toString());
            }
        //退出的类型--光标移出超链接位置    
        else if(type==HyperlinkEvent.EventType.EXITED){
            messageLable.setText(" ");
            }    
        }
        
    //实现PropertyChangeListener接口的propertyChange方法
    public void propertyChange(PropertyChangeEvent evt){
        System.out.println("PropertyName: "+evt.getPropertyName());
        //直到页面加载成功,之前都是对页面展示的准备,所有页面属性都是由JEditorPane完成,由PropertyChangeListener监听
        if(evt.getPropertyName().equals("page")){
            stopAnimation();
            }
        }
        
    public static void main(String[] args){
        WebBrowser.setExitWhenLastWindowClosed(true);
        WebBrowser browser = new WebBrowser();
        //获取屏幕分辨率,
//        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
//        browser.setSize(screenSize);
        browser.setSize(800,700);
        browser.setVisible(true);
        browser.displayPage(browser.getHome());
        }    
    }

加载页面:

原文地址:https://www.cnblogs.com/celine/p/9905268.html