ButtonGroup.doc_第1页
ButtonGroup.doc_第2页
ButtonGroup.doc_第3页
ButtonGroup.doc_第4页
ButtonGroup.doc_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Java技巧: 推动JButtonGroup发布时间:2005-01-19 08:00:00 来源: 作者: 点击:283摘要 Swing的 ButtonGroup 类允许单选按钮分组以保证单一选择;但是,这个实现引起了许多问题标记。你不能检索到组中当前选择的按钮的引用,并且类允许你选择或者取消选择通过引用访问的任何按钮,不是组中成员也可。本技巧描述了当提供便利的、使得JButtonGroup更加易于使用的方法时JButtonGroup 子类ButtonGroup如何提供更为可靠的实现。 Swing有许多有用的类,这些类可简化绘图用户界面(GUI)的开发。 但是,其中有一些类实现起来不那么容易,如ButtonGroup。本文解释了为什么ButtonGroup 难于设计并提供了一个代替的类,JButtonGroup,它继承了ButtonGroup并解决了ButtonGroup的某些问题。 注意: 你可从Resources处下载本文的源代码。 ButtonGroup 突破口 在开发Swing GUI 经常会出现这样的情况:你建立了一个表格来收集关于输入到数据库或者保存到文件中的数据项。这个表格可能包括文本框、单选按钮和其他窗口小部件。你使用ButtonGroup 类将所有需要单一选择的单选按钮分组。当表格设计准备好了的时候,你开始填写表格数据。你遇到一组单选按钮,你需要知道组中哪个按钮被选了这样你就能储存恰当的信息到数据库或者文件中。你现在卡住了。为什么? ButtonGroup 类不提供到组中当前所选按钮的引用。 ButtonGroup有一个getSelection()方法,它返回所选按钮的模型(作为ButtonModel 类型),但不是按钮本身。现在,如果你能够从模型中得到按钮引用那也好,但是你得不到。ButtonModel 接口和它的实现类不允许你从它的模型中检索按钮引用。那你怎么办?你仔细看看ButtonGroup 文档你会看到getActionCommand()方法。你想想如果你使用按钮旁边显示文本的String 来例示JRadioButton 的话,你调用按钮上的getActionCommand(),构造器中的文本就会返回。你可能会以为你仍然使用代码工作,因为虽然你没有按钮引用,至少你有了它的文本而且仍然知道所选的按钮。 好,太棒了!可奇怪的是,你的代码在运行过程出现NullPointerException。为什么?因为ButtonModel中的getActionCommand() 返回null。如果你赌(像我一样) getActionCommand()在按钮上的调用或者在模型上的调用也出现了同样的异常(许多其他的方法都是这样,如 isSelected()、isEnabled()、或者getMnemonic()),那你就错了。如果你确实没有调用按钮上的setActionCommand(),你没有在它的模型中设置作用指令的话, 获得器方法就会返回对于模型的null 。但是,调用按钮上的获得器方法,它确实会返回按钮文本。下面就是AbstractButton 中的 getActionCommand() ,继承于Swing 中的所有按钮类: public String getActionCommand() String ac = getModel().getActionCommand();if(ac = null) ac = getText();return ac;设置和获得行为指令之间的矛盾是无法接受的。如果当行为指令为空时,AbstractButton 中的setText()设置模型的行为指令到按钮文本上,你就能避免这种矛盾。毕竟,除非setActionCommand()使用某些String参数(非空)来调用,否则按钮文本总是被按钮本身当作行为指令。为什么模型表现如此不同呢? 当你的代码需要到ButtonGroup 中的当前所选按钮的引用,你得遵循下列步骤,这些步骤中没有一个调用了getSelection(): ?调用ButtonGroup 上的getElements(),它将返回一个Enumeration ?通过Enumeration迭代,以便得到每个按钮的引用 ?调用每个按钮上的 isSelected(),判断出它是否被选 ?返回引用到返回true 的按钮上 ?或者,如果你需要行为指令,调用按钮上的getActionCommand() 如果这些步骤看起来过于繁杂的话,请往下读。我认为 ButtonGroup的实现根本上是错误的。它保存的是到所选按钮模型的引用,实际上它应该保存到所选按钮的引用。而且, getSelection()检索所选按钮的方法,你会认为相应的设置器方法就是setSelection(),可实际上它不是,而是setSelected()。现在,setSelected()有一个大问题。它的参数是ButtonModel和布尔值。如果你调用ButtonGroup 上的setSelected(),并传递按钮的非该组成员的模型和参数true , 那么该按钮被选,组中其他按钮则为非被选。换句话说, ButtonGroup 有权决定传递到它的方法处的按钮选择还是不选择,即使该按钮与该组毫无关系。这种行为是存在的,因为ButtonGroup 中的setSelected()不检查作为参数收到的 ButtonModel引用是否代表组中的按钮。而且由于该方法坚持单一选择,它实际上不选自己的按钮而选择与该组无关的按钮。 这种约定在ButtonGroup文档中表现得更为有趣: 我们无法为了清除按钮组而程序化地关闭按钮。为了表现出“非被选”,添加一个可见的单选按钮到组中,然后程序化地选择该按钮来关闭所有显示的单选按钮。例如:可安装带有卷标none的普通按钮来选择可见的单选按钮。 很好,但是这不现实:你可以使用任何按钮,放在你的应用程序中的任何位置,可见或不可见,设置也可以是无效的。是的,你甚至可以使用按钮组来选择一个组外的无效按钮,并且它仍然还可以取消对它所有按钮的选择。要得到组中所有按钮的引用,你得调用这个机械的getElements()。elements 能对ButtonGroup做些什么,大家都知道。getElements(),的命名可能就是受Enumeration类的方法 (hasMoreElements()和nextElement()所启发,但是getElements()无疑应该命名为 getButtons()。因为按钮组分组的是按钮,而不是元素。 你可以在本文最后一页的JavaWorld Talkback发表你的评论,看看你的同行们会如何回答你。Solution: JButtonGroup 由于以上原因,我想要实现一个新的类,这个类可以解决ButtonGroup 中的错误并且提供一些功能和便利给用户。我不得不决定创建一个新类还是由ButtonGroup衍生。所有上述的讨论都建议我创建一个新类而不是创建ButtonGroup的子类。但是, ButtonModel接口需要一个能够接受ButtonGroup参数的方法setGroup()。除非我也准备重新实现按钮模型,否则我只能选择创建ButtonGroup 子类并用它覆盖ButtonGroup的大部分方法。说到 ButtonModel接口,注意它不包括方法 getGroup()。 我没有提到的另一个方案就是ButtonGroup 内部将到它的按钮的引用保存在Vector中。当他使用ArrayList时,因为这个类本身为非线程安全,同时Swing是单线程的。因此,它没有必要得到同步的Vector的系统开销。但是,受保护的变量buttons公告为Vector 类型,而不是你希望的良好编程的类型List 。因此,我不能把这个变量当作ArrayList 来实现;并且因为我想调用super.add()和super.remove(),我不能隐藏超类变量。所以我放弃了这个方案。 我假设类JButtonGroup与大部分的Swing类的名称保持一致。该类可遍历ButtonGroup 中的大部分方法并能提供额外的便利的方法。它保存到当前所选按钮的引用,你可以使用一个简单的到getSelected()的调用来检索它。由于ButtonGroup的实现能力很差,我可以将我的方法命名为getSelected(),因为getSelection()方法返回的是按钮模型。 下面就是JButtonGroup的方法。 首先,我得对add()方法作两个修改:如果需要添加的按钮在组中,方法返回。因此,你只能添加按钮到组中一次。有了ButtonGroup,你可以创建一个JRadioButton 并将它添加到组中10次。调用getButtonCount() 则会返回10。这一般不会这样用,所以我不允许复制的引用。这样,如果所添加的按钮前面选择过,那它就会变成所选按钮(这种行为在ButtonGroup 中是默认的,这是合理的。所以我不想修改它)。变量selectedButton 是到组中当前所选按钮的引用: public void add(AbstractButton button) if (button = null | buttons.contains(button) return;super.add(button);if (getSelection() = button.getModel() selectedButton = button;超载的add()方法添加了整个排列的按钮到组中。当你想储存按钮引用到排列中以便于块处理(如设置边界,添加行为听取器等等),这是很有用的: public void add(AbstractButton buttons)if (buttons = null) return;for (int i=0; ibuttons.length; i+)add(buttonsi);下面的两个方法删除了组中的一个按钮或者一个排列的按钮: public void remove(AbstractButton button)if (button != null)if (selectedButton = button) selectedButton = null;super.remove(button);public void remove(AbstractButton buttons)if (buttons = null) return;for (int i=0; ibuttons.length; i+)remove(buttonsi);今后,第一个setSelected()方法允许你通过按钮引用而不是通过按钮模型来设置按钮的选择状态。第二个方法顶替了ButtonGroup 中相应的setSelected(),以保证组只能选择或者取消选择组中的按钮: public void setSelected(AbstractButton button, boolean selected)if (button != null & buttons.contains(button)setSelected(button.getModel(), selected);if (getSelection() = button.getModel() selectedButton = button;public void setSelected(ButtonModel model, boolean selected)AbstractButton button = getButton(model);if (buttons.contains(button) super.setSelected(model, selected);getButton()方法检索了到模型给出的按钮的引用。setSelected()使用这个方法来检索 所选的要求给出它的模型的按钮。如果传递到方法的模型属于组外的按钮,则getButton()返回null 。这个方法应该存在于ButtonModel 实现中,不幸的是它没有: public AbstractButton getButton(ButtonModel model)Iterator it = buttons.iterator();while (it.hasNext()AbstractButton ab = (AbstractButton)it.next();if (ab.getModel() = model) return ab;return null;getSelected()和 isSelected()是JButtonGroup类中最简单的,也是最有用的方法。getSelected()返回到所选按钮的引用并且isSelected() 超载ButtonGroup 中的同名方法来得到按钮引用: public AbstractButton getSelected()return selectedButton;public boolean isSelected(AbstractButton button)return button =

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论