Java Swing - 常识篇 之 LayoutManager 03

        这篇还是继续讲Swing的常识,主要是针对想成为Swing“高手”的新接触的朋友。在这里想说一下题外话,Swing这种技术虽然很“老旧”,但是又有几个人能完完全全熟透Swing呢,在很多人的眼里都认为Swing很复杂,但是如果把Swing弄懂了之后,其他的JavaFX、SWT、Android的界面开发,其实也不再话下。其实界面开发都是差不多的,一个样。在这里想告诉大家一个道理,别看到新技术就一头扎进去。如果熟练掌握Swing,而又熟悉JavaFX的朋友,可能会发现JDK下的com.sun.java.swing包下的很多东西都和JavaFX的特效相似.

      上两篇文章介绍完了两个非常好用的LayoutManager(MigLayout和TableLayout),今天在这里将会讲述一下CardLayout,介绍它如何使用,哪些地方存在不足。

      先看看API对CardLayout的描述:它将容器中的每个组件看作一张卡片。一次只能看到一张卡片,容器则充当卡片的堆栈。当容器第一次显示时,第一个添加到 CardLayout对象的组件为可见组件。然后我们再看看它的方法,不难发现,它的几个重要的方法如下:

first(Container) Flips to the first card of the container.

last(Container): Flips to the last card of the container.

next(Container)Flips to the next card of the specified container.

previous(Container)Flips to the previous card of the specified container.

show(Container):Flips to the component that was added to this layout with the specified name, using addLayoutComponent.

    下面先来看一个例子:

package org.dui.sample;

import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import net.miginfocom.swing.MigLayout;


/**
 * <code>CardLayoutSample</code> demonstrates how to use the
 * <code>CardLayout</code>
 * 
 * @author Jimmy
 * @since <i> DUI v1.0.0 (Apr 1,2013)</i>
 */
public class CardLayoutSample extends JPanel {
	private static final long serialVersionUID = 1L;
	/**Cache the index of the current displaying component*/
	private int m_iCurrent = 0;
	{
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			UIManager.put("Label.font", new Font("", Font.BOLD, 20));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * Just create an instance.
	 * 
	 */
	public CardLayoutSample() {
		initGUI();
	}

	/**
	 * Init the UI
	 *
	 * @since <i>DUI v.1.0.0 (Apr 1, 2013)</i>
	 */
	public void initGUI() {
		this.setLayout(new MigLayout("ins 5", "grow,fill", "[grow,fill][fill]"));
		this.setPreferredSize(new Dimension(400,300));
		
		final CardLayout layoutCard = new CardLayout();
		final JPanel pnlCard = new JPanel(layoutCard);
		JButton btnPrev = new JButton("Prev");
		JButton btnNext = new JButton("Next");
		this.add(pnlCard, "cell 0 0")
		.add(btnPrev, "cell 0 1, gapleft push")
		.add(btnNext, "cell 0 1, gapright push");
		
		final String[] aNames = {"card1","card2", "card3", "card4"};
		pnlCard.add(new JLabel("Card1"), aNames[0]);
		pnlCard.add(new JLabel("Card2"), aNames[1]);
		pnlCard.add(new JLabel("Card3"), aNames[2]);
		pnlCard.add(new JLabel("Card4"), aNames[3]);
		
		btnPrev.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				m_iCurrent = m_iCurrent >= 1 ? --m_iCurrent : m_iCurrent;
				layoutCard.show(pnlCard, aNames[m_iCurrent]);
			}
		});
		
		btnNext.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				m_iCurrent = m_iCurrent < 3 ? ++m_iCurrent : m_iCurrent;
				layoutCard.show(pnlCard, aNames[m_iCurrent]);
			}
		});
	}
	
	/**
	 * Add a Component specify by <code>oComp</code> to the container <code>self</code>
	 * @param oComp
	 * @param oConstraints
	 * @return self
	 *
	 * @since <i>DUI v.1.0.0 (Apr 1, 2013)</i>
	 */
	public CardLayoutSample add(JComponent oComp, Object oConstraints){
		super.add(oComp, oConstraints);
		return this;
	}
	
	
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				JFrame oFrame = new JFrame();
				oFrame.setTitle("CardLayoutSample");
				oFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				oFrame.setResizable(true);
				oFrame.setContentPane(new CardLayoutSample());
				oFrame.pack();
				oFrame.setVisible(true);
				oFrame.setLocationRelativeTo(null);
			}
		});
	}
	
}

           看了上面的例子,细心的你可能会发现,在程序中要用m_iCurrent来记录当前CarLayout所显示的组件,其实CardLayout有两个做得不够好的地方:

1)CardLayout没有提供方法去获取当前正在显示的组件。

