`
mikewang
  • 浏览: 10220 次
  • 性别: Icon_minigender_1
  • 来自: 南京
文章分类
社区版块
存档分类
最新评论

环形布局管理器 + 环形弹出菜单(学习swing的一些小成果)

阅读更多
最近闲来无事, 学习学习swing。
在查看JPopMenu的代码时候突发奇想, 想实现一个环形的弹出菜单,说干就干。

我们都知道, swing 组件的位置和大小是由于layout 管理的,所以想实现环形的弹出菜单就必须实现一个环形的布局管理器。请看我的实现

效果



package info.mikewang.gui.layout;

import static java.lang.Math.PI;
import static java.lang.Math.round;
import static java.lang.Math.sin;
import static java.lang.Math.cos;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;

public class CircleLayout implements LayoutManager {

	int maxCompWidth = 0; // 最大组件宽度
	int maxCompHeight = 0; // 最大组件高度

	int lc = 0; // 组件数(边的个数,即多边形边的个数)

	double v = 1.5D; // 缩放因子
	double cd = 0; // 组件和组件之间的距离(中心点到中心点)

	int l; // 外截正方形边长/2

	int lw = 0; // 调整过的边长
	int lh = 0;

	@Override
	public void addLayoutComponent(String name, Component comp) {

	}

	@Override
	public void layoutContainer(Container parent) {

		synchronized (parent.getTreeLock()) {

			Dimension d = parent.getPreferredSize();

			Point cp = new Point(d.width / 2, d.height / 2);

			double dx = 0, dy = 0;
			int cpx = 0, cpy = 0;
			for (int i = 0; i < lc; i++) {

     // 下面两行的代码要是看不懂的话,就去翻翻初中2年纪的几何书吧

				dx = sin(i * (2 * PI / lc)) * l;
				dy = -cos(i * (2 * PI / lc)) * l;

				cpx = (int) (cp.x + dx);
				cpy = (int) (cp.y + dy);
				Point cpp = new Point(cpx, cpy);
				Component comp = parent.getComponent(i);
				Dimension compSize = comp.getPreferredSize();

				comp.setBounds(calcR(cpp, compSize));
			}
		}
	}

	@Override
	public Dimension minimumLayoutSize(Container parent) {
		lc = parent.getComponentCount();

		Component[] components = parent.getComponents();
		for (Component component : components) {
			Dimension d = component.getPreferredSize();
			if (d.width > this.maxCompWidth) {
				this.maxCompWidth = d.width;
			}
			if (d.height > this.maxCompHeight) {
				this.maxCompHeight = d.height;
			}
		}

		calc();

		return new Dimension(lw, lh);
	}

	@Override
	public Dimension preferredLayoutSize(Container parent) {
		return minimumLayoutSize(parent);
	}

	@Override
	public void removeLayoutComponent(Component comp) {

	}

	private void calc() {
		cd = maxCompWidth * v;

		// 根据正多边形的一条边长,计算出这个多边形外切圆形的外切矩形的边长(近似值)
		// 使用正弦定理,
		double x = cd / sin(2 * PI / lc);
		l = (int) round(x);

		lh = 2 * l + maxCompHeight;
		lw = 2 * l + maxCompWidth;
	}

	private Rectangle calcR(Point p, Dimension d) {
		int y = p.y - d.height / 2;
		int x = p.x - d.width / 2;
		return new Rectangle(new Point(x, y), d);
	}
}



环形 弹出菜单实现


package info.mikewang.gui.layout;


import javax.swing.JPopupMenu;

public class CirclePopupMenu extends JPopupMenu {

	private static final long serialVersionUID = 7318307166817760768L;

	public CirclePopupMenu() {
		this.setLayout(new CircleLayout());
	}
}



有个问题, 顺便在这里问一下:

如何才能把弹出窗口的背景设置成透明呀??
  • 大小: 18.5 KB
分享到:
评论
11 楼 luo_shibin 2009-04-22  
经过自己的实践,前面的程序也是正确的,之所以会出现我前面提到的不透明的效果,是因为jdk版本的缘故。之前的版本是jdk5u7,换成最新的jdk6u13,就一切正常了!
收益颇多啊!呵呵!非常感谢mikewang!
10 楼 mikewang 2009-04-17  
luo_shibin 写道
我执行TestW的结果为什么是这个?
只有弹出的菜单全部在java窗口内,才正常。

有些修改的代码没上传, 现在上传一个最新版本, 你可以用 java -jar cm.jar 看到效果, 同时源程序也在jar包里面了。
9 楼 luo_shibin 2009-04-17  
我执行TestW的结果为什么是这个?



只有弹出的菜单全部在java窗口内,才正常。


8 楼 gml520 2009-03-31  
mikewang 写道
gml520 写道
这个是不是也适合 其他组件的布局呢?


当然可以

图中的5个按钮就是使用的原型布局。
setLayout(new CircleLayout());
add(new JButton("Button1"));
add(new JButton("Button2"));
add(new JButton("Button3"));
add(new JButton("Button4"));
add(new JButton("Button5"));




不错,相当的好啊,有了这个布局,有很多东西都可以用的上了。
太感谢你了。
7 楼 ailu5949 2009-03-31  
不错不错  真是好想法
6 楼 mikewang 2009-03-30  
gml520 写道
这个是不是也适合 其他组件的布局呢?


当然可以

图中的5个按钮就是使用的原型布局。
setLayout(new CircleLayout());
add(new JButton("Button1"));
add(new JButton("Button2"));
add(new JButton("Button3"));
add(new JButton("Button4"));
add(new JButton("Button5"));


5 楼 gml520 2009-03-30  
这个是不是也适合 其他组件的布局呢?
4 楼 laiseeme 2009-03-08  
不错 ,最近也弄swing了  不过一直停留在ctrl+c和ctrl+v的水平
3 楼 h819 2009-03-08  
不错啊,正要学习 swing,就是不知道从何入手
2 楼 mikewang 2009-03-06  
再次改进

1, 修复事件区域的判断的bug
2, 现在 当item < 3 时, 布局管理器可以正常工作了!



代码修改的很少, 基本都有注释, 有兴趣的朋友可以看一下。
1 楼 mikewang 2009-03-05  
改进一下



进过一天的学习
1 终于将背景搞成了“透明” (其实不是透明, 只是用了屏幕拷贝来实现而已)
2 修正了弹出窗口坐标问题(原来弹出的起点在菜单的左上角, 现在改为圆心)
3 对事件响应区做了修改, 非MenuItem不再响应事件

已知bug
当Item < 3 时候,布局管理器不能正常工作, 因为用到了三角函数,所以必须要在能构成三角形的情况下才能工作
这个bug 明天一定修正

修改的代码点评
package info.mikewang.gui.layout;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.image.BufferedImage;

import javax.swing.JPopupMenu;

public class CirclePopupMenu extends JPopupMenu {

	private static final long serialVersionUID = 7318307166817760768L;

	boolean compChanged = true;
	Rectangle[] componentRects;

	public CirclePopupMenu() {
		this.setLayout(new CircleLayout());
		setBorderPainted(false);

// 加个监听器, 防止运行时增加或者减少菜单项影响下面的事件响应区的判断
		addContainerListener(new ContainerListener() {
			@Override
			public void componentAdded(ContainerEvent e) {
				compChanged = true;
			}

			@Override
			public void componentRemoved(ContainerEvent e) {
				compChanged = true;
			}
		});
	}

//判断当前点是否在响应区域
// 实现的原理
// 挖掉除了menuitem外的所有区域
// ( 只有存在item的地方才响应事件 因为菜单本身是“透明”的 )
	@Override
	public boolean contains(int x, int y) {
// 如果内部的组件发生了改变(增加或者删除), 则要重新计算事件响应的区域
		if (compChanged) {

			int compSize = getComponentCount();
			componentRects = new Rectangle[compSize];

			Point menuPoint = getLocationOnScreen();

			Component c = null;
			Point cp = null;

			Dimension d = null;
// 算法其实很简单,就是坐标的平移
			for (int i = 0; i < compSize; i++) {
				c = getComponent(i);
				cp = c.getLocationOnScreen();
				int dx = cp.x - menuPoint.x;
				int dy = cp.y - menuPoint.y;
				d = c.getPreferredSize();
				Rectangle r = new Rectangle(dx, dy, d.width, d.height);
				componentRects[i] = r;
			}

			compChanged = false;
		}


// 真正的判断在这里
		for (Rectangle r : this.componentRects) {

			if (r.contains(x, y)) {
				return true;
			}
		}
		return false;
	}

// 覆盖 show 方法, 将弹出的位置修改到圆心
	@Override
	public void show(Component invoker, int x, int y) {

		setInvoker(invoker);

		Point invokerOrigin;
		if (invoker != null) {
			invokerOrigin = invoker.getLocationOnScreen();

			long lx, ly;
			lx = ((long) invokerOrigin.x) + ((long) x);
			ly = ((long) invokerOrigin.y) + ((long) y);

			// ------
 // 平移弹出位置到中间(就是圆心处)
			Dimension myDim = this.getPreferredSize();

			lx = lx - myDim.width / 2;
			ly = ly - myDim.height / 2;
			// ------

			if (lx > Integer.MAX_VALUE)
				lx = Integer.MAX_VALUE;
			if (lx < Integer.MIN_VALUE)
				lx = Integer.MIN_VALUE;
			if (ly > Integer.MAX_VALUE)
				ly = Integer.MAX_VALUE;
			if (ly < Integer.MIN_VALUE)
				ly = Integer.MIN_VALUE;

			setLocation((int) lx, (int) ly);
		} else {
			setLocation(x, y);
		}
		setVisible(true);

	}

	@Override
	public void paintComponent(Graphics g) {

// 拷贝屏幕作为弹出菜单的背景(假透明)

		BufferedImage background = null;
		try {
			Robot rbt = new Robot();
			Toolkit tk = Toolkit.getDefaultToolkit();
			Dimension dim = tk.getScreenSize();
			background = rbt.createScreenCapture(new Rectangle(0, 0, (int) dim
					.getWidth(), (int) dim.getHeight()));
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		Point pos = getLocationOnScreen();
		Point offset = new Point(-pos.x, -pos.y);
		g.drawImage(background, offset.x, offset.y, null);
	}
}



其他的代码都改的不多, 在附件中,请下载。 谢谢!

相关推荐

    jquery点击分享环形弹出菜单.zip

    在这个“jquery点击分享环形弹出菜单.zip”压缩包中,包含了一个利用jQuery实现的特色功能——点击分享按钮时,弹出一个环形布局的菜单。这个功能在网页设计中常用于社交媒体分享,用户只需轻轻一点,就能轻松分享...

    html5+jQuery实现的环形按钮菜单点击弹出弹性图标菜单特效源码.zip

    在"html5+jQuery实现的环形按钮菜单点击弹出弹性图标菜单特效源码.zip"这个项目中,我们将深入探讨如何利用这两种技术来构建一个独特的用户界面元素。 首先,HTML5作为现代Web标准的核心部分,提供了许多新的标签和...

    jquery环形菜单制作点击弹出图标环形菜单代码

    jquery环形菜单制作点击弹出图标环形菜单代码 jquery环形菜单制作点击弹出图标环形菜单代码 jquery环形菜单制作点击弹出图标环形菜单代码 jquery环形菜单制作点击弹出图标环形菜单代码 jquery环形菜单制作点击弹出...

    纯CSS3环形菜单动画 可展开二级子菜单

    综上所述,实现“纯CSS3环形菜单动画 可展开二级子菜单”涉及到了CSS3的多个核心特性,包括变换(`transform`)、伪类选择器(`:hover`)、过渡(`transition`)、动画(`animation`)、布局(如`flexbox`或`grid`)...

    jquery点击弹出图标环形菜单代码.zip

    本资源"jquery点击弹出图标环形菜单代码.zip"提供了一个利用jQuery实现的创新性菜单导航特效,尤其适用于增强网站的用户界面体验。 首先,环形菜单是一种独特且吸引人的设计模式,它将菜单项围绕一个中心点以圆形...

    jQuery五彩环形弹出菜单特效.rar

    【jQuery五彩环形弹出菜单特效】是一个适用于网页设计的实用工具,它基于JavaScript库jQuery和CSS样式来实现一种独特且吸引人的交互式菜单效果。这个特效将菜单项以环形排列,当用户鼠标悬停在某个菜单项上时,会以...

    Qt实现的PC端环形菜单、悬浮球菜单、动画菜单、高级菜单

    在本文中,我们将深入探讨如何使用Qt框架来实现各种创新的菜单设计,包括环形菜单、悬浮球菜单和动画菜单。这些高级菜单设计为用户界面增添了互动性和视觉吸引力,是现代应用程序中提升用户体验的重要元素。 首先,...

    很方便管理的环形菜单

    环形菜单是一种创新的用户界面元素,尤其在移动设备上,它可以提供一种高效且美观的方式来...通过学习和理解该项目的源码,开发者不仅可以掌握环形菜单的实现原理,还能深入理解Android应用开发中的核心概念和技术。

    android 弹出弧形菜单

    5. **布局管理**:合理安排菜单项的位置,可能需要用到RelativeLayout或LinearLayout等布局容器。 6. **状态保存与恢复**:如果需要,还需考虑菜单的打开/关闭状态在配置更改(如屏幕旋转)时的保存和恢复。 在提供...

    一个别致的环形菜单.zip

    环形菜单是一种创新的用户界面元素,...总之,"一个别致的环形菜单.zip" 提供了一个学习和实践Android自定义视图和动画的好机会,同时也展示了开源文化的力量,让开发者能够从他人的工作成果中获益,并为社区做出贡献。

    WPF 环形菜单控件

    对于环形菜单,我们需要自定义布局管理器来使菜单项围绕中心点呈环状排列。 2. **几何形状** - 使用`Path`或`Shape`类来绘制环形和菜单项的形状。环形可能由`ArcSegment`或`PieSegment`来构建,而菜单项可以是圆形...

    非常漂亮的环形菜单

    环形菜单是一种创新的用户界面元素,它将菜单项组织成一个圆形布局,通常用于触摸屏设备或图形用户界面中,以提供独特且直观的交互体验。这种设计可以使用户通过旋转手势来浏览和选择不同的功能或操作,尤其适用于...

    动态环形菜单

    在Android开发中,动态环形菜单是一种独特且吸引用户的交互设计。它通常用于展示一系列可选操作,如应用的功能选项或者设置项,用户通过点击或滑动触发菜单展开或收起,形成一个环绕中心的环状布局。这种设计在很多...

    jquery css3仿游戏网站环形菜单代码.rar

    这个环形菜单利用了jQuery的强大功能和CSS3的现代特性,实现了一个可旋转弹出并能平滑收回的效果,同时伴有音效,使得用户操作更加生动有趣。 首先,jQuery是JavaScript的一个库,它简化了DOM操作、事件处理、动画...

    jquery实现点击弹出图标环形菜单特效源码.zip

    在这个函数中,我们将编写弹出环形菜单的逻辑。 接下来,我们讨论环形菜单的布局。环形布局通常需要利用CSS3的transform属性,特别是rotate和translate。当用户点击图标后,我们可以动态修改子元素的transform值,...

    CSS3环形菜单切换动画特效

    在本文中,我们将深入探讨如何实现“CSS3环形菜单切换动画特效”,这是一种现代且具有科技感的网页设计技术。CSS3(层叠样式表第三版)为网页设计师提供了丰富的功能,包括过渡、动画和变换,使我们能够创建出动态且...

    环形动画菜单特效代码

    1. **圆角边框**:通过`border-radius`属性,我们可以创建出圆形的菜单项,这为环形布局奠定了基础。 2. **定位和布局**:使用`position`(如`relative`或`absolute`)和`transform`属性,可以精确控制菜单项的位置...

    ios-环形标签菜单(demo功能大全).zip

    这个“ios-环形标签菜单(demo功能大全).zip”文件很可能包含了多种实现环形菜单的示例代码,帮助开发者了解并学习如何在自己的应用中实现类似的功能。 环形菜单的核心在于其布局方式,它将各个菜单项分布在圆形的...

    环形菜单实现

    - **学习曲线**:对于习惯传统菜单的用户来说,环形菜单可能需要一些时间去适应。 - **可读性**:如果菜单项过多,或者文字和图标不清晰,可能会降低用户的识别速度。 - **无障碍性**:对于视力障碍或动作受限的用户...

    css3旋转的环形菜单动画特效

    在本文中,我们将深入探讨如何使用CSS3实现一个旋转的环形菜单动画特效。CSS3是层叠样式表的最新版本,它引入了许多强大的新特性,包括2D和3D变换、过渡效果以及动画,使得网页设计更加动态和富有表现力。 首先,让...

Global site tag (gtag.js) - Google Analytics