编程爱好者联盟 2017-01-04
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=newJPanel();
2 JButton button=newJButton(“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想作是支撑面板的框架,他甚至可以使用 自定义的方式换掉框架的面板:
nyframe.setContentpane(myPanel);