`

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);
		}
	}
}

 

分享到:
评论

相关推荐

    Java Swing - 常识篇 之 LayoutManager

    本篇文章将深入探讨Java Swing中的布局管理器,以及如何有效地利用它们来构建用户界面。 首先,我们需要理解Swing中的几种基本布局管理器。每个容器都有一个默认的LayoutManager,例如JFrame使用的是BorderLayout,...

    Java-Swing-exercises.rar_java 控件

    Java Swing是Java GUI(图形用户界面)库的一部分,它提供了丰富的组件和工具,用于构建桌面应用程序。这个"Java-Swing-exercises.rar"压缩包显然包含了作者在大学期间编写的Swing控件练习,旨在帮助学习者熟悉并...

    java swing漂亮界面(超酷) javaswing教程

    文档"javaswing教程.doc"应该包含了详细的步骤、实例代码以及最佳实践,帮助你深入理解和掌握Java Swing的界面设计技巧。 总之,Java Swing不仅是一个强大的工具集,也是开发者实现桌面应用创新设计的关键。通过这...

    基于Java的实例开发源码-swing-explorer(Swing开发辅助工具).zip

    Swing Explorer是一款基于Java Swing库开发的辅助工具,旨在帮助开发者更轻松地理解和调试Swing应用程序。这个压缩包包含了Swing Explorer的完整源代码,为Java开发者提供了一个深入学习Swing组件和布局管理器的实践...

    javaswing详解

    本篇文章将深入讲解Java Swing的基础知识、核心组件、事件处理以及实际案例应用。 一、Java Swing基础知识 1. 轻量级与重量级组件:Swing组件是轻量级的,基于Java的AWT(Abstract Window Toolkit)组件,比AWT...

    javaswing组件大全.pdf

    BorderLayout 是 Java Swing 中的一个布局管理器,继承自 java.awt.LayoutManager 类。BorderLayout 提供了一个基本的布局管理,可以用来布局组件。在上面的代码中,我们可以看到 BorderLayout 的使用,实现了一个...

    java swing 工具箱

    本篇将深入探讨Java Swing工具箱中的关键概念和技术。 首先,Swing 提供了大量组件(JComponents),这些组件用于构建用户界面,例如按钮(JButton)、文本框(JTextField)、列表(JList)、表格(JTable)和面板...

    Java Swing 组件全演示

    Java Swing 是Java GUI(图形用户界面)库的一部分,用于构建桌面应用程序。它提供了丰富的组件集合,使得开发者可以创建复杂的、交互式的用户界面。在Java Swing组件全演示中,我们将深入探讨Swing的核心概念、组件...

    java swing实时时钟

    Java Swing 是Java平台上的一个图形用户界面(GUI)工具包,它是Java Foundation Classes (JFC)的一部分,用于构建桌面应用程序。本项目"java swing实时时钟"是一个基于Swing的简单应用,旨在帮助初学者理解如何在Java...

    深入浅出Java Swing程序设计_11394260.rar

    Java Swing是Java GUI(图形用户界面)开发的重要库,它属于Java Foundation Classes (JFC)的一部分,用于构建桌面应用程序。本资源"深入浅出Java Swing程序设计_11394260.rar"显然是一个关于Java Swing编程的详细...

    Java编程-中级界面篇

    在Java编程领域,中级界面篇通常涉及的是图形用户界面(GUI)的设计与开发。Java提供了丰富的库和工具来创建美观且功能强大的用户界面,其中最常用的就是Java Swing和JavaFX。下面将详细介绍这两个库以及相关的知识...

    JAVA图形编程(AWT+SWING)

    本资源包主要涵盖了两个核心库:AWT(Abstract Window Toolkit)和Swing,它们都是Java Foundation Classes (JFC) 的一部分,用于构建桌面应用程序。 **AWT** 是Java早期提供的图形用户界面(GUI)工具包,它直接与...

    java Swing(容器,简单控件,布局管理器)

    ### Java Swing 概述 Java Swing 是 Java 平台中用于构建图形用户界面(GUI)的一个强大库。它是在 Java 2.0 版本中引入的,作为对早期 Java AWT(Abstract Window Toolkit)库的增强和扩展。Swing 的主要优势在于...

    java swing(影印版)

    Java Swing 是Java GUI编程的重要部分,它提供了丰富的组件和功能,使得开发者能够创建美观且功能齐全的桌面应用程序。本资源“java swing(影印版)”是一部针对Java Swing的学习教材,旨在帮助学习者掌握Swing的...

    Java应用程序-日记本

    Java应用程序-日记本是一款基于Java Swing开发的桌面应用,它为用户提供了一个集日记书写、截图和音乐播放功能于一体的平台。Swing是Java Standard Edition (Java SE)的一部分,用于构建图形用户界面(GUI)的库,...

    java swing LayerTest

    Java Swing 是Java GUI(图形用户界面)开发的一个重要库,它是Java AWT(抽象窗口工具包)的扩展,提供了更多丰富的组件和功能。在Swing中,`JPanel`是常用的一种容器组件,用于组合其他组件,实现复杂的用户界面。...

Global site tag (gtag.js) - Google Analytics