你的位置:首页 > Java教程

[Java教程]Java Swing快速构建窗体应用程序


  以前接触java感觉其在桌面开发上,总是不太方便,没有一个好的拖拽界面布局工具,可以快速构建窗体. 最近学习了一下NetBeans IDE 8.1,感觉其窗体设计工具还是很不错的 , 就尝试一下做了一个窗体应用程序. 总体下来,感觉和winform开发相差也不大,只是一些具体的设置或者语法有些差异,可以通过查阅相关资料进行掌握:

1 应用结构

新建一个java应用程序JavaApp,并创建相关的包及文件,其中简单实现了一个登录界面(JDBC 访问MYSQL数据库),登录成功后跳转到主界面.在主界面上单击菜单,可以打开子窗体.java swing自带的JTabbedPane没有显示关闭按钮的功能,这里在com.mkmis.controls包下自定义了一个TabbedPane控件,可以实现带关闭按钮的页签面板.应用结构如下图所示:

2 登陆界面设计

在IDE中新建一个Login的JFrame窗体,单击[设计]视图,可以将组件面板中的相关控件拖放到界面上,和Vistual Studio的操作差别不大,就是界面显示效果较差,不及Vistual Studio.用户名文本框用的文本字段,密码框用的是口令字段控件.登录和退出按钮用的是按钮控件.

设计完成后,单击运行按钮,界面效果如下图所示:

3 相关属性设置

Java Swing的很多属性设置用的方法,而NET用的属性.例如设置窗体标题,java swing用的是setTitle().另外窗体居中用的是setLocationRelativeTo(getOwner()). 获取文本框的值为getText()方法,如下代码所示:

