Swing的組件(component,或者稱之為元件),是較widget更為正確的術語,它們就是會放在GUI(Graphical User Interface)上面的東西,這些內容就是一些用戶會看到並且與其交互的,如Text Field、Button、scrollable、list、radio button等,這些組件均是繼承自java.swing.JComponent;
在Swing中,幾乎所有的組件都是安置到其他組件當中。
2.創建GUI的四個步驟:
1 JFrame frame=new JFrame();
1 JButton button=new JButton(“click me”);
1 frame.getContentPane.add(BorderLayout.EAST,button);
1 frame.setSize(300,300);
2 frame.setVisible(true);
首先,布局管理器是與特定組件相關聯的java對象,他大多數是背景組件。
其次,布局管理器是用來控制所關聯組件上攜帶的其他組件,換言之,如果某個框架帶有面板,面板上有按鈕的情況下,則面板布局管理器就是控制按鈕的大小與位置,而框架的布局管理器是控制著面板的大小與位置。
將對應的按鍵添加到對應的面板上,可以如下實現:
1 JPanel jpanel=new JPanel();
2 JButton button=new JButton(“click me”);
3 jpanel.add(button);
1)BorderLayout:該管理器會將組建分割成5個區域,每個區域只能放置一個組件,由此管理員安置的組件不會取得默認的大小。這個也是框架默認得布局管理器;
2)FlowLayout:該管理器的行為與文書處理程序的版面配置方式差不多。這個組件會依照理想的大小呈現,並且胡依照從左到右,依次加入的順序(中間可能會換行)排列,因此如果組建放不下一行的時候會自動換行。這個是面板默認得布局管理器。
3)BoxLayout:它就像FlowLayout一樣讓每個組件按照默認得大小,依次按照加入的順序進行排列,它是以垂直的方式排列(也可以水平,但是通常我們只關心垂直的方式)。與FlowLayout不 同的是,它是需要插入某種換行的機制來強制組件從新的一列進行排列。
接下來我們看一下干貨:
3 import java.awt.BorderLayout; 4 import java.awt.GridLayout; 5 import java.awt.Label; 6 import java.awt.event.ActionEvent; 7 import java.awt.event.ActionListener; 8 import java.util.ArrayList; 9 10 import javax.sound.midi.*; 11 import javax.swing.*; 12 13 public class BeatBox { 14 JPanel mainJPanel; 15 ArrayList<JCheckBox> checkboxslist; 16 Sequencer sequencer; 17 Sequence sequence; 18 Track track; 19 JFrame theFrame; 20 String[]instrumentNames={ 21 "Bass Drum","closed Hi-Hat","open Hi-Hat","Acoustic Snare", 22 "Crash Cymbal","Hand Clap","High Tome","Hi Bongo","Maracas", 23 "Whistal","Low Conga","Cowbell","Vibraslap","Low_mid Tom", 24 "High Agogo","open High Coga" 25 };//樂器的名稱,用String的array維護 26 int []instrument={35,42,46,38,49,39,50,60,70,72,64,56,58,47,67,63};//實際樂器的關鍵字,比如說35是Bass Drum,42是closed Hi-Hat 27 public static void main(String[] args) { 28 // TODO Auto-generated method stub 29 new BeatBox().buildGUI(); 30 } 31 public void buildGUI(){ 32 theFrame = new JFrame("Cyber BeatBox"); 33 theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗口關閉時關閉程序 34 BorderLayout layout = new BorderLayout();//定義了一個BorderLayout面板對象 35 JPanel background=new JPanel(layout);//將面板對象實例化JPanel對象 36 background.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));//用於設置邊緣空白大小 37 38 checkboxslist=new ArrayList<JCheckBox>(); 39 Box buttonBox = new Box(BoxLayout.Y_AXIS); 40 41 JButton start = new JButton("start"); 42 start.addActionListener(new MyStartlistener()); 43 buttonBox.add(start); 44 45 JButton stop = new JButton("stop"); 46 start.addActionListener(new MyStoplistener()); 47 buttonBox.add(stop); 48 49 JButton upTempo = new JButton("Tempo up"); 50 start.addActionListener(new MyupTempolistener()); 51 buttonBox.add(upTempo); 52 53 JButton downTempo = new JButton("Tempo down"); 54 start.addActionListener(new MydownTempolistener()); 55 buttonBox.add(downTempo); 56 57 Box nameBox=new Box(BoxLayout.Y_AXIS); 58 for(int i=0;i<16;i++){ 59 nameBox.add(new Label(instrumentNames[i])); 60 } 61 62 background.add(BorderLayout.EAST,buttonBox); 63 background.add(BorderLayout.WEST,nameBox); 64 65 theFrame.getContentPane().add(background); 66 67 GridLayout gridLayout=new GridLayout(16,16);//創建具有指定行數和列數的網格布局。 布局中的所有組件都具有相等的大小。 68 //行和列中的一個(但不是兩者)可以為零,這意味著任何數量的對象都可以放置在一行或一列中。 69 gridLayout.setVgap(1);//將組件之間的垂直間距設置為指定的值。 70 gridLayout.setHgap(2);//將組件之間的水平間距設置為指定的值。 71 mainJPanel=new JPanel(gridLayout); 72 background.add(BorderLayout.CENTER,mainJPanel); 73 74 for(int i=0;i<256;i++){ 75 JCheckBox checkBox=new JCheckBox(); 76 checkBox.setSelected(false); 77 checkboxslist.add(checkBox); 78 mainJPanel.add(checkBox); 79 }//結束循環 80 //創建checkBox組,並將其設定成未勾選的false,並添加到arraylist以及面板上 81 82 setUpMidi(); 83 84 theFrame.setBounds(50, 50, 300, 300); 85 theFrame.pack();//pack()函數:使此窗口的大小適合其子組件的首選大小和布局。 如果任一維度小於由上次調用setMinimumSize方法指定的最小大小,則會自動放大窗口的最終寬度和高度。 86 //如果窗口和/或其所有者不可顯示,則在計算優選大小之前使它們兩者都可顯示。 窗口在計算其大小後生效。 87 theFrame.setVisible(true); 88 }//關閉buildGUI()方法 89 90 public void setUpMidi(){ 91 try{ 92 93 sequencer= MidiSystem.getSequencer();//此方法等效於調用getSequencer(true) 創建sequencer 94 sequencer.open(); 95 //創建並打開隊列 96 97 sequence=new Sequence(Sequence.PPQ, 4); 98 track=sequence.createTrack(); 99 //創建隊列並track 100 101 sequencer.setTempoInBPM(120); 102 103 }catch(Exception e){ 104 e.printStackTrace(); 105 } 106 }//關閉 setUpMidi()方法 107 108 public void buildTrackAndStart(){ 109 110 int []trackList=null;//創建出16個元素的數組來存儲一項樂器值,如果有該演奏,其值就將會是關鍵字值,否則將值為零 111 112 sequence.deleteTrack(track); 113 track=sequence.createTrack();//清除舊的track,做一個新的 114 115 for (int i = 0; i < 16; i++) {//每個樂器執行一次 116 trackList=new int[16]; 117 118 int key=instrument[i];//設代表樂器的關鍵字 119 120 for(int j = 0;j<16;j++){//每一拍執行一次 121 JCheckBox jc=(JCheckBox)checkboxslist.get(j+16*i); 122 if(jc.isSelected()){//如果勾選,那麼關鍵字的值放到數組得該位置上,不然的話,就補零 123 trackList[j]=key; 124 }else{ 125 trackList[j]=0; 126 } 127 }//關閉循環 128 129 makeTracks(trackList); 130 track.add(makeEvent(176,1,127,0,16));//創建此樂器事件,並添加到track上; 131 }//關閉外循環 132 133 134 track.add(makeEvent(192,9,1,0,15)); 135 136 try{ 137 sequencer.setSequence(sequence); 138 sequencer.setLoopCount(sequencer.LOOP_CONTINUOUSLY); 139 sequencer.start(); 140 sequencer.setTempoInBPM(120);//以每分鐘的拍數設置速度。 播放的實際速度是指定值和速度因子的乘積。 141 }catch(Exception e){ 142 e.printStackTrace(); 143 } 144 }//結束buildTrackAndStart方法 145 146 public class MyStartlistener implements ActionListener{ 147 //按鈕的監聽者 148 @Override 149 public void actionPerformed(ActionEvent e) { 150 // TODO Auto-generated method stub 151 buildTrackAndStart(); 152 } 153 154 }//內部類關閉 155 public class MyStoplistener implements ActionListener{ 156 //按鈕的監聽者 157 @Override 158 public void actionPerformed(ActionEvent e) { 159 // TODO Auto-generated method stub 160 sequencer.stop(); 161 } 162 163 }//內部類關閉 164 public class MyupTempolistener implements ActionListener{ 165 //按鈕的監聽者 166 @Override 167 public void actionPerformed(ActionEvent e) { 168 // TODO Auto-generated method stub 169 float tempoFactor=sequencer.getTempoFactor(); 170 sequencer.setTempoFactor((float)(tempoFactor*1.03));//節奏因子,預設為1.0,每次調整3% 171 } 172 173 }//內部類關閉 174 public class MydownTempolistener implements ActionListener{ 175 //按鈕的監聽者 176 @Override 177 public void actionPerformed(ActionEvent e) { 178 // TODO Auto-generated method stub 179 float tempoFactor=sequencer.getTempoFactor(); 180 sequencer.setTempoFactor((float)(tempoFactor*.97));//節奏因子,預設為1.0,每次調整3% 181 } 182 183 }//內部類關閉 184 public void makeTracks(int []list){ 185 186 for (int i = 0; i < 16; i++) { 187 int key=list[i]; 188 if (key!=0) { 189 track.add(makeEvent(144,9,key,100,i)); 190 track.add(makeEvent(128,9,key,100,i+1));//創建Note on以及Note off,並添加到track上 191 } 192 } 193 }//關閉makeTracks方法 194 public MidiEvent makeEvent(int comd,int chan,int one,int two,int tick){ 195 MidiEvent event=null; 196 try{ 197 ShortMessage shortMessage=new ShortMessage();//創建消息實例 198 shortMessage.setMessage(comd, chan, one, two);//調用setMessage 199 event=new MidiEvent(shortMessage, tick);//制作消息的MidiEvent實例 200 }catch(Exception e){ 201 e.printStackTrace(); 202 } 203 return event; 204 }//關閉makeEvent方法,該方法是制作消息以及事件 205 }
對應的界面呈現為:
問:框架為什麼不能像面板那樣直接加上組件呢?
答:JFrame會這麼特殊是因為它是讓無顯示在畫面上的接點。
因為Swing的組件純粹是由Java構成的,JFrame必須要連接到底層的操作系統以便於存儲顯示裝置。我們可以把面板想做是安置在JFrame上的100%的java層,或者把JFrame想作是支撐面板的框架,他甚至可以使用 自定義的方式換掉框架的面板:
1 nyframe.setContentpane(myPanel);