随笔 - 18  文章 - 96  trackbacks - 0
<2007年9月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456


常用链接

留言簿(4)

随笔档案

相册

我的兄弟们

搜索

  •  

最新评论

阅读排行榜

评论排行榜

接着昨天的MyJTextField,我们继续为JTextField增强,今天我们为MyJTextField增加一个泡泡提示。先看图片:

当输入第三个字符'a'时,由于昨天我们的MyJTextField做了处理,所以'a'不能被输入,而且弹出泡泡提示你下次不要了哟!
同样的,下一张图片:


为MyJTextField增加泡泡提示功能要做以下几件事情:
1. 泡泡窗口
2. 显示的时候计算位置

这里我使用了Bernhard Pauler的BalloonTip包的BalloonBorder代码,改造了BalloonTip代码,好废话不说,放上完整代码后再解释:
  1 /**
  2  * @(#)MyJTextField.java  0.1.1  2007-9-8
  3  */
  4 package ruislan;
  5 
  6 import java.awt.BorderLayout;
  7 import java.awt.Color;
  8 import java.awt.Component;
  9 import java.awt.Container;
 10 import java.awt.Font;
 11 import java.awt.Point;
 12 import java.awt.event.ComponentAdapter;
 13 import java.awt.event.ComponentEvent;
 14 import java.awt.event.KeyAdapter;
 15 import java.awt.event.KeyEvent;
 16 
 17 import javax.swing.Icon;
 18 import javax.swing.ImageIcon;
 19 import javax.swing.JDialog;
 20 import javax.swing.JFrame;
 21 import javax.swing.JLabel;
 22 import javax.swing.JLayeredPane;
 23 import javax.swing.JPanel;
 24 import javax.swing.JTextField;
 25 import javax.swing.border.EmptyBorder;
 26 
 27 import net.java.balloontip.BalloonBorder;
 28 
 29 
 30 /**
 31  * Custom JTextField.
 32  * 
 33  * @version 0.1.1, 2007-9-9
 34  * @author ruislan <a href="mailto:z17520@126.com"/>
 35  */
 36 public class MyJTextField extends JTextField {
 37     private static final Color TIP_COLOR = new Color(255255225);
 38     private int limit = Integer.MAX_VALUE;
 39     private boolean numberOnly;
 40     private CoolToolTip numberTip;
 41     private CoolToolTip limitTip;
 42     private ImageIcon tipIcon;
 43 
 44     public MyJTextField() {
 45         initComponents();
 46         initEventListeners();
 47     }
 48 
 49     private void initComponents() {
 50         tipIcon = new ImageIcon(MyJTextField.class.getResource("tip.gif"));
 51 
 52         numberTip = new CoolToolTip(this, TIP_COLOR, getColumns(), 10);
 53         numberTip.setText("只能输入数字!");
 54         numberTip.setIcon(tipIcon);
 55         numberTip.setIconTextGap(10);
 56 
 57         limitTip = new CoolToolTip(this, TIP_COLOR, getColumns(), 10);
 58         limitTip.setIcon(tipIcon);
 59         limitTip.setIconTextGap(10);
 60     }
 61 
 62     private void initEventListeners() {
 63         addKeyListener(new KeyAdapter() {
 64             @Override
 65             public void keyTyped(KeyEvent e) {
 66                 if (getText().length() + 1 > limit) {
 67                     deleteInputChar(e);
 68                     limitTip.setVisible(true);
 69                     return;
 70                 } else {
 71                     limitTip.setVisible(false);
 72                 }
 73                 if (numberOnly) {
 74                     char input = e.getKeyChar();
 75                     if (!Character.isDigit(input)) {
 76                         numberTip.setVisible(true);
 77                         deleteInputChar(e);
 78                     } else {
 79                         numberTip.setVisible(false);
 80                     }
 81                 }
 82             }
 83 
 84             private void deleteInputChar(KeyEvent source) {
 85                 source.setKeyChar((char) KeyEvent.VK_CLEAR);
 86             }
 87         });
 88     }
 89 
 90     public void setMaxTextLength(int limit) {
 91         if (limit < 0) {
 92             return;
 93         }
 94         this.limit = limit;
 95         limitTip.setText(String.format("超过最大长度 \"%d\"", limit));
 96     }
 97 
 98     public int getMaxTextLength() {
 99         return limit;
100     }
101 
102     public void setNumberOnly(boolean numberOnly) {
103         this.numberOnly = numberOnly;
104     }
105 
106     public boolean isNumberOnly() {
107         return this.numberOnly;
108     }
109 
110     private class CoolToolTip extends JPanel {
111         private JLabel label = new JLabel();
112         private boolean haveShowPlace;
113 
114         private Component attachedComponent;
115 
116         public CoolToolTip(Component attachedComponent, Color fillColor,
117                 int borderWidth, int offset) {
118             this.attachedComponent = attachedComponent;
119 
120             label.setBorder(new EmptyBorder(borderWidth, borderWidth,
121                     borderWidth, borderWidth));
122             label.setBackground(fillColor);
123             label.setOpaque(true);
124             label.setFont(new Font("system"012));
125 
126             setOpaque(false);
127             this.setBorder(new BalloonBorder(fillColor, offset));
128             this.setLayout(new BorderLayout());
129             add(label);
130 
131             setVisible(false);
132 
133             // if the attached component is moved while the balloon tip is
134             // visible, we need to move as well
135             attachedComponent.addComponentListener(new ComponentAdapter() {
136                 public void componentMoved(ComponentEvent e) {
137                     if (isShowing()) {
138                         determineAndSetLocation();
139                     }
140                 }
141             });
142 
143         }
144 
145         private void determineAndSetLocation() {
146             Point location = attachedComponent.getLocation();
147             setBounds(location.x, location.y - getPreferredSize().height,
148                     getPreferredSize().width, getPreferredSize().height);
149         }
150 
151         public void setText(String text) {
152             label.setText(text);
153         }
154 
155         public void setIcon(Icon icon) {
156             label.setIcon(icon);
157         }
158 
159         public void setIconTextGap(int iconTextGap) {
160             label.setIconTextGap(iconTextGap);
161         }
162 
163         public void setVisible(boolean show) {
164             if (show) {
165                 determineAndSetLocation();
166                 findShowPlace();
167             }
168             super.setVisible(show);
169         }
170 
171         private void findShowPlace() {
172             if (haveShowPlace) {
173                 return;
174             }
175             // we use the popup layer of the top level container (frame or
176             // dialog) to show the balloon tip
177             // first we need to determine the top level container
178             Container parent = attachedComponent.getParent();
179             JLayeredPane layeredPane;
180             while (true) {
181                 if (parent instanceof JFrame) {
182                     layeredPane = ((JFrame) parent).getLayeredPane();
183                     break;
184                 } else if (parent instanceof JDialog) {
185                     layeredPane = ((JDialog) parent).getLayeredPane();
186                     break;
187                 }
188                 parent = parent.getParent();
189             }
190             layeredPane.add(this, JLayeredPane.POPUP_LAYER);
191             haveShowPlace = true;
192         }
193     }
194 }
195 

