Java中做一個帶有圖標和文字的JList列表(類似文件管理器列表或者QQ好友列表)

        這幾天研究了一下JList,發現自定義它的樣式真的是很難的過程。不過在此我想把我研究的東西整理並分享一下,希望對大家有所幫助。

一、列表基本操作

        首先我們來創建一個JList對象,並給它加一個滾動條:

JList jl=new JList();        //實例化JList對象
JScrollPane jsp=new JScrollPane();        //實例化滾動條對象
jsp.setViewportView(jl);        //把JList加到滾動條裏面

再把滾動條對象jsp加入到JPanel對象即可。

不過如何給JList加元素呢?通常我們使用默認數據模型DefaultListModel對象,在默認數據模型對象裏面添加元素(addElement()方法),再把模型對象放入JList的構造方法裏面,那麼,我把上面代碼改變如下:

DefaultListModel dfl=new DefaultListModel();        //實例化默認數據模型對象
dfl.addElement("a");        //給模型加入字符串元素a
dfl.addElement("b");        //給模型加入字符串元素b
JList jl=new JList(dfl);        //實例化JList對象,構造方法寫入默認數據模型對象
JScrollPane jsp=new JScrollPane();        //實例化滾動條對象
jsp.setViewportView(jl);        //把JList加到滾動條裏面

這樣就實現了最簡單的文字列表了:

觀察DefaultListModel對象的addElement()方法,發現參數是Object,也就是說他可以裝任何類型數據。我試着把圖片對象(ImageIcon)和文件對象(File)裝進去試試,改變代碼如下:

DefaultListModel dfl=new DefaultListModel();        //實例化默認數據模型對象
dfl.addElement("a");        //給模型加入字符串元素a
dfl.addElement("b");        //給模型加入字符串元素b
dfl.addElement(new ImageIcon("res\\testicon.png"));        //給模型加入圖片類型元素
dfl.addElement(new File("res\\testicon.png"));        //給模型加入文件類型元素
JList jl=new JList(dfl);        //實例化JList對象,構造方法寫入默認數據模型對象
JScrollPane jsp=new JScrollPane();        //實例化滾動條對象
jsp.setViewportView(jl);        //把JList加到滾動條裏面

效果:

可見,不同類型數據元素有着不同的顯示和繪製方法,其餘大家可以自行嘗試。

二、重寫渲染器以實現自定義列表樣式

不過怎麼自定義這個列表使其又有圖片又有文字呢?

首先我們要知道,JList有一個渲染器(DefaultListCellRenderer),它決定着JList如何顯示內容。要想自定義這個列表樣式,我們就必須 重寫這個渲染器。

在這個渲染器裏面有一個getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus)方法,它決定着列表如何顯示等等。

在此之前我們必須瞭解getListCellRendererComponent方法自帶的五個參數(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus)分別是什麼意義,否則我們不知道從何下手來自定義列表。

查看官方文檔得知意義如下:

JList<? extends Object> list表示我們正在創建的JList對象,其中<? extends Object>表示我們的列表對象元素類型是任意的。這個參數基本上我們不會使用。

Object value這個代表了我們列表中的元素,可以是任何類型,他是list.getModel().getElementAt(index)的返回值。

int index表示列表中被我們鼠標選擇的元素的索引,例如列表中第一個元素被選中了,則這個值就是0。

boolean isSelected表示我們的列表是否有元素被選中。

boolean cellHasFocus表示我們的列表是否有焦點(???)。

知道了這5個參數的意義,我們就可以很好的用他們來重寫我們的渲染器了。當然,剛開始這裏有一點我一直弄不明白,就是上面的參數Object value的意義,因爲他是Object,所以我們可能難以判斷其真實的、具體的類型,那麼怎麼來使用呢?於是我想看看它的“真面目”,或者是它包含着什麼信息。

不過我們知道了,他是list.getModel().getElementAt(index)的返回值,所以我決定先在JList所在的類裏面試試這個方法是什麼。

我又將上述JList相關代碼下面加上了這個方法,改變如下:

DefaultListModel dfl=new DefaultListModel();        //實例化默認數據模型對象
dfl.addElement("a");        //給模型加入字符串元素a
dfl.addElement("b");        //給模型加入字符串元素b
dfl.addElement(new ImageIcon("res\\testicon.png"));        //給模型加入圖片類型元素
dfl.addElement(new File("res\\testicon.png"));        //給模型加入文件類型元素
JList jl=new JList(dfl);        //實例化JList對象,構造方法寫入默認數據模型對象
JScrollPane jsp=new JScrollPane();        //實例化滾動條對象
jsp.setViewportView(jl);        //把JList加到滾動條裏面
/**
    使用Object的toString()方法,用控制檯輸出獲取到的表格的第1、2、3、4個內容。
*/
System.out.println(jl.getModel().getElementAt(0).toString());        
System.out.println(jl.getModel().getElementAt(1).toString());
System.out.println(jl.getModel().getElementAt(2).toString());
System.out.println(jl.getModel().getElementAt(3).toString());