2)当开始显示的整个Container的时候,CardLayout里面的组件没有得到聚焦。

为了解决上面两个问题,在这里提供一个增强版的CardLayout 命名为RCardLayout。例子在这里就不再写了,如果不会使用的朋友,可以留言。

package org.dui.sample;

import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.util.ArrayList;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;

/**
 * The <code>RCardLayout</code> provides some extensions to the CardLayout
 * class. In particular adding support for:
 * 
 * a) setting focus on the card when it is displayed b) getting the currently
 * displayed Card c) Next and Previous Actions This added support will only work
 * when a JComponent is added as a Card.
 * 
 * @since <i> DUI v1.0.0 (Apr 1,2013)</i>
 * 
 */
public class RCardLayout extends CardLayout implements HierarchyListener {
	private static final long serialVersionUID = 1L;
	private ArrayList<JComponent> cards = new ArrayList<JComponent>();
	private JComponent firstCard;
	private JComponent lastCard;
	private JComponent currentCard;
	private boolean isRequestFocusOnCard = true;
	private Action nextAction;
	private Action previousAction;

	/**
	 * Creates a new card layout with gaps of size zero.
	 */
	public RCardLayout() {
		this(0, 0);
	}

	/**
	 * Creates a new card layout with the specified horizontal and vertical
	 * gaps. The horizontal gaps are placed at the left and right edges. The
	 * vertical gaps are placed at the top and bottom edges.
	 * 
	 * @param hgap
	 *            the horizontal gap.
	 * @param vgap
	 *            the vertical gap.
	 */
	public RCardLayout(int hgap, int vgap) {
		super(hgap, vgap);
	}

	// Overridden methods

	public void addLayoutComponent(Component comp, Object constraints) {
		super.addLayoutComponent(comp, constraints);

		if (!(comp instanceof JComponent))
			return;

		JComponent component = (JComponent) comp;
		cards.add(component);

		if (firstCard == null)
			firstCard = component;

		lastCard = component;

		component.addHierarchyListener(this);
	}

	public void removeLayoutComponent(Component comp) {
		super.removeLayoutComponent(comp);

		if (!(comp instanceof JComponent))
			return;

		JComponent component = (JComponent) comp;
		component.removeHierarchyListener(this);
		cards.remove(component);

		if (component.equals(firstCard) && cards.size() > 0) {
			firstCard = cards.get(0);
		}

		if (component.equals(lastCard) && cards.size() > 0) {
			lastCard = cards.get(cards.size() - 1);
		}

	}

	// New methods

	public JComponent getCurrentCard() {
		return currentCard;
	}

	public Action getNextAction() {
		return getNextAction("Next");
	}

	public Action getNextAction(String name) {
		if (nextAction == null) {
			nextAction = new CardAction(name, true);
			nextAction.putValue(Action.MNEMONIC_KEY, (int) name.charAt(0));
			nextAction.setEnabled(isNextCardAvailable());
		}

		return nextAction;
	}

	public Action getPreviousAction() {
		return getPreviousAction("Previous");
	}

	public Action getPreviousAction(String name) {
		if (previousAction == null) {
			previousAction = new CardAction(name, false);
			previousAction.putValue(Action.MNEMONIC_KEY, (int) name.charAt(0));
			previousAction.setEnabled(isNextCardAvailable());
		}

		return previousAction;
	}

	public boolean isNextCardAvailable() {
		return currentCard != lastCard;
	}

	public boolean isPreviousCardAvailable() {
		return currentCard != firstCard;
	}

	public boolean isRequestFocusOnCard() {
		return isRequestFocusOnCard;
	}

	public void setRequestFocusOnCard(boolean isRequestFocusOnCard) {
		this.isRequestFocusOnCard = isRequestFocusOnCard;
	}

	// Implement Hierarchy Listener

	@Override
	public void hierarchyChanged(HierarchyEvent e) {
		JComponent component = (JComponent) e.getSource();

		if ((HierarchyEvent.SHOWING_CHANGED & e.getChangeFlags()) != 0 && component.isShowing()) {
			currentCard = component;

			if (isRequestFocusOnCard)
				currentCard.transferFocus();

			if (nextAction != null)
				nextAction.setEnabled(isNextCardAvailable());

			if (previousAction != null)
				previousAction.setEnabled(isPreviousCardAvailable());
		}
	}

	class CardAction extends AbstractAction {
		private static final long serialVersionUID = 1L;
		private boolean isNext;

		public CardAction(String text, boolean isNext) {
			super(text);
			this.isNext = isNext;
			putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME));
		}

		public void actionPerformed(ActionEvent e) {
			Container parent = getCurrentCard().getParent();

			if (isNext)
				next(parent);
			else
				previous(parent);
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值