测试代码:
 1 package ruislan.examples;
 2 
 3 import java.awt.Container;
 4 import java.awt.Dimension;
 5 import java.awt.GridBagLayout;
 6 import java.awt.Toolkit;
 7 
 8 import javax.swing.JFrame;
 9 
10 import ruislan.MyJTextField;
11 
12 public class MyJTextFieldTest {
13 
14     public static void main(String[] args) {
15         JFrame frame = new JFrame();
16         Container contentPane = frame.getContentPane();
17         contentPane.setLayout(new GridBagLayout());
18         final MyJTextField textField = new MyJTextField();
19         textField.setNumberOnly(true);
20         textField.setColumns(15);
21         textField.setMaxTextLength(5);
22         contentPane.add(textField);
23 
24         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
25         frame.setSize(320240);
26         centerWindow(frame);
27         frame.setTitle("MyJTextField");
28         frame.setVisible(true);
29     }
30 
31     public static void centerWindow(Container window) {
32         // get the size of the screen
33         Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
34 
35         // determine the new location of the window
36         int w = window.getSize().width;
37         int h = window.getSize().height;
38         int x = (dim.width - w) / 2;
39         int y = (dim.height - h) / 2;
40 
41         // move the window
42         window.setLocation(x, y);
43     }
44 }
45 

就以上代码解释一下
1. 为什么CoolToolTip不使用JWindow而使用JPanel?
不错,JWindow可以放置在屏幕的任意位置,而且也是我的首选,但是JWindow是调用native代码来绘图,没有提供可以改变形状的API(我们需要泡泡嘛),所以使用了JPanel,那么这就具有了局限性,第一个就是我们在显示泡泡的时候必须找到最高级的组件来显示,以便覆盖到其下的所有子组件,第二个就是显示的区域受到了最高级组件的局限,例如JFrame上只有一个MyJTextField,而JFrame.pack了之后大小刚好是MyJTextField的大小,这样就看不到CoolToolTip了。

2. 为什么CoolToolTip在setVisible的时候才找一个要show的地方?
这个操作在Bernhard Pauler的BalloonTip代码中是由构造方法来完成的,但是这里就会出现一个问题,对,NullPointer,因为Swing不像SWT,是在component.add(child)方法调用的时候才设置child的Parent,而非在构造child的时候将component放入,所以我们只有懒加载来避免这个情况发生。说到懒加载我发表一下一个题外意见,在下认为懒加载在swing中不要用得太过频繁,用户体验是第一位的,在下宁愿在启动程序的时候看进度条也不愿在启动某个视图的时候突然卡死一小会。

3. 还有什么没有做的?
例如当输入Esc、Backspace、Enter等等按键的时候CoolToolTip也会跳出来show一把,我们必须过滤掉它们!

今天就到这里吧,下一次我们让MyJTextField更酷一点,我们为它加上Beep声音,当我们输入了非法字符的时候就beep、beep的叫唤,没有声音也没有泡泡提示的话有些人很可能是以为自己的键盘坏掉了。

本人就对QQ的登录窗口很有意见,每次我开机都是Eclipse和QQ一起打开的,一般操作都是先登录QQ,但是有一天我QQ后打开的,我正在happy coding,突然输入的字符全乱了套,我以为是输入的问题,结果是英文也,然后我认为可能是eclipse的问题(因为有的时候eclipse的代码编辑区就无端不让操作了),换成了记事本,结果也是这个情况,然后就有点慌以为键盘坏掉了,毕竟换一个笔记本键盘很贵的说(在找问题其间多次路过QQ的登录窗口,我还嫌其碍事最小化了),维修部电话打过之后他们叫我拿过去,我就准备关电脑,也不知道怎的,在我关闭了一系列的程序包括QQ登录窗口之后,我突然又想最后确定一下,当然结果很明显又好了,这个时候我就像修复程序BUG一样,找到恢复正常前的最后一个动作,重复操作直到又不正常为止,终于发现是QQ登录框的问题,气煞我也,差点就花钱换一个键盘了...

posted on 2007-09-09 13:32 ruislan 阅读(5158) 评论(2)  编辑  收藏

FeedBack:
# re: 带提示的JTextField 2007-09-09 15:33 darkhe
顶顶顶啊。。。  回复  更多评论
  
# re: 带提示的JTextField 2007-12-05 11:58 等待
顶  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: