Java Swing 编程一二


Java Swing 编程一二

最近,参照 JDK API 手册,及一本 《Java 语言程序设计》 (ISBN: 7-302-10635-5),尝试去写窗体程序,由于书中 Swing 编程不是重点,内容较少,因此在代码编写中,产生许多困惑.在边查资料边思考中,记录以下.

一: Look & Feel
  使用 javax.swing.UIManager 可以更改界面风格, 应该在创建画面之前执行,否则设置有可能不起作用. 在 GUI 显示后,也可以改变界面风格,但可见组件不会自动更新显示外观,需要对每个顶层容器调用 SwingUtilities.updateComponentTreeUI() 方法.
  主要的 Look & Feel  有:  Java/Metal, Windows, CDE/Motif, 但如果有其它的 L&F 包,还可以扩展.只要指定类名加载即可.
 
  设置语句:

Java code
   
   
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); // 当前系统默认 UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); // 跨平台 UIManager.setLookAndFeel( " com.sun.java.swing.plaf.windows.WindowsLookAndFeel " ); // Windows L & F

 
  更新显示语句:
  SwingUtilities.updateComponentTreeUI(frame);
 
  Look & Feel 界面风格, 影响了各种可视组件的外观, 大致有颜色,字体,滚动条样式等.
 
二: 显示字体
  在对 JFrame 设置字体时,未发现有何变化,其内含的组件字体未跟着改变,没有想当然的继承现象.目前只能遍历,一个个地进行字体设置.

 

  代码:

Java code
   
   
public static void main(String[] args) { // 创建窗体 JFrame frame = new JFrame("Swing Test"); frame.setLayout(new BorderLayout()); // 设置窗体字体(似乎无效) frame.setFont(new Font("Courier New", Font.PLAIN, 24)); // 创建文本标签 final JLabel label = new JLabel("mostone@hotmail.com"); frame.add(label, BorderLayout.CENTER); // 创建命令按钮 JButton button = new JButton("Test"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // 点击按钮,改变文本标签的字体(有效) label.setFont(new Font("Courier New", Font.PLAIN, 24)); } }); frame.add(button, BorderLayout.SOUTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(350, 250); frame.setVisible(true); }


    按钮点击前:

    按钮点击后:

    
    字体设置未被继承的原因,可能是在 JLabel 创建时,已经被设置了默认字体(应该是从 Look & Feel 中继承而来的),在添加到 JFrame 容器中时,并未重新取得字体,因此与容器没有继承关系,而与 Look & Feel 存在继承关系(以上只是猜测,未经确认!)
三: 画面布局
  在容器上添加的组件,似乎都在布局对象的管理下,无法使用绝对坐标放置可视组件,因为我调用 JLabel.setLocation() 无效,查看API帮助文档,也没有找到特别说明,但猜测,是否存在一种画面布局,可以让用户自由摆放可视组件.
  对于画面布局对象,书上及 API 帮助都有比较详细的说明,只要试几次,还是比较容易理解的.但布局对象比较丰富,初学者就选择来说,有点困难,必须要对所有布局对象都了解的情况下,才能决定最优选择.
  比较常用的有: FlowLayout(流式), BorderLayout(边界), GridLayout(网格), CardLayout(卡片), GridBagLayout(网格包),以上是 java.awt 包中提供的;另外在 javax.swing 包中,还提供了:BoxLayout, SpringLayout 等.

 

  setLocation() 对于顶层的 JFrame 倒是有效的,下面是将窗口以当前屏幕居中显示的代码:

Java code
   
   
// move to center of screen Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = frame.getSize(); if (frameSize.height > screenSize.height) { frameSize.height = screenSize.height; } if (frameSize.width > screenSize.width) { frameSize.width = screenSize.width; } frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);


四: JScrollPane 与 JTextArea
    代码:

Java code
   
   
JScrollPane scrollPane; // input textbox JTextArea inputTextbox = new JTextArea(); scrollPane = new JScrollPane(inputTextbox); pnlInput.setLayout( new GridLayout( 0 , 1 )); pnlInput.add(inputTextbox);

        运行以上代码后,输入大块广西,但并未出现预期中的滚动条, 将最后一句代码改成: pnlInput.add(scrollPane);后,终于出现了滚动条.出现这个问题是将两者的关系弄反了,应该是 JScrollPane 包含 JTextArea,而不是 JTextArea 主动关联 JScrollPane.
       
五: 设置焦点
  使用 .NetFrameWork,或是 DHTML,设置焦点都是类似于 xxx.focus() 的写法,以此参照,我差点找不到 swing 控件中相应的方法,最后发现,原来是: xxx.requestFocus(), 看起来比直接 focus() 委婉了些,这似乎更合理吧,本来就不是说任何情况下,都能获得焦点的,以请求式对应前者的命令式,swing 要客气得多 :)