然後控制檯輸出如下:

我們發現,通過toString()方法,表格內容包含的文字信息被輸出了。也就是說,我們通過toString()方法,就可以吧渲染器裏面value值給以String形式獲取了!

好了,解除了疑惑,我們現在就要開始自己重寫渲染器,來自定義列表樣式了!

新建一個類,我這裏起名爲CRTest,然後重寫方法:

import java.awt.*;
import javax.swing.*;
public class CRTest extends DefaultListCellRenderer {        //繼承渲染器類
    public Component getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus) {        //重寫渲染器的方法

        return this;
    }
}

需要注意的是,默認渲染器類繼承了JLabel,因此在這個裏面設置樣式我們就用JLabel的方法即可。

現在給列表加上圖片,改變渲染器代碼如下:

import java.awt.*;
import javax.swing.*;
public class CRTest extends DefaultListCellRenderer {        //繼承渲染器類
    public Component getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus) {        //重寫渲染器的方法
        setText(value.toString());		//設置文字(獲取每個元素文字信息將其顯示)
        setIcon(new ImageIcon("res\\testicon.png"));        //設置圖標
        return this;
    }
}

然後再JList所在的類設置渲染器爲我們自己寫的渲染器,加上下面這句話:

jl.setCellRenderer(new CRTest());        //設置渲染器爲我們自己的

效果如下:

通過設置圖片大小、背景顏色等等,我們可以實現列表每個元素的圖標的自適應、設置鼠標放上去時和被選中時顯示的顏色等等。

改變渲染器代碼如下:

import java.awt.*;
import javax.swing.*;
public class CRTest extends DefaultListCellRenderer {        //繼承渲染器類
    public Component getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus) {        //重寫渲染器的方法
        setText(value.toString());		//設置文字(獲取每個元素文字信息將其顯示)
        ImageIcon ico=new ImageIcon("res\\testicon.png");		//實例化一個ImageIcon對象
        Image img=ico.getImage();		//實例化Image對象獲取ico對象的內容 
        img=img.getScaledInstance(25,25,Image.SCALE_DEFAULT);		//把圖片全部縮放爲25x25
        ico.setImage(img);		//ImageIcon對象重新獲取縮放後圖標
        setIcon(ico);		//設置圖標
        if(isSelected) {		//當某個元素被選中時
            setForeground(Color.WHITE);		//設置前景色(文字顏色)爲白色
            setBackground(Color.BLUE);		//設置背景色爲藍色
            System.out.println(index+"被選中");
        } else {		//某個元素未被選中時(取消選中)
            setForeground(Color.BLACK);		//設置前景色(文字顏色)爲黑色
            setBackground(Color.WHITE);		//設置背景色爲白色
        }
        return this;
    }
}

 效果:

還可以添加如下方法設置每個單元格水平、垂直位置關係,大家可以加入自行嘗試:

setVerticalTextPosition(SwingConstants.CENTER);        //垂直
setHorizontalTextPosition(SwingConstants.CENTER);        //水平
//上面CENTER意思是設置到中間,改變這個CENTER可以換位其它位置

如果我想每一個元素圖標不同怎麼辦呢?那也很簡單,在渲染器裏面判斷value值,然後分別設置即可,我改變代碼如下:

import java.awt.*;
import javax.swing.*;
public class CRTest extends DefaultListCellRenderer {        //繼承渲染器類
    public Component getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus) {        //重寫渲染器的方法
        setText(value.toString());		//設置文字(獲取每個元素文字信息將其顯示)
        if(value.toString().equals("a")) {		//判斷value(列表值)來分情況設置不同圖標
            ImageIcon ico=new ImageIcon("res\\testicon.png");		//實例化一個ImageIcon對象
            Image img=ico.getImage();		//實例化Image對象獲取ico對象的內容 
            img=img.getScaledInstance(25,25,Image.SCALE_DEFAULT);		//把圖片全部縮放爲25x25
            ico.setImage(img);		//ImageIcon對象重新獲取縮放後圖標
            setIcon(ico);		//設置圖標
        } else {
            ImageIcon ico=new ImageIcon("res\\testicon-2.png");		//實例化一個ImageIcon對象
            Image img=ico.getImage();		//實例化Image對象獲取ico對象的內容 
            img=img.getScaledInstance(25,25,Image.SCALE_DEFAULT);		//把圖片全部縮放爲25x25
            ico.setImage(img);		//ImageIcon對象重新獲取縮放後圖標
            setIcon(ico);
        }
        if(isSelected) {		//當某個元素被選中時
            setForeground(Color.WHITE);		//設置前景色(文字顏色)爲白色
            setBackground(Color.BLUE);		//設置背景色爲藍色
            System.out.println(index+"被選中");
        } else {		//某個元素未被選中時(取消選中)
            setForeground(Color.BLACK);		//設置前景色(文字顏色)爲黑色
            setBackground(Color.WHITE);		//設置背景色爲白色
        }
        return this;
    }
}

