TWaver - 專注UI技術

          http://twaver.servasoft.com/
          posts - 171, comments - 191, trackbacks - 0, articles - 2
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          Swing探秘:編寫一個JCheckListBox組件

          Posted on 2010-08-23 13:56 TWaver 閱讀(2040) 評論(1)  編輯  收藏

          記得Delphi里面有一個TCheckListBox控件,是一個可打勾的列表。但是這個東西在Swing里面并沒有現成的。如今,我們就一起動手制作一個。根據Java的管理,就叫JCheckListBox吧。

          寫代碼之前,先考慮以下問題:

          • 繼承:當然是從Swing的JList繼承。
          • 數據擴充:對于JList來說,它是顯示了一系列Object。無論其類型如何,都用一個默認的渲染器(DefaultListCellRenderer,從JLabel繼承而來)來畫,每個條目的文字用Object.toString()來設置。但是對于JCheckListBox來說,除了顯示文本外,還要考慮每個條目是否被選中,如果選中,要顯示“打勾”。所以,JList需要維護“每一個條目是否選中”的狀態信息。我們放在一個boolean數組中。
          • 渲染器:默認的Renderer肯定是不行了,無法顯示打勾。自然想到用JCheckBox來重新做一個渲染器,設置到JCheckListBox中。
          • 鼠標監聽器:現在可以畫每個條目了,但還不夠,必須能響應鼠標的點擊以便Check/UnCheck才行。所以要在JCheckListBox上加一個鼠標監聽器來響應鼠標事件。當然,如果你想讓它相應鍵盤輸入(例如Ctrl+A全選)也可如法炮制。
          • CheckListBoxModel:為了操作方便,這里還從AbstractListModel擴充一個CheckListBoxModel,它能在條目Check變化時發送事件。

          好了,由于代碼和原理都比較簡單,不再贅述,直接給出代碼,以及簡單注釋。

            1import java.awt.*;
            2import java.awt.event.*;
            3import javax.swing.*;
            4import javax.swing.event.*;
            5
            6public class JCheckListBox extends JList {
            7    //這個boolean數組裝載所有item是否被check的信息。
            8
            9    private boolean[] checkedItems = null;
           10
           11    /**
           12     * 定義一個簡單的ListModel,它可以發送check變化事件。
           13     */

           14    class CheckListBoxModel extends AbstractListModel {
           15
           16        private Object[] items = null;
           17
           18        CheckListBoxModel(Object[] items) {
           19            this.items = items;
           20        }

           21
           22        public int getSize() {
           23            return items.length;
           24        }

           25
           26        public Object getElementAt(int i) {
           27            return items[i];
           28        }

           29
           30        protected void fireCheckChanged(Object source, int index) {
           31            fireContentsChanged(source, index, index);
           32        }

           33
           34        public Object getItem(int index) {
           35            return items[index];
           36        }

           37    }

           38
           39    /**
           40     * 這里就覆蓋了一個構造函數。其他JList你自己覆蓋吧,反正super一下再init就OK了。
           41     * @param items Object[]
           42     */

           43    public JCheckListBox(Object[] items) {
           44        setModel(new CheckListBoxModel(items));
           45        init();
           46    }

           47
           48    /**
           49     * 初始化控件。包括初始化boolean數組、安裝一個渲染器、安裝一個鼠標監聽器。
           50     */

           51    protected void init() {
           52        checkedItems = new boolean[this.getModel().getSize()];
           53        class MyCellRenderer extends JCheckBox implements ListCellRenderer {
           54
           55            public MyCellRenderer() {
           56                setOpaque(true);
           57            }

           58
           59            public Component getListCellRendererComponent(
           60                    JList list,
           61                    Object value,
           62                    int index,
           63                    boolean isSelected,
           64                    boolean cellHasFocus) {
           65                //這點代碼基本上從DefaultListCellRenderer.java中抄襲的。
           66                setComponentOrientation(list.getComponentOrientation());
           67                if (isSelected) {
           68                    setBackground(list.getSelectionBackground());
           69                    setForeground(list.getSelectionForeground());
           70                }
           else {
           71                    setBackground(list.getBackground());
           72                    setForeground(list.getForeground());
           73                }

           74
           75                if (value instanceof Icon) {
           76                    setIcon((Icon) value);
           77                    setText("");
           78                }
           else {
           79                    setIcon(null);
           80                    setText((value == null? "" : value.toString());
           81                }

           82                setEnabled(list.isEnabled());
           83                setFont(list.getFont());
           84
           85                //雖然抄襲,可這里別忘了設置check信息。
           86                this.setSelected(isChecked(index));
           87                return this;
           88            }

           89        }

           90
           91        this.setCellRenderer(new MyCellRenderer());
           92        //定義一個鼠標監聽器。如果點擊某個item,翻轉其check狀態。
           93        class CheckBoxListener extends MouseAdapter {
           94
           95            @Override
           96            public void mouseClicked(MouseEvent e) {
           97                int index = locationToIndex(e.getPoint());
           98                invertChecked(index);
           99            }

          100        }

          101
          102        this.addMouseListener(new CheckBoxListener());
          103    }

          104
          105    /**
          106     * 翻轉指定item的check狀態。
          107     * @param index int
          108     */

          109    public void invertChecked(int index) {
          110        checkedItems[index] = !checkedItems[index];
          111        //別忘了發送event。
          112        CheckListBoxModel model = (CheckListBoxModel) getModel();
          113        model.fireCheckChanged(this, index);
          114        this.repaint();
          115    }

          116
          117    /**
          118     * 是否指定item被check。
          119     * @param index int
          120     * @return boolean
          121     */

          122    public boolean isChecked(int index) {
          123        return checkedItems[index];
          124    }

          125
          126    /**
          127     * 獲得選中的item個數
          128     */

          129    public int getCheckedCount() {
          130        int result = 0;
          131        for (int i = 0; i < checkedItems.length; i++{
          132            if (checkedItems[i]) {
          133                result++;
          134            }

          135        }

          136        return result;
          137    }

          138
          139    /**
          140     * 所有選中item索引的數組。
          141     */

          142    public int[] getCheckedIndices() {
          143        int[] result = new int[getCheckedCount()];
          144        int index = 0;
          145        for (int i = 0; i < checkedItems.length; i++{
          146            if (checkedItems[i]) {
          147                result[index] = i;
          148                index++;
          149            }

          150        }

          151        return result;
          152    }

          153
          154    public static void main(String[] args) throws Exception {
          155
          156        Font font = new Font("微軟雅黑", Font.PLAIN, 12);
          157
          158        JFrame frame = new JFrame("TWaver中文社區之Swing探秘");
          159
          160        final JCheckListBox list = new JCheckListBox(new Object[]{"張三""李四""王二麻子""木頭六","小七子"});
          161        list.setFont(font);
          162        frame.getContentPane().add(new JScrollPane(list), BorderLayout.CENTER);
          163        JButton button = new JButton("OK");
          164        button.addActionListener(new ActionListener() {
          165
          166            public void actionPerformed(ActionEvent e) {
          167                System.exit(0);
          168            }

          169        }
          );
          170        frame.getContentPane().add(button, BorderLayout.SOUTH);
          171        final JLabel label = new JLabel("當前沒有選擇。");
          172        label.setFont(font);
          173        list.getModel().addListDataListener(new ListDataListener() {
          174
          175            public void intervalAdded(ListDataEvent e) {
          176            }

          177
          178            public void intervalRemoved(ListDataEvent e) {
          179            }

          180
          181            public void contentsChanged(ListDataEvent e) {
          182                if (list.getCheckedCount() == 0{
          183                    label.setText("當前沒有選擇。");
          184                }
           else {
          185                    String text = "當前選擇:";
          186                    int[] indices = list.getCheckedIndices();
          187                    for (int i = 0; i < indices.length; i++{
          188                        text += ((CheckListBoxModel) list.getModel()).getItem(indices[i]).toString() + ",";
          189                    }

          190                    label.setText(text);
          191                }

          192            }

          193        }
          );
          194        frame.getContentPane().add(label, BorderLayout.NORTH);
          195        frame.setBounds(300300400200);
          196        frame.setVisible(true);
          197    }

          198}

          運行效果如下圖:


          評論

          # re: Swing探秘:編寫一個JCheckListBox組件  回復  更多評論   

          2010-08-24 09:25 by zeyuphoenix
          恩 以前我也寫過一個
          http://www.aygfsteel.com/zeyuphoenix/archive/2010/05/03/319976.html
          jlist是比較簡單的組件,基本不用考慮ui的問題,比jtable和jtree好處理,也沒什么高級擴展

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 黄石市| 桃江县| 循化| 台前县| 德阳市| 莲花县| 溧阳市| 榆林市| 扎鲁特旗| 彩票| 句容市| 舞钢市| 张北县| 政和县| 洪泽县| 鹿邑县| 武夷山市| 通许县| 宁化县| 鹤壁市| 高邮市| 静宁县| 称多县| 千阳县| 当雄县| 沂南县| 福鼎市| 乌兰县| 江陵县| 西宁市| 绥化市| 锦屏县| 青阳县| 永平县| 江山市| 衡东县| 吉水县| 玉山县| 龙山县| 屏山县| 铜川市|