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);