效果:

這樣,我們就完成了列表自定義了!

我們還可以設置列表是橫排還是豎着顯示。回到JList所在的類,通過JList的setLayoutOrientation()方法和setVisibleRowCount()方法實現。如下,我加入下面兩行代碼:

jl.setLayoutOrientation(JList.HORIZONTAL_WRAP);		//設置表格橫着排列元素
jl.setVisibleRowCount(1);		//設置總行數爲1行

 效果:

setVisibleRowCount設置爲2時:

其餘大家可以自己嘗試。

那麼以上就是自定義列表的方法了,我們總共有2個類,其中注意渲染器類重寫時每個參數的意義!這非常重要!

完整代碼:

主類:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
public class JListObj {
	@SuppressWarnings({ "unchecked", "rawtypes", "static-access", "deprecation" })
	public static void main(String[] args) {
		JFrame jf=new JFrame("列表對象獲取");
		jf.setSize(500,300);
		jf.setDefaultCloseOperation(jf.EXIT_ON_CLOSE);
		DefaultListModel dfl=new DefaultListModel();
		dfl.addElement("a");
		dfl.addElement("b");
		dfl.addElement(new ImageIcon("res\\testicon.png"));
		dfl.addElement(new File("res\\testicon.png"));
		JList jl=new JList(dfl);
		jl.setCellRenderer(new CRTest());		//設置渲染器爲我們自己的
		JScrollPane jsp=new JScrollPane();
		jsp.setBounds(14, 13, 431, 210);
		jsp.setViewportView(jl);
		JPanel jp=new JPanel();
		jf.getContentPane().add(jp);
		jp.setLayout(null);	
		jp.add(jsp);
		jf.show();
		/**
			使用Object的toString()方法,用控制檯輸出獲取到的表格的第1、2、3、4個內容。
		 */
		System.out.println(jl.getModel().getElementAt(0).toString());
		System.out.println(jl.getModel().getElementAt(1).toString());
		System.out.println(jl.getModel().getElementAt(2).toString());
		System.out.println(jl.getModel().getElementAt(3).toString());
	}
}

自定義渲染器類(重寫默認渲染器):

import java.awt.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class CRTest extends DefaultListCellRenderer {
	public Component getListCellRendererComponent(JList<? extends Object> list,Object value,int index,boolean isSelected,boolean cellHasFocus) {
		setText(value.toString());		//設置文字
		if(value.toString().equals("a")) {		//判斷value(列表值)來分情況設置不同圖標
			ImageIcon ico=new ImageIcon("res\\testicon.png");		//實例化一個ImageIcon對象
			Image img=ico.getImage();		//實例化Image對象獲取ico對象的內容 
			img=img.getScaledInstance(25,25,Image.SCALE_DEFAULT);		//把圖片全部縮放爲25x25
			ico.setImage(img);		//ImageIcon對象重新獲取縮放後圖標
			setIcon(ico);		//設置圖標
		} else {
			ImageIcon ico=new ImageIcon("res\\testicon-2.png");		//實例化一個ImageIcon對象
			Image img=ico.getImage();		//實例化Image對象獲取ico對象的內容 
			img=img.getScaledInstance(25,25,Image.SCALE_DEFAULT);		//把圖片全部縮放爲25x25
			ico.setImage(img);		//ImageIcon對象重新獲取縮放後圖標
			setIcon(ico);
		}
		if(isSelected) {		//當某個元素被選中時
			setForeground(Color.WHITE);		//設置前景色(文字顏色)爲白色
			setBackground(Color.BLUE);		//設置背景色爲藍色
			System.out.println(index+"被選中");
		} else {		//某個元素未被選中時(取消選中)
			setForeground(Color.BLACK);		//設置前景色(文字顏色)爲黑色
			setBackground(Color.WHITE);		//設置背景色爲白色
		}
		return this;
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章