Sin グラフを横スクロールさせる、ComboBox で「波長の数、カラー」を指定して、[Make]ボタンで新しい Sin グラフを追加できます。
2つ以上の Sin グラフを表示すると、白色で合成波を表示します。
なお、SinGraph の Draw メソッドは使用していません。
このデモは「Concurrency Utilities」のスレッドを使用しています。
排他制御(synchronized)、最適化の抑制(volatile)も使用しており、特に排他制御(synchronized)は必要最小限にするように熟慮しています。
(知らぬ間に)古いタイプのThreadが非推奨に?、(正式な非推奨では無いかもしれないが)そんなクズみたいなモノを何時までも使わないでくれよ、って話。
スレッドは「Concurrency Utilities」のスレッドが強く推奨されます。
なお 新しいJavaでも古いタイプのThreadを使ってたら意味ないので注意して下さい、ただし素のJavaとAndroid Javaは内部的には別モノなので、Android Javaなら普通の(古いタイプの)Threadでおkです。
下記 動画を参照して下さい、青色がCUPの未使用率、緑色がCUPの使用率だと思われます。
その動画のコンソール入力に注目すると、「ConcurrencyTest」を実行すると、CUPの使用率が ほぼ100%になり、圧倒的に効率が上がります(逆に言うと古いタイプのThreadが如何にクズかと言うことでも有りますが)。
Concurrency Utilities for EE 7
https://yoshio3.com/2013/05/15/concurrency-utilities-for-ee-7/
【SinGraph007.java】
import java.awt.EventQueue;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.BorderLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class SinGraph007 extends JFrame {
static String sAppTitle = "Application SinGraph 7.";
static boolean lApplication = false; // true;
static SinGraph007 oAppFrame;
JPanel content;
// Thread oAppThread;
int iLayoutX, iLayoutY;
CanvasObj oCanvas;
int iCanvasWidth, iCanvasHeight;
JComboBox ccbSinGraph_WaveQnt;
int iCbSinGraph_WaveQnt_Width, iCbSinGraph_WaveQnt_Height;
JComboBox ccbSinGraph_Color;
int iCbSinGraph_Color_Width, iCbSinGraph_Color_Height;
Color[] d1oCbSinGraph_ColorSets;
JButton cbtSinGraph_Make;
int iBtSinGraph_Make_Width, iBtSinGraph_Make_Height;
ExecutorService voTPool;
CountDownLatch voCDLatch_Canvas;
Future<Boolean> voFuture_Canvas;
/**
* Launch the application.
*/
public static void main(String[] args) {
// 以前はイベントもメイン・スレッドでしたが、
// イベントはイベント・ディスパッチ・スレッドに分離されたために、
// GUIコンポーネントの設定もイベント・ディスパッチ・スレッドで設定しなければならなくなったので、
// メイン・スレッドでのGUIコンポーネントの設定はNGになりました、
// 下記のように「EventQueue.invokeLater()」でイベント・ディスパッチ・スレッドに登録しなければなりません。
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
oAppFrame = new SinGraph007();
oAppFrame.setVisible(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public SinGraph007() {
// 閉じるボタンをクリックされた場合の動作を設定
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle(sAppTitle);
setLocation(50, 50);
// ContentPaneの実態はJFrameにビルトインされているデフォルト・パネル。
content = (JPanel) getContentPane();
// content.setSize(500, 500);
// content.setLayout(null);
// getContentPane().add(oAppFrame, BorderLayout.CENTER);
getContentPane().setLayout(null); // Layout 座標指定モード
ccbSinGraph_WaveQnt = new JComboBox();
ccbSinGraph_WaveQnt.setModel(new DefaultComboBoxModel(new Object[] { " 1 ", " 2 ", " 3 " }));
ccbSinGraph_WaveQnt.setDoubleBuffered(false);
ccbSinGraph_WaveQnt.setBorder(null);
iCbSinGraph_WaveQnt_Width = ccbSinGraph_WaveQnt.getMinimumSize().width;
iCbSinGraph_WaveQnt_Height = ccbSinGraph_WaveQnt.getMinimumSize().height;
d1oCbSinGraph_ColorSets = new Color[] {
Color.GREEN, Color.PINK,
Color.RED, Color.YELLOW,
};
ccbSinGraph_Color = new JComboBox();
ccbSinGraph_Color.setModel(new DefaultComboBoxModel(new Object[] { "グリーン", "ピンク", "赤", "黄色", }));
ccbSinGraph_Color.setDoubleBuffered(false);
ccbSinGraph_Color.setBorder(null);
iCbSinGraph_Color_Width = ccbSinGraph_Color.getMinimumSize().width;
iCbSinGraph_Color_Height = ccbSinGraph_Color.getMinimumSize().height;
cbtSinGraph_Make = new JButton();
cbtSinGraph_Make.setText("Make");
iBtSinGraph_Make_Width = cbtSinGraph_Make.getMinimumSize().width;
iBtSinGraph_Make_Height = cbtSinGraph_Make.getMinimumSize().height;
cbtSinGraph_Make.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ev) {
if (null != oCanvas) {
oCanvas.SinGraph_Make();
}
}
});
iCanvasWidth = 500;
iCanvasHeight = 500;
iLayoutX = 0;
iLayoutY = 0;
getContentPane().add(ccbSinGraph_WaveQnt);
ccbSinGraph_WaveQnt.setBounds(iLayoutX, iLayoutY, iCbSinGraph_WaveQnt_Width, iCbSinGraph_WaveQnt_Height);
iLayoutX = iLayoutX + iCbSinGraph_WaveQnt_Width; // iLayoutY = 0;
getContentPane().add(ccbSinGraph_Color);
ccbSinGraph_Color.setBounds(iLayoutX, iLayoutY, iCbSinGraph_Color_Width, iCbSinGraph_Color_Height);
iLayoutX = iLayoutX + iCbSinGraph_Color_Width; // iLayoutY = 0;
getContentPane().add(cbtSinGraph_Make);
cbtSinGraph_Make.setBounds(iLayoutX, iLayoutY, iBtSinGraph_Make_Width, iBtSinGraph_Make_Height);
iLayoutX = 0;
iLayoutY = iLayoutY + iBtSinGraph_Make_Height;
oCanvas = new CanvasObj(iLayoutX, iLayoutY, iCanvasWidth, iCanvasHeight);
getContentPane().add(oCanvas);
// oCanvas.setVisible(true);
iLayoutX = iCanvasWidth;
iLayoutY = iLayoutY + iCanvasHeight;
content.setSize(iLayoutX, iLayoutY);
// 「JFrame#setSize(~)」でフレーム・サイズを設定すると、
// タイトルも含むウインドウ全体のサイズになります。
// つまり、ウインドウ内の表示領域の縦がタイトルのサイズ分 少なくなります。
// 「JFrame#getContentPane().setPreferredSize(~)」で設定し、
// 「pack()」すれば、ContentPaneで設定された全表示領域が表示されます。
content.setPreferredSize(content.getSize());
pack();
voTPool = Executors.newCachedThreadPool();
voCDLatch_Canvas = new CountDownLatch(1);
voFuture_Canvas = voTPool.submit(oCanvas);
voTPool.shutdown();
// ExecutorService#shutdownは既に投入済みの全タスクの
// 処理が終わるまで待機してからスレッドを終了させます。
// また、shutdownを実行しないと、mainスレッドが終了してもJVMは終了しません。
}
class SinGraph {
CanvasObj oCanvas;
// int iWidth, iHeight;
int iMoveStride = 3;
// volatile:最適化の抑制.
volatile int iMoveDistance = 0;
int iWaveQnt = 1;
double vdWaveHeightRate = iWaveQnt;
int iGraphXStep = 0;
int iWaveWidth;
int iWaveHeight;
Color oColor = Color.BLUE;
double vdRadian;
double vdWaveWidth, vdWaveHeight;
double vdGraphX1, vdGraphX2;
double vdGraphY1, vdGraphY2;
double vdWaveY1, vdWaveY2;
double vdRate, vdRateInt;
SinGraph(CanvasObj ccv, int iWQ, Color oC) {
// コンストラクター自体には synchronized 修飾子を付与できないので、
// synchronized ブロックで囲う。
synchronized (this) {
// iMoveDistance に対する競合(描画中の変更)を回避する。
// 対象は SinGraph("自分")内の変数です。
oCanvas = ccv;
iWaveQnt = iWQ;
vdWaveHeightRate = iWaveQnt; // sin グラフの高さの調整。
oColor = oC;
}
}
synchronized void Draw(Graphics oGraphic) {
// iMoveDistance に対する競合(描画中の変更)を回避する。
// 対象は SinGraph("自分")内の変数です。
Graphics2D oGraphic2D = (Graphics2D) oGraphic;
vdGraphX1 = -1;
vdGraphX2 = -1;
oGraphic2D.setColor(oColor);
vdWaveWidth = (double) oCanvas.iWidth / iWaveQnt;
vdWaveHeight = vdWaveWidth / (2 * Math.PI) * vdWaveHeightRate;
iGraphXStep = 0;
while (iGraphXStep < oCanvas.iWidth) { // true / false
DrawBullet(oGraphic, iGraphXStep);
iGraphXStep++;
}
}
void DrawBullet(Graphics oGraphic, int iBulletGraphXStep) {
Graphics2D oGraphic2D = (Graphics2D) oGraphic;
oGraphic2D.setColor(oColor);
if (0 == iBulletGraphXStep) {
vdGraphX1 = -1;
vdGraphX2 = -1;
}
vdWaveWidth = (double) oCanvas.iWidth / iWaveQnt;
vdWaveHeight = vdWaveWidth / (2 * Math.PI) * vdWaveHeightRate;
vdGraphX1 = vdGraphX2;
vdGraphY1 = vdGraphY2;
vdWaveY1 = vdWaveY2;
vdRate = (double) (iBulletGraphXStep + oCanvas.iWidth - iMoveDistance) / oCanvas.iWidth * iWaveQnt;
vdRateInt = Math.floor(vdRate);
vdRate = vdRate - vdRateInt;
vdGraphX2 = iBulletGraphXStep;
vdRadian = 2 * Math.PI * vdRate;
vdWaveY2 = Math.sin(vdRadian) * vdWaveHeight;
vdGraphY2 = oCanvas.iHeight / 2 - vdWaveY2;
if (0 <= vdGraphX1) {
oGraphic2D.drawLine(
(int) Math.round(vdGraphX1), (int) Math.round(vdGraphY1),
(int) Math.round(vdGraphX2), (int) Math.round(vdGraphY2));
// oCanvas.vdGraphX1 = oCanvas.vdGraphX1+vdGraphX1;
// oCanvas.vdGraphX2 = oCanvas.vdGraphX2+vdGraphX2;
oCanvas.vdWaveY1 = oCanvas.vdWaveY1 + vdWaveY1;
oCanvas.vdWaveY2 = oCanvas.vdWaveY2 + vdWaveY2;
}
}
}
class CanvasObj extends JPanel implements Callable<Boolean> {
// Swing には JCanvas は存在しないので、
// グラフィックの描画には JPanel を継承して Canvas の代わりに使う。
Thread oThread;
Future<Boolean> voFuture_Canvas;
// CountDownLatch voCDLatch_Alpha;
// SinGraph oSinGraph;
int iWidth;
int iHeight;
ArrayList<SinGraph> dl1oSinGraph = new ArrayList<SinGraph>();
int iGraphXStep;
double vdGraphX1, vdGraphX2;
double vdGraphY1, vdGraphY2;
double vdWaveY1, vdWaveY2;
double vdWaveYRate = 0.666; // 合成波のY軸の倍率。
CanvasObj(int x, int y, int w, int h) {
super();
setBounds(x, y, w, h);
iWidth = getWidth();
iHeight = getHeight();
SinGraph_Make();
}
void SinGraph_Make() {
dl1oSinGraph.add(new SinGraph(this,
ccbSinGraph_WaveQnt.getSelectedIndex() + 1,
d1oCbSinGraph_ColorSets[ccbSinGraph_Color.getSelectedIndex()]));
}
@Override
public Boolean call() {
while (true) { // true / false
repaint();
try {
Thread.sleep(50); // ←50ミリ秒の sleep。
} catch (InterruptedException ex) {
// ex.printStackTrace();
System.out.println("CanvasObj#(Boolean)call(): Interrupted Exception.");
break;
}
synchronized (CanvasObj.this) {
// SinGraph内の iMoveDistance変数に対する競合(描画中の変更)を回避する。
// 対象は SinGraph内の変数なのだが、
// (CanvasObj の) paint内のループ全体の処理を1つと見なす必要があるので
// 実際の対象は CanvasObj とする必要がある。
for (SinGraph oSinGraph : dl1oSinGraph.toArray(new SinGraph[0])) {
// ↑この「new SinGraph[0]」の部分は要素がゼロ個の配列を指定しなければならないらしい。
// それにより指定された型と同一の型が返されるらしい。
oSinGraph.iMoveDistance = oSinGraph.iMoveDistance + oSinGraph.iMoveStride;
if (iWidth <= oSinGraph.iMoveDistance) {
oSinGraph.iMoveDistance = oSinGraph.iMoveDistance - iWidth;
}
}
}
}
return null;
}
@Override
public synchronized void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// ↑(JPanel を継承しているので)ここの Graphics の実態は Graphics2D となるから、
// キャストしてやれば Graphics2D が使える.
g2.setBackground(Color.BLACK);
g2.clearRect(0, 0, iWidth, iHeight);
g2.setColor(Color.WHITE);
g2.drawLine(0, iHeight / 2, iWidth, iHeight / 2);
iGraphXStep = 0;
vdGraphX1 = 0;
vdGraphX2 = 0;
while (iGraphXStep < iWidth) { // true / false
vdWaveY1 = 0;
vdWaveY2 = 0;
vdGraphX1 = vdGraphX2;
for (SinGraph oSinGraph : dl1oSinGraph.toArray(new SinGraph[0])) {
// ↑この「new SinGraph[0]」の部分は要素がゼロ個の配列を指定しなければならないらしい。
// それにより指定された型と同一の型が返されるらしい。
oSinGraph.DrawBullet(g, iGraphXStep);
}
vdGraphX2 = iGraphXStep;
if (2 <= dl1oSinGraph.size() && 0 < iGraphXStep) {
vdGraphY1 = iHeight / 2 - vdWaveY1 * vdWaveYRate;
vdGraphY2 = iHeight / 2 - vdWaveY2 * vdWaveYRate;
g2.setColor(Color.WHITE);
g2.drawLine(
(int) Math.round(vdGraphX1), (int) Math.round(vdGraphY1),
(int) Math.round(vdGraphX2), (int) Math.round(vdGraphY2));
}
iGraphXStep++;
}
}
}
}
|
|