1   public Login() {    2     initComponents();3     setTitle("登录");  4     setDefaultCloseOperation(EXIT_ON_CLOSE);  5     setVisible(true);   6     setResizable(false);  7     setLocationRelativeTo(getOwner()); //居中显示8 9   }

 1 private void btnLoginActionPerformed(java.awt.event.ActionEvent evt) {                      2   // TODO add your handling code here: 3   if(this.txtUserName.getText()!="" && this.txtPWD.getText().toString()!="") 4   { 5     Connection conn = DBConnection.getConnection(); 6     PreparedStatement ps = null; 7     ResultSet rs = null; 8     try { 9       ps = conn.prepareStatement(
         "select * from users where UserName = ? and password = ?");10 ps.setString(1,this.txtUserName.getText());// 11 ps.setString(2, this.txtPWD.getText());12 rs = ps.executeQuery();13 while (rs.next()) {14 User user = new User();15 user.setId(rs.getInt("id"));16 user.setUsername(rs.getString("UserName"));17 user.setPassword(rs.getString("password"));18 19 System.out.println(user.toString());20 //跳转页面21 FrameMain frm=new FrameMain(user.getUsername());22 frm.setVisible(true);23 this.dispose();//关闭当前窗体24 25 }26 } catch (SQLException e) {27 e.printStackTrace();28 } finally {29 DBConnection.closeResultSet(rs);30 DBConnection.closeStatement(ps);31 DBConnection.closeConnection(conn);32 }33 34 }35 }

 显示一个窗体是设置其setVisiable(true);关闭一个窗体用的dispose();在登录界面想着输完用户名和密码后,按enter键可以自动登录,在网上搜下,发现了一个变通的方法,就是监听密码框的keypressed事件,当然需要验证一下用户名和密码是否为空(此处未加验证!),如下代码所示:

1  private void txtPWDKeyPressed(java.awt.event.KeyEvent evt) {                 2     // TODO add your handling code here:3     if(evt.getKeyCode()==KeyEvent.VK_ENTER)4     {5       //调用登录事件6       btnLoginActionPerformed(null);7       8     }9   }    

 4 主界面

登录成功后,单击左边的树叶节点,通过反射动态实例化窗体(实际上菜单应该从数据库加载)并显示,主界面如下:

 图表控件用的是JFreeChart控件,默认显示中文有乱码情况,需要设置显示中文处的字体进行解决.另外设置主界面显示最大化的代码为this.setExtendedState(this.getExtendedState()|JFrame.MAXMIZED_BOTH).为了让某个控件可以随着窗体大小变化而自动调整,需要设置其水平和垂直自动调整.

 1   public FrameMain(){ 2     initComponents(); 3     setLocationRelativeTo(getOwner()); //居中显示 4     this.setExtendedState(this.getExtendedState()|JFrame.MAXIMIZED_BOTH );
       //最大化 window 5 LoadTree(); 6 7 } 8 public FrameMain(String uname){ 9 initComponents();10 setLocationRelativeTo(getOwner()); //居中显示11 this.setExtendedState(this.getExtendedState()|JFrame.MAXIMIZED_BOTH );12 LoadTree();13 this.lblUser.setText("欢迎 "+uname+ " 登录!");14 15 }

 主界面在初始化时,调用LoadTree方法来填充左边的菜单树,如下所示:

 1   private void LoadTree() 2   { 3     //自定义控件,支持关闭按钮 4     jTabbedPane1.setCloseButtonEnabled(true); 5  6     DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("软件部"); 7     node1.add(new DefaultMutableTreeNode("产品部")); 8     node1.add(new DefaultMutableTreeNode("测试部")); 9     node1.add(new DefaultMutableTreeNode("设计部"));10 11     DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("销售部");12     node2.add(new DefaultMutableTreeNode("jack"));13     node2.add(new DefaultMutableTreeNode("Lily"));14     node2.add(new DefaultMutableTreeNode("Smith"));15 16     DefaultMutableTreeNode top = new DefaultMutableTreeNode("职员管理");17      18    19     top.add(new DefaultMutableTreeNode("总经理"));20     top.add(node1);21     top.add(node2);22    23     //JTree tree=new JTree(top);    24     DefaultTreeModel model = new DefaultTreeModel (top);   25     this.jTree1.setModel(model);26    //jTree1.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION)   27    //set jframe icon28    try29      30     {31    Image icon= ImageIO.read(this.getClass().getResource("/images/Icon.png"));32    tabIcon = createImageIcon("/images/Icon.png", "tab icon");33    34    this.setIconImage(icon);35     }36    catch(IOException ex)37     {38      39       System.out.println(ex);40          41     }42   43   }

 在Tree的值变化事件中,通过class.forName()和 cls.newInstance()反射动态实例化窗体,代码如下:

 1   private void jTree1ValueChanged(javax.swing.event.TreeSelectionEvent evt) {                   2     // TODO add your handling code here: 3    4    DefaultMutableTreeNode node = (DefaultMutableTreeNode) 
        jTree1.getLastSelectedPathComponent(); 5 6 if (node == null){ 7 //Nothing is selected. 8 return; 9 }10 11 Object nodeInfo = node.getUserObject();12 String item = (String) nodeInfo;13 14 if (node.isLeaf()) {15 String item1 = (String) nodeInfo;16 // this.setTitle(item1);17 //File f = new File("client.jar");18 //URLClassLoader cl = new URLClassLoader(new URL[]{f.toURI().toURL(), null});19 //Class<?> clazz = cl.loadClass("epicurus.Client");20 //Method main = clazz.getMethod("main", String[].class);21 //main.invoke(null, new Object[]{new String[]{}});22 try {23 Class cls = Class.forName("com.mkmis.forms.JIFrame1");24 javax.swing.JInternalFrame frm =
                (javax.swing.JInternalFrame) cls.newInstance();25 frm.setVisible(true);26 27 //jTabbedPane1.addTab(" "+item1+" ",null,frm);28 jTabbedPane1.addTab(" "+item1+" ",this.tabIcon,frm);29 30 }31 catch (Throwable e) {32 System.err.println(e);33 }34 } else {35 System.out.println("not leaf");36 }37 }

 在javaswing中的路径也和net不同,下面定义了一个创建ImageIcon的方法:

 1   /** Returns an ImageIcon, or null if the path was invalid. */ 2   protected ImageIcon createImageIcon(String path,String description) { 3     java.net.URL imgURL = getClass().getResource(path); 4     if (imgURL != null) { 5       return new ImageIcon(imgURL, description); 6     } else { 7       System.err.println("Couldn't find file: " + path); 8       return null; 9     }10   }

 5 JDBC MYSQL代码

 1 package com.mkmis.db; 2  3 import java.io.FileInputStream; 4 import java.io.IOException; 5 import java.sql.Connection; 6 import java.sql.DriverManager; 7 import java.sql.PreparedStatement; 8 import java.sql.ResultSet; 9 import java.sql.SQLException;10 import java.sql.Statement;11 import java.util.Properties;12 13 14 public class DBConnection {15 16   public static Connection getConnection() {17     Properties props = new Properties();18     FileInputStream fis = null;19     Connection con = null;20     try {21       fis = new FileInputStream("db.properties");22       props.load(fis);23       //24       Class.forName(props.getProperty("DB_DRIVER_CLASS"));25       // 26       con = DriverManager.getConnection(props.getProperty("DB_URL"), props.getProperty("DB_USERNAME"), props.getProperty("DB_PASSWORD"));27     } catch (IOException | SQLException | ClassNotFoundException e) {28       e.printStackTrace();29     }30     return con;31   }32 33   // �ر�ResultSet34   public static void closeResultSet(ResultSet rs) {35     if (rs != null) {36       try {37         rs.close();38         rs = null;39       } catch (SQLException e) {40         e.printStackTrace();41       }42     }43   }44 45   //Statement46   public static void closeStatement(Statement stm) {47     if (stm != null) {48       try {49         stm.close();50         stm = null;51       } catch (SQLException e) {52         e.printStackTrace();53       }54     }55   }56 57   //PreparedStatement58   public static void closePreparedStatement(PreparedStatement pstm) {59     if (pstm != null) {60       try {61         pstm.close();62         pstm = null;63       } catch (SQLException e) {64         e.printStackTrace();65       }66     }67   }68 69   //Connection70   public static void closeConnection(Connection con) {71     if (con != null) {72       try {73         con.close();74         con = null;75       } catch (SQLException e) {76         e.printStackTrace();77       }78       con = null;79     }80   }81 82 }

View Code

 6 图表窗体代码

 1 /* 2  * To change this license header, choose License Headers in Project Properties. 3  * To change this template file, choose Tools | Templates 4  * and open the template in the editor. 5 */ 6 package com.mkmis.forms; 7  8 import java.awt.Color; 9 import java.awt.Dimension; 10 import java.awt.Font; 11  12 import org.jfree.chart.ChartFactory; 13 import org.jfree.chart.ChartPanel; 14 import org.jfree.chart.JFreeChart; 15 import org.jfree.chart.StandardChartTheme; 16 import org.jfree.chart.axis.CategoryAxis; 17 import org.jfree.chart.axis.NumberAxis; 18 import org.jfree.chart.block.BlockBorder; 19 import org.jfree.chart.plot.CategoryPlot; 20 import org.jfree.chart.renderer.category.BarRenderer; 21 import org.jfree.chart.title.TextTitle; 22 import org.jfree.data.category.CategoryDataset; 23 import org.jfree.data.category.DefaultCategoryDataset; 24 //import org.jfree.ui.ApplicationFrame; 25 //import org.jfree.ui.RefineryUtilities; 26 /** 27  * 28  * @author wangming 29 */ 30 public class JIFrame1 extends javax.swing.JInternalFrame { 31  32   /** 33    * Creates new form JIFrame1 34   */ 35   public JIFrame1() { 36     initComponents(); 37     //hiding title bar of JInternalFrame     38     ((javax.swing.plaf.basic.BasicInternalFrameUI)this.getUI()).setNorthPane(null); 39     this.setBackground(Color.white); 40      41     CategoryDataset dataset = createDataset(); 42     JFreeChart chart = createChart(dataset); 43     ChartPanel chartPanel = new ChartPanel(chart); 44     chartPanel.setFillZoomRectangle(true); 45     chartPanel.setMouseWheelEnabled(true); 46     chartPanel.setPreferredSize(new Dimension(500, 270)); 47     setContentPane(chartPanel); 48   } 49  50   /** 51    * This method is called from within the constructor to initialize the form. 52    * WARNING: Do NOT modify this code. The content of this method is always 53    * regenerated by the Form Editor. 54   */ 55   @SuppressWarnings("unchecked") 56   // <editor-fold defaultstate="collapsed" desc="Generated Code">              57   private void initComponents() { 58  59     setBorder(null); 60     setClosable(true); 61     setMaximizable(true); 62     setResizable(true); 63  64     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 65     getContentPane().setLayout(layout); 66     layout.setHorizontalGroup( 67       layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 68       .addGap(0, 410, Short.MAX_VALUE) 69     ); 70     layout.setVerticalGroup( 71       layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 72       .addGap(0, 285, Short.MAX_VALUE) 73     ); 74  75     pack(); 76   }// </editor-fold>             77  78     private static final long serialVersionUID = 1L; 79  80   static { 81     // set a theme using the new shadow generator feature available in 82     // 1.0.14 - for backwards compatibility it is not enabled by default 83     ChartFactory.setChartTheme(new StandardChartTheme("JFree/Shadow", 84         true)); 85   } 86  87   /** 88    * Creates a new demo instance. 89    * 90    * @param title the frame title. 91   */ 92   public JIFrame1(String title) { 93     super(title); 94     CategoryDataset dataset = createDataset(); 95     JFreeChart chart = createChart(dataset); 96     ChartPanel chartPanel = new ChartPanel(chart); 97     chartPanel.setFillZoomRectangle(true); 98     chartPanel.setMouseWheelEnabled(true); 99     chartPanel.setPreferredSize(new Dimension(500, 270));100     setContentPane(chartPanel);101   }102 103   /**104    * Returns a sample dataset.105    *106    * @return The dataset.107   */108   private static CategoryDataset createDataset() {109     DefaultCategoryDataset dataset = new DefaultCategoryDataset();110     dataset.addValue(7445, "JFreeSVG", "Warm-up");111     dataset.addValue(24448, "Batik", "Warm-up");112     dataset.addValue(4297, "JFreeSVG", "Test");113     dataset.addValue(21022, "Batik", "Test");114     return dataset;115   }116 117   /**118    * Creates a sample chart.119    *120    * @param dataset the dataset.121    *122    * @return The chart.123   */124   private static JFreeChart createChart(CategoryDataset dataset) {125     //中文乱码,设置字体126     Font font=new Font("微软雅黑",Font.BOLD,18);//测试是可以的127    128    129    130    131     JFreeChart chart = ChartFactory.createBarChart("性能: JFreeSVG 对比 Batik", null /* x-axis label*/, 132         "毫秒" /* y-axis label */, dataset);133     //中文乱码,设置字体134     chart.getTitle().setFont(font);135 136     chart.addSubtitle(new TextTitle("在SVG中产生1000个图表"));137     chart.setBackgroundPaint(Color.white);138     CategoryPlot plot = (CategoryPlot) chart.getPlot();139     NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();140      rangeAxis.setLabelFont(font);141 142     CategoryAxis domainAxis = plot.getDomainAxis();143      domainAxis.setLabelFont(font);144     // ******************************************************************145     // More than 150 demo applications are included with the JFreeChart146     // Developer Guide...for more information, see:147     //148     // >  http://www.object-refinery.com/jfreechart/guide.html149     //150     // ******************************************************************151 152    153     rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());154     BarRenderer renderer = (BarRenderer) plot.getRenderer();155     renderer.setDrawBarOutline(false);156     chart.getLegend().setFrame(BlockBorder.NONE);157     return chart;158   }159 160   /**161    * Starting point for the demonstration application.162    *163    * @param args ignored.164   */165 //  public static void main(String[] args) {166 //    BarChartDemo1 demo = new BarChartDemo1("JFreeChart: BarChartDemo1.java");167 //    demo.pack();168 //    RefineryUtilities.centerFrameOnScreen(demo);169 //    demo.setVisible(true);170 //  }171 172   // Variables declaration - do not modify           173   // End of variables declaration          174 }

View Code

 运行此app,一定要引入需要的库,mysql jdbc驱动和jfreechart库