以前接觸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 icon 28 try 29 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 // �ر�ResultSet 34 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 //Statement 46 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 //PreparedStatement 58 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 //Connection 70 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 }
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 JFreeChart 146 // Developer Guide...for more information, see: 147 // 148 // > http://www.object-refinery.com/jfreechart/guide.html 149 // 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 }
運行此app,一定要引入需要的庫,mysql jdbc驅動和jfreechart庫