六: 加载图标
  加载图标,还是比较简单的,代码:
        ImageIcon icon = new ImageIcon("icon.png");
        frame.setIconImage(icon.getImage()); 

七: 标准对话框
  JOptionPane 提供了标准对话框,可以方便使用,以下摘录自API帮助文档:

Java code
   
   
// 显示一个错误对话框,该对话框显示的 message 为 'alert': JOptionPane.showMessageDialog( null , " alert " , " alert " , JOptionPane.ERROR_MESSAGE); // 显示一个内部信息对话框,其 message 为 'information': JOptionPane.showInternalMessageDialog(frame, " information " , " information " , JOptionPane.INFORMATION_MESSAGE); // 显示一个信息面板,其 options 为 "yes/no",message 为 'choose one': JOptionPane.showConfirmDialog( null , " choose one " , " choose one " , JOptionPane.YES_NO_OPTION); // 显示一个内部信息对话框,其 options 为 "yes/no/cancel",message 为 'please choose one',并具有 title 信息: JOptionPane.showInternalConfirmDialog(frame, " please choose one " , " information " , JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); // 显示一个警告对话框,其 options 为 OK、CANCEL,title 为 'Warning',message 为 'Click OK to continue': Object[] options = { " OK " , " CANCEL " }; JOptionPane.showOptionDialog( null , " Click OK to continue " , " Warning " , JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null , options, options[ 0 ]); // 显示一个要求用户键入 String 的对话框: String inputValue = JOptionPane.showInputDialog( " Please input a value " ); // 显示一个要求用户选择 String 的对话框: Object[] possibleValues = { " First " , " Second " , " Third " }; Object selectedValue = JOptionPane.showInputDialog( null , " Choose one " , " Input " , JOptionPane.INFORMATION_MESSAGE, null , possibleValues, possibleValues[ 0 ]);

parentComponent
定义作为此对话框的父对话框的 Component。通过两种方式使用此参数:包含它的  Frame 可以用作对话框的父  Frame,在对话框的位置使用其屏幕坐标。一般情况下,将对话框紧靠组件置于其之下。此参数可以为 null,在这种情况下,默认的 Frame 用作父级,并且对话框将居中位于屏幕上(取决于 L&F)。

在上面这段话中,"默认的 Frame 用作父级",对于默认的 Frame 不知道所指为何,有可能是 Application 所创建的第一个 Frame 吧.

八: 事件绑定
  用惯了 Delphi, C# 这些开发语言,一开始很不习惯 Swing 中的事件绑定方式.在 Swing 中,如果要给按钮添加 click 事件处理方法,需要调用 button.addActionListener(aActionListenerObject);必须要给出一个实现了相应接口的类对象.而在 C# 中,是可以直接将方法以对象方式访问,创建一个处理方法的句柄,从代码上来说,要简单得多.
  在 Swing 中,如果所有处理方法都在Frame继承类里添加,则有两个问题:一是如果有多个按钮事件,则需要在同一个处理方法里,作筛选;另外,如果有N多种类型的处理方法,则Frame继承类要实现N多的接口,在类定义后要写一堆 implements 接口定义,个人认为很不雅观; 如果每个事件处理方法,新建一个处理类,则文件会增加太多,一个窗口的处理机能,相关代码太分散;当然,也可以在创建组件时,直接创建事件处理类对象,但也有一点不好,初始化代码与事件处理代码纠缠在一起,显得比较混乱.
  基于以上考虑,我能想到的做法是另写一个方法,专门返回一个匿名的事件处理类对象,以模拟类似于 Delphi 的代码风格:

Java code
   
   
@Override protected void frameInit() { super .frameInit(); JButton button = new JButton( " Test " ); this .add(button); button.addActionListener( this .onTestButtonClick()); ... } private ActionListener onTestButtonClick(){ return new ActionListener(){ public void actionPerformed(ActionEvent e){ JOptionPane.showMessageDialog( null , " alert " , " alert " , JOptionPane.ERROR_MESSAGE); } } }

    这里的内部匿名类,要访问外部类成员时,这个成员应该是final的,如果成员名称与内部类成员名称冲突,可以使用外部类名来访问,如:
MainFrame.this.inputTextbox.setText("Test String...");
   
九:事件处理机制
  不管是什么样的代码,最终 CPU 还是顺序执行的,以面向过程编辑来看上面(二)中的示例代码,当程序执行到 frame.setVisible(true);没有后续的代码,应当正常结束程序并返回.但这段代码并没有.
  在 Delphi7 的 WinForm 程序中,有个 Application.run() 方法,这个方法会开始执行消息处理,换种说法,也可以说是执行一个"死循环",不断地从系统消息棧中提取消息并分发到相应处理方法中,直到主窗口被关闭.
  同样,Swing 窗口程序也应该存在类似的处理,这可能在程序创建 JFrame 时,后面还有一个隐藏的 "Application" 对象在工作吧.

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值