下午在查Fourier近似时,在网页上看到一个小程序,给定一些函数,可以将傅里叶近似的结果用图像显示,可以和用户交互,如下图,一目了然(如果大学教育能多多地使用这种方式,那么学生会更能接受)。一时好奇,就想看看源代码,同时想把这个小程序保存在本地。
网页的地址是http://www.jhu.edu/signals/fourier2/index.html,通过查看网页的源代码,发现有这么一段
<center> <table bgcolor="E0E0E0" border="1"> <tr> <td> <applet archive = FourierNew.jar code = FourierNew width = 480 height = 400></applet> </td> </tr> </table> </center>
2. 解压以后得到很多.class文件,可以使用jad + net.sf.jadclipse_3.3.0.jar将.class文件反编译得到相应的java文件,具体方法参见这里。这个演示小程序的java源代码见附录。
另外,有几个notes
1. Applet应用程序没用main方法,代之以public void init(); public void start(); public void stop(); public void destroy();
2. 在编写Applet程序时,首先必须引入java.applet.Applet包.
3. 编写一Applet程序时,一个类必须继承自Applet类,之后要复写里面的paint(Graphics g)方法.
4. Applet程序不能单独运行,必须嵌套在HTML中才可以使用。
5. 批量编译javac, 反编译jad,如 jad -o -r -s java -d src org/**/*.class,以及javac **.java
6. CODE=AppleFile提供包含Applet类的经编译后的扩展名为.class的文件
7. 可以将编译后的所有.class的文件打包成.jar文件,用 archive = FourierNew.jar提供,像本文开头那段html.
8. Applet既可以打开网页的方式执行,亦可以在命令行下用appletviewer FileNmae.htm执行
附录 :
//FourierNew.java import java.applet.Applet; import java.awt.*; public class FourierNew extends Applet { public FourierNew() { } public void init() { GridBagLayout gridbaglayout = new GridBagLayout(); GridBagConstraints gridbagconstraints = new GridBagConstraints(); Panel panel = new Panel(); Panel panel1 = new Panel(); Panel panel2 = new Panel(); panel2.setBackground(Color.lightGray); setLayout(gridbaglayout); setSize(480, 400); gridbagconstraints.fill = 1; gridbagconstraints.gridx = 0; gridbagconstraints.weightx = 1.0D; gridbagconstraints.weighty = 1.0D; gridbaglayout.setConstraints(panel, gridbagconstraints); add(panel); gridbagconstraints.weighty = 1.0D; gridbaglayout.setConstraints(panel1, gridbagconstraints); add(panel1); panel.setLayout(new BorderLayout()); panel1.setLayout(new BorderLayout()); SigPanel sigpanel = new SigPanel(); panel.add(sigpanel, "Center"); SigControls sigcontrols = new SigControls(sigpanel); panel.add(sigcontrols, "East"); panel.add(panel2, "North"); FourierControls fouriercontrols = new FourierControls(sigpanel); panel1.add(fouriercontrols, "North"); MagPanel magpanel = new MagPanel(); panel1.add(magpanel, "Center"); sigpanel.setControls(fouriercontrols, magpanel); } } //MagPanel.java import java.awt.*; class MagPanel extends Panel { public MagPanel() { setup = false; setBackground(Color.white); } public Dimension minimumSize() { return new Dimension(150, 90); } public void paint(Graphics g) { if(!setup) { fImage = createImage(getSize().width, getSize().height); fGraphics = fImage.getGraphics(); setup = true; } fGraphics.clearRect(0, 0, getSize().width, getSize().height); byte byte0 = 5; byte byte1 = 5; int i = getSize().width / 2 + 5; int j = i - 5; fGraphics.setColor(Color.lightGray); fGraphics.drawLine(byte1, 0, byte1, getSize().height); fGraphics.drawLine(0, getSize().height - 4, j, getSize().height - 4); fGraphics.drawLine(i, 0, i, getSize().height); fGraphics.drawLine(i, getSize().height - 4, getSize().width, getSize().height - 4); fGraphics.drawLine(i - 2, 4, i + 2, 4); fGraphics.setColor(Color.black); if(fMag != null) { for(int k = 0; k <= fCoefs; k++) { if(byte1 + byte0 * k <= j) { fGraphics.setColor(Color.red); fGraphics.drawLine(byte1 + byte0 * k, getSize().height - 4, byte1 + byte0 * k, getSize().height - 4 - fMag[k]); fGraphics.drawLine(byte1 + byte0 * k + 1, getSize().height - 4, byte1 + byte0 * k + 1, getSize().height - 4 - fMag[k]); } fGraphics.setColor(Color.blue); fGraphics.drawLine(i + byte0 * k, getSize().height - 4, i + byte0 * k, getSize().height - 4 - fPhase[k]); fGraphics.drawLine(i + byte0 * k + 1, getSize().height - 4, i + byte0 * k + 1, getSize().height - 4 - fPhase[k]); } } fGraphics.setColor(Color.black); fGraphics.drawString("Magnitude spectrum", byte1 + 5, 13); fGraphics.drawString("Phase spectrum", i + 5, 13); g.drawImage(fImage, 0, 0, this); } public void set(int ai[], int ai1[], int i) { fMag = ai; fPhase = ai1; fCoefs = i; repaint(); } public void update(Graphics g) { paint(g); } int fMag[]; int fPhase[]; boolean setup; int fSigLength; int fAmplitude; int fCoefs; Image fImage; Graphics fGraphics; } //SigControls.java import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; class SigControls extends Panel implements ActionListener { public SigControls(SigPanel sigpanel) { rect = new Button("Rectangular Pulse"); bipulse = new Button("Bipolar Pulse"); saw = new Button("Sawtooth"); tri = new Button("Triangle"); exp = new Button("Exponential"); noise = new Button("Noise"); clear = new Button("Clear"); panel = sigpanel; setLayout(new GridLayout(8, 2, 5, 5)); setBackground(Color.lightGray); add(rect); add(bipulse); add(saw); add(tri); add(exp); add(noise); add(new Label()); add(clear); rect.addActionListener(this); bipulse.addActionListener(this); saw.addActionListener(this); tri.addActionListener(this); exp.addActionListener(this); noise.addActionListener(this); clear.addActionListener(this); } public void actionPerformed(ActionEvent actionevent) { if(actionevent.getActionCommand().equals("Exponential")) panel.doDecay(); else if(actionevent.getActionCommand().equals("Noise")) panel.doNoise(); else if(actionevent.getActionCommand().equals("Rectangular Pulse")) panel.doPulse(); else if(actionevent.getActionCommand().equals("Bipolar Pulse")) panel.doDoublePulse(); else if(actionevent.getActionCommand().equals("Triangle")) panel.doTriangle(); else if(actionevent.getActionCommand().equals("Sawtooth")) panel.doSawtooth(); else if(actionevent.getActionCommand().equals("Clear")) panel.clear(); } public Insets insets() { return new Insets(3, 3, 3, 3); } Button rect; Button bipulse; Button saw; Button tri; Button exp; Button noise; Button clear; SigPanel panel; } //Signal.java import java.awt.*; class Signal { public Signal(int i, int j, FourierControls fouriercontrols, MagPanel magpanel) { fourier = false; fSigLength = i; fAmplitude = j / 2; fFourierControls = fouriercontrols; fMagPanel = magpanel; x = new int[fSigLength]; approxX = new int[fSigLength]; doPulse(); } public void Drag(int i, int j, int k, int l) { if(k == i) return; changed(); if(i > k) { int i1 = i; i = k; k = i1; i1 = j; j = l; l = i1; } for(int j1 = i; j1 <= k; j1++) x[j1] = fAmplitude - (j + ((l - j) * (j1 - i)) / (k - i)); } public void Draw(Graphics g) { g.setColor(Color.lightGray); g.drawLine(0, fAmplitude, fSigLength, fAmplitude); g.drawLine(fSigLength / 2, 0, fSigLength / 2, fAmplitude * 2); g.setColor(Color.black); g.drawString("One period of x(t)", 3, 13); g.setColor(Color.blue); for(int i = 1; i < fSigLength; i++) g.drawLine(i - 1, fAmplitude - x[i - 1], i, fAmplitude - x[i]); if(fourier) { g.setColor(Color.red); for(int j = 1; j < fSigLength; j++) g.drawLine(j - 1, fAmplitude - approxX[j - 1], j, fAmplitude - approxX[j]); } } public void Modify(int i, int j) { changed(); x[i] = fAmplitude - j; } public void changed() { fourier = false; fFourierControls.disablePlusMinus(); fMagPanel.set(null, null, 0); } public void doDecay() { double d = Math.sqrt(fAmplitude); double d1 = (-Math.log(d) * 2D) / (double)fSigLength; for(int i = 0; i < fSigLength; i++) x[i] = (int)(d * Math.exp(d1 * (double)(i - fSigLength / 2))); changed(); } public void doDoublePulse() { for(int i = 0; i < fSigLength; i++) if(i > (2 * fSigLength) / 3 && i < (fSigLength * 5) / 6) x[i] = (int)(0.80000000000000004D * (double)fAmplitude); else if(i > fSigLength / 6 && i < fSigLength / 3) x[i] = (int)(-0.80000000000000004D * (double)fAmplitude); else x[i] = 0; changed(); } public void doNoise() { for(int i = 0; i < fSigLength; i++) if(i % 8 == 0) x[i] = (int)(Math.random() * 2D * (double)fAmplitude - (double)fAmplitude); else x[i] = x[i - 1] + (int)(Math.random() * 6D - 3D); changed(); } public void doPulse() { for(int i = 0; i < fSigLength; i++) if(i > (3 * fSigLength) / 7 && i < (fSigLength * 4) / 7) x[i] = (int)(0.80000000000000004D * (double)fAmplitude); else x[i] = (int)(-0.80000000000000004D * (double)fAmplitude); changed(); } public void doSawtooth() { for(int i = 0; i < fSigLength; i++) x[i] = (int)(0.80000000000000004D * ((((double)(float)fAmplitude * 2D) / (double)fSigLength) * (double)(i - fSigLength / 2))); changed(); } public void doTriangle() { for(int i = 0; i < fSigLength; i++) x[i] = (int)(0.80000000000000004D * ((double)fAmplitude - (((double)fAmplitude * 4D) / (double)fSigLength) * (double)Math.abs(i - fSigLength / 2))); changed(); } public void getCoefs(TextArea textarea) { textarea.setText(" Magnitude: Phase:\n"); for(int i = 0; i <= fCoefs; i++) { String s = String.valueOf(mag[i]); String s1 = String.valueOf(phase[i]); if(s.length() > 5) s = s.substring(0, 6); if(s1.length() > 5) s1 = s1.substring(0, 5); textarea.appendText(i + ". " + s + "\t " + s1 + "\n"); } } public void go(int i) { fCoefs = i; double d = 6.2831853071795862D / (double)fSigLength; double ad[] = new double[i + 1]; double ad1[] = new double[i + 1]; mag = new double[i + 1]; phase = new double[i + 1]; for(int j = 0; j < fSigLength; j++) ad[0] += (double)x[j] * d; ad[0] /= 6.2831853071795862D; ad1[0] = 0.0D; mag[0] = Math.abs(ad[0]) / 2D; phase[0] = ad[0] < 0.0D && Math.abs(ad[0]) >= 1.0000000000000001E-005D ? 3.1415926535897931D : 0.0D; double d1 = mag[0]; for(int k = 1; k <= i; k++) { for(int l = 0; l < fSigLength; l++) { double d2 = (double)(k * (l - fSigLength / 2)) * d; double d3 = (double)x[l] * d; ad[k] += d3 * Math.cos(d2); ad1[k] += d3 * Math.sin(d2); } ad[k] /= 3.1415926535897931D; ad1[k] /= 3.1415926535897931D; mag[k] = Math.sqrt(ad[k] * ad[k] + ad1[k] * ad1[k]); phase[k] = Math.atan((ad1[k] - ad1[k - 1]) / (ad[k] - ad[k - 1])); if(ad[k] < 0.0D) phase[k] = phase[k] + 3.1415926535897931D; if(phase[k] <= 0.10000000000000001D) phase[k] = 0.0D; if(mag[k] > d1) d1 = mag[k]; } int ai[] = new int[i + 1]; int ai1[] = new int[i + 1]; for(int i1 = 0; i1 <= i; i1++) { if(mag.length == 1) { if(mag[i1] <= 1.0D) ai[i1] = 0; else ai[i1] = (int)((mag[i1] * (double)(fMagPanel.getSize().height - 8)) / (2D * d1)); } else { ai[i1] = (int)((mag[i1] * (double)(fMagPanel.getSize().height - 8)) / d1); } ai1[i1] = (int)((phase[i1] * (double)(fMagPanel.getSize().height - 8)) / 6.2831853071795862D); } for(int j1 = 0; j1 < fSigLength; j1++) { double d4 = (double)(j1 - fSigLength / 2) * d; double d5 = ad[0]; for(int k1 = 1; k1 <= i; k1++) { double d6 = (double)k1 * d4; d5 += ad[k1] * Math.cos(d6) + ad1[k1] * Math.sin(d6); } approxX[j1] = (int)d5; } fMagPanel.set(ai, ai1, i); fourier = true; } public void zero() { for(int i = 0; i < fSigLength; i++) x[i] = 0; changed(); } int fSigLength; int fAmplitude; int x[]; int approxX[]; double mag[]; double phase[]; boolean fourier; FourierControls fFourierControls; MagPanel fMagPanel; int fCoefs; } // SigPanel.java import java.awt.*; import java.awt.event.*; class SigPanel extends Panel implements MouseListener, MouseMotionListener { public SigPanel() { prevX = 0; prevY = 0; setup = false; setBackground(Color.white); addMouseListener(this); addMouseMotionListener(this); } public void clear() { signal.zero(); repaint(); } public void doDecay() { signal.doDecay(); repaint(); } public void doDoublePulse() { signal.doDoublePulse(); repaint(); } public void doNoise() { signal.doNoise(); repaint(); } public void doPulse() { signal.doPulse(); repaint(); } public void doSawtooth() { signal.doSawtooth(); repaint(); } public void doTriangle() { signal.doTriangle(); repaint(); } public void getCoefs(TextArea textarea) { signal.getCoefs(textarea); } public void go(int i) { signal.go(i); repaint(); } public Dimension minimumSize() { return new Dimension(300, 100); } public void mouseClicked(MouseEvent mouseevent) { signal.Modify(mouseevent.getX(), mouseevent.getY()); prevX = mouseevent.getX(); prevY = mouseevent.getY(); repaint(); } public void mouseDragged(MouseEvent mouseevent) { signal.Drag(prevX, prevY, mouseevent.getX(), mouseevent.getY()); prevX = mouseevent.getX(); prevY = mouseevent.getY(); repaint(); } public void mouseEntered(MouseEvent mouseevent) { } public void mouseExited(MouseEvent mouseevent) { } public void mouseMoved(MouseEvent mouseevent) { } public void mousePressed(MouseEvent mouseevent) { } public void mouseReleased(MouseEvent mouseevent) { } public void paint(Graphics g) { if(!setup) { signal = new Signal(getSize().width, getSize().height, fFourierControls, fMagPanel); fImage = createImage(getSize().width, getSize().height); fGraphics = fImage.getGraphics(); setup = true; } fGraphics.clearRect(0, 0, getSize().width, getSize().height); signal.Draw(fGraphics); g.drawImage(fImage, 0, 0, this); } public void setControls(FourierControls fouriercontrols, MagPanel magpanel) { fFourierControls = fouriercontrols; fMagPanel = magpanel; } public void update(Graphics g) { paint(g); } Signal signal; int prevX; int prevY; boolean setup; FourierControls fFourierControls; MagPanel fMagPanel; Image fImage; Graphics fGraphics; } //CoefFrame.java import java.awt.Frame; import java.awt.Window; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; class CoefFrame extends Frame implements WindowListener { public CoefFrame(String s) { super(s); addWindowListener(this); } public void windowActivated(WindowEvent windowevent) { } public void windowClosed(WindowEvent windowevent) { } public void windowClosing(WindowEvent windowevent) { dispose(); } public void windowDeactivated(WindowEvent windowevent) { } public void windowDeiconified(WindowEvent windowevent) { } public void windowIconified(WindowEvent windowevent) { } public void windowOpened(WindowEvent windowevent) { } FourierControls fPanel; } //FourierControls import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; class FourierControls extends Panel implements ActionListener { public FourierControls(SigPanel sigpanel) { fNumCoefs = 10; fCoefField = new TextField("10", 3); fPlusButton = new Button("+"); fMinusButton = new Button("-"); fShowCoefsButton = new Button("Table"); calculate = new Button("Calculate"); panel = sigpanel; setLayout(new FlowLayout()); setBackground(Color.lightGray); add(new Label("Fourier series coefficients:")); add(fCoefField); add(calculate); fWin = new CoefFrame("Fourier Series Coefficients"); fWin.setLayout(new BorderLayout()); fTextArea = new TextArea(fNumCoefs, 50); fTextArea.setEditable(false); fTextArea.setFont(new Font("Courier", 0, 12)); fWin.add("Center", fTextArea); fWin.resize(300, 200); Point point = location(); fWin.move(point.x + 50, point.y + 50); disablePlusMinus(); add(new Label(" ")); add(fMinusButton); add(fPlusButton); add(new Label(" ")); add(fShowCoefsButton); fMinusButton.addActionListener(this); fPlusButton.addActionListener(this); fShowCoefsButton.addActionListener(this); calculate.addActionListener(this); } public void actionPerformed(ActionEvent actionevent) { if(actionevent.getActionCommand().equals("Calculate")) try { panel.go(fNumCoefs = Integer.parseInt(fCoefField.getText())); panel.getCoefs(fTextArea); fPlusButton.enable(); fShowCoefsButton.enable(); if(fNumCoefs >= 1) fMinusButton.enable(); } catch(NumberFormatException _ex) { } else if(actionevent.getActionCommand().equals("Table")) { panel.getCoefs(fTextArea); fWin.show(); } else if(actionevent.getActionCommand().equals("+")) { fCoefField.setText((new Integer(++fNumCoefs)).toString()); panel.go(fNumCoefs); panel.getCoefs(fTextArea); fMinusButton.enable(); } else if(actionevent.getActionCommand().equals("-") && fNumCoefs >= 1) { fCoefField.setText((new Integer(--fNumCoefs)).toString()); panel.go(fNumCoefs); panel.getCoefs(fTextArea); if(fNumCoefs == 0) fMinusButton.disable(); } } public void disablePlusMinus() { fPlusButton.disable(); fMinusButton.disable(); fShowCoefsButton.disable(); fTextArea.setText(""); } SigPanel panel; int fNumCoefs; TextField fCoefField; Button fPlusButton; Button fMinusButton; Button fShowCoefsButton; Button calculate; TextArea fTextArea; Window fWin; }