C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[1]: Timerを使った観覧車が回転しない


(過去ログ 139 を表示中)

[トピック内 12 記事 (1 - 12 表示)]  << 0 >>

■81455 / inTopicNo.1)  Timerを使った観覧車が回転しない
  
□投稿者/ かんたろう (1回)-(2016/09/26(Mon) 10:52:30)

分類:[Java] 

お早う御座います。

Timerを使って観覧車を回転させようと考えています。

全く回転しません。
更に他のパネル等も加えて、何んとか、Timerを使って全体をコントロールしたいと
考えています。

色々と参考サイトを見ましたが、原因が分かりません。
詳しい方、宜しくご教示お願い致します。

//--------------------------------------------------
public class Kanran_Frame extends JFrame
{
	public Kanran_Frame( )
	{
		Container cnt = this.getContentPane() ;
		cnt.setBackground( Color.black ) ;

		this.setSize( 800 , 600 ) ;
		this.setLayout( null ) ;

		Kanran_Panel1 k_can1 = new Kanran_Panel1() ;
		k_can1.setLayout( null ) ;
		k_can1.setSize( 350 , 350 ) ;

		cnt.add( k_can1 ) ;
	}

	public static void main( String[] args )
	{
		Toolkit.getDefaultToolkit().setDynamicLayout( true ) ;
		new Kanran_Frame() ;
		( new Kanran_Frame() ).setVisible( true ) ;
	}
}


//--------------------------------------

public class Kanran_Panel1 extends JPanel
{
	int     x , y ;
	int     xc = 200 ;
	int     yc = 200 ;
	double  hankei = 100.0 ;
	double  kakudo ;

	int rr = 0 ;
	Graphics2D g2 ;

	Timer tm ;

	public Kanran_Panel1( )
	{
		this.setLocation( 300 , 0 ) ;
		this.setBackground( Color.black ) ;
	}

	public void paintComponent( Graphics g )
	{
		super.paintComponent( g ) ;
		g2 = (Graphics2D) g ;

		g2.rotate( rr * Math.PI / 180 , xc , yc ) ;

		//Outer Cicle Line
		g2.setColor( Color.GREEN ) ;
		g2.drawOval( 100 , 100 , 200 , 200 ) ;

		//Frame
		for( kakudo = 0.0 ; kakudo < 360 ; kakudo += 20.0 )
		{
			x = xc + (int)( hankei * Math.cos( Math.toRadians( kakudo ) ) ) ;
			y = yc + (int)( hankei * Math.sin( Math.toRadians( kakudo ) ) ) ;

			g2.drawLine( xc , yc , x , y ) ;
		}
	}

	public void run()
	{
		tm = new Timer() ;
		{
			tm.schedule
			(
				new TimerTask()
				{
					public void run()
					{
						rr = ++rr % 360 ;
						repaint() ;
					}
				} , 0 , 50 ) ;
		}
	}
}

//-----------------------------------------------------------------------

引用返信 編集キー/
■81456 / inTopicNo.2)  Re[1]: Timerを使った観覧車が回転しない
□投稿者/ shu (914回)-(2016/09/26(Mon) 12:32:21)
No81455 (かんたろう さん) に返信
> お早う御座います。
>
> Timerを使って観覧車を回転させようと考えています。
>
> 全く回転しません。
> 更に他のパネル等も加えて、何んとか、Timerを使って全体をコントロールしたいと
> 考えています。
>
> 色々と参考サイトを見ましたが、原因が分かりません。
> 詳しい方、宜しくご教示お願い致します。

Timerの実装が駄目なのか回転の処理が駄目なのか明確にするために
回転の処理をボタンを設けてクリック毎に処理を行ってみて
確認をしてみてはどうでしょうか?それで動けばTimerの実装の部分ということに
なるかと思います。

引用返信 編集キー/
■81460 / inTopicNo.3)  Re[2]: Timerを使った観覧車が回転しない
□投稿者/ かんたろう (2回)-(2016/09/26(Mon) 14:57:49)
shu さん 回答ありがとうございます。


「Timer schedul」を使わずに「SwingのTimer」で書いた時には
正常に動いています。

今回、「Timer schedul」を使かうために書き直したら、動作しません。
つまり、「Timer schedul」の書き方、書く位置が原因と考えていますが、
修正の仕方が分かりません。


宜しくお願いします。


//-----------------------------------------------------------

public class Kanran_Frame extends JFrame 
{		
	public Kanran_Frame( )
	{				
		Container cnt = this.getContentPane() ;
		
		this.setSize( 800 , 600 ) ;
		cnt.setBackground( Color.black ) ;
		this.setLayout( null ) ;
		
		Kanran_Panel1 k_can1 = new Kanran_Panel1() ;
		k_can1.setLayout( null ) ;
		k_can1.setSize( 350 , 350 ) ;
		k_can1.setBackground( Color.black ) ;
		cnt.add( k_can1 ) ;
		
		new Timer( 30 , k_can1 ).start() ;
	}

	public static void main( String[] args )
	{
		Toolkit.getDefaultToolkit().setDynamicLayout( true ) ;
		
		new Kanran_Frame() ;
		( new Kanran_Frame() ).setVisible( true ) ;
	}
}

//--------------------------------------------

public class Kanran_Panel1 extends JPanel implements ActionListener
{
	int     x , y ;
	int     xc = 200 ;
	int     yc = 200 ;
	double  hankei = 100.0 ;
	double  kakudo ;

	int rr = 0 ;
	Graphics2D g2 ;

	public Kanran_Panel1( )
	{
		this.setLocation( 300 , 0 ) ;
	}

	public void paintComponent( Graphics g )
	{
		super.paintComponent( g ) ;
		g2 = (Graphics2D) g ;
		
		g2.rotate( rr * Math.PI / 180 , xc , yc ) ;
	
		//Outer Cicle Line
		g2.setColor( Color.GREEN ) ;
		g2.drawOval( 100 , 100 , 200 , 200 ) ;

		g2.setColor( Color.magenta ) ;
		g2.drawOval( 101 , 101 , 198 , 198 ) ;

		g2.setColor( Color.orange ) ;
		g2.drawOval( 102 , 102 , 196 , 196 ) ;

		//Scue Arm Line
		//Backets
		for( kakudo = 0.0 ; kakudo < 360 ; kakudo += 20.0 )
		{
			//Scue Arm Line
			x = xc + (int)( hankei * Math.cos( Math.toRadians( kakudo ) ) ) ;
			y = yc + (int)( hankei * Math.sin( Math.toRadians( kakudo ) ) ) ;
			g2.drawLine( xc , yc , x , y ) ;

			//Backets
			g2.fillRect( x - 5 , y - 2 , 11 , 11 ) ;
		}
	}
//	@Override
	public void actionPerformed( ActionEvent e )
	{
		// TODO 自動生成されたメソッド・スタブ
		rr = ++rr % 360 ;
		repaint() ;
	}
}

引用返信 編集キー/
■81468 / inTopicNo.4)  Re[3]: Timerを使った観覧車が回転しない
□投稿者/ もりお (21回)-(2016/09/27(Tue) 00:58:25)
No81460 (かんたろう さん) に返信

Kanran_Panel1のrunメソッドがどこからも呼ばれてないので
runメソッドを呼ぶようにすれば観覧車は回るはずですよ、ぐーるぐるですよ

java.util.Timerを使う場合TimerTaskはGUIの描画処理を行うスレッドとは
別のスレッドで実行されますのでちゃんと実装するならこんな感じで

new TimerTask() {
    public void run() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                rr = ++rr % 360;
                repaint();
            }
        });
    }
}

引用返信 編集キー/
■81477 / inTopicNo.5)  Re[4]: Timerを使った観覧車が回転しない
□投稿者/ かんたろう (3回)-(2016/09/27(Tue) 11:39:41)
もりお さん 回答有難う御座います。


教えて頂いたコードを下記のように修正してやりましたが、

//-------------------
@Override
public void run() 
{
rr = ++rr % 360;
repaint();
}
//-------------------
の個所で
「new Runnable(){}のメソッドrun()はスーパークラスのメッソドをオーバライドする必要があります」
というエラーになります。

どこをどのように修正してやればいいのでしょうか。
宜しくご教示お願い致します。


//--------------------------------------

class Kanran_Panel1 extends JPanel implements Runnable 
{
	int     x , y ;
	int     xc = 200 ;
	int     yc = 200 ;
	double  hankei = 100.0 ;
	double  kakudo ;

	int rr = 0 ;
	Graphics2D g2 ;

	Timer tm ;

	public Kanran_Panel1( )
	{
		this.setLocation( 300 , 0 ) ;
		this.setBackground( Color.black ) ;
	}

	public void paintComponent( Graphics g )
	{
		super.paintComponent( g ) ;
		g2 = (Graphics2D) g ;

		g2.rotate( rr * Math.PI / 180 , xc , yc ) ;

		//Outer Cicle Line
		g2.setColor( Color.GREEN ) ;
		g2.drawOval( 100 , 100 , 200 , 200 ) ;

		//Frame
		for( kakudo = 0.0 ; kakudo < 360 ; kakudo += 20.0 )
		{
			x = xc + (int)( hankei * Math.cos( Math.toRadians( kakudo ) ) ) ;
			y = yc + (int)( hankei * Math.sin( Math.toRadians( kakudo ) ) ) ;

			g2.drawLine( xc , yc , x , y ) ;
		}
	}

	public void run()
	{
		tm = new Timer() ;
		{
			tm.schedule
			(
				new TimerTask() 
				{
					public void run() 
					{
						SwingUtilities.invokeLater
						(
							new Runnable() 
							{
								@Override
								public void run() 
								{
									rr = ++rr % 360;
									repaint();
								}
							}
						);
					}
				} , 0 , 50 ) ;
		}		
	}	
}
//------------------------------------------------------------------

引用返信 編集キー/
■81478 / inTopicNo.6)  Re[1]: Timerを使った観覧車が回転しない
□投稿者/ Jitta (215回)-(2016/09/27(Tue) 14:52:55)
No81455 (かんたろう さん) に返信

主題ではないけど。
カゴが、最初は下にあるけど、
描画時間が進むと下になくなってくるような気がする。
描画座標を回しているので、カゴも同じように回っちゃうと思う。
違うかなぁ?
引用返信 編集キー/
■81481 / inTopicNo.7)  Re[5]: Timerを使った観覧車が回転しない
□投稿者/ もりお (22回)-(2016/09/27(Tue) 22:55:07)
No81477 (かんたろう さん) に返信

@Override
これを削除すればいかがでしょうか。
JDK1.5だとそうなるようですね。ググりました、グーグル。
引用返信 編集キー/
■81482 / inTopicNo.8)  Re[6]: Timerを使った観覧車が回転しない
□投稿者/ かんたろう (4回)-(2016/09/27(Tue) 23:08:54)
もりお さん 回答有難う御座います。

> @Override
> これを削除すればいかがでしょうか。
> JDK1.5だとそうなるようですね。ググりました、グーグル。

# @Override を削除するとうまく動作しました。
  ありがとうございました。
  文法的な問題かなと思ってしまいました。
  申し訳ありませんでした、今後とも宜しくお願いします。


引用返信 編集キー/
■81486 / inTopicNo.9)  Re[7]: Timerを使った観覧車が回転しない
□投稿者/ かんたろう (5回)-(2016/09/28(Wed) 19:54:17)
もりお さん 回答有難う御座います。

//---------------------------------------------------------

new TimerTask() {
    public void run() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                rr = ++rr % 360;
                repaint();
            }
        });
    }
}

//---------------------------------------------------------

との回答をいただきましたが、

//---------------------------------------------------------

new TimerTask() {
    public void run() {
                rr = ++rr % 360;
                repaint();
                }
}

//---------------------------------------------------------

と書くと何故間違いのでしょうか。

色々と調べてみましたが、よくわかりませんでした。

宜しくお願いします。



引用返信 編集キー/
■81491 / inTopicNo.10)  Re[8]: Timerを使った観覧車が回転しない
□投稿者/ もりお (23回)-(2016/09/29(Thu) 01:35:28)
No81486 (かんたろう さん) に返信

rrを更新するスレッドとrrを読み取るスレッドが異なるのですよ
GUIの描画を行うスレッドをEvent Dispatch Threadと言いますが
rrは、EDTとは別のスレッドで更新されてEDTで読み取られます

どのスレッドからも読み書き可能な共有のメモリがあるのですが
スレッドは毎回共有メモリにアクセスするわけではなくて
スレッドごとにキャッシュをもってキャッシュを読み書きします

rrを更新して共有メモリに書き出されればよいのですが
共有メモリに書き出されることが保証されていなくて
共有メモリから読みだされることも保証されていないのですよ

SwingUtilities.invokeLaterを使うとEDTで処理することができます
rrはEDTで更新されてEDTで読み取られます
共有メモリを気にしなくて済みます

図を見るとわかりやすいのですが、ちょっとすぐには見つけられません


じつは、JFrameやJPanelといったGUIのコンポネントもマルチスレッドに対応していなかったりします
複数のスレッドからアクセスすると壊れます

SwingではGUIのコンポネントにアクセスするのはEDTからのみにしましょうと
いう制約を設けることでGUIのコンポネントが壊れないようにします
この制約はシングルスレッド制約と呼ばれています

なので、mainメソッドの中でJFrameのコンストラクタを呼んでプロパティを設定していますが
ここのところもSwingUtilities.invokeLaterを使ったがよいです

引用返信 編集キー/
■81510 / inTopicNo.11)  Re[9]: Timerを使った観覧車が回転しない
□投稿者/ かんたろう (6回)-(2016/10/01(Sat) 01:47:08)
もりお さん 回答有難う御座います。

内容を完全に理解するのは今の私にはまだまだ難しいですが、
私なりにもう少し勉強していきます。

今後とも宜しくお願い致します。
解決済にさせて頂きます。
本当に有難う御座いました。

解決済み
引用返信 編集キー/
■81576 / inTopicNo.12)  Re[10]: Timerを使った観覧車が回転しない
□投稿者/ Jitta (218回)-(2016/10/16(Sun) 10:13:56)
No81510 (かんたろう さん) に返信

時間も経っていてあれだけど、やっぱり気になるので。

Javaはわからないのだけど、観覧車を描いているところ、
特に「g2.rotate( rr * Math.PI / 180 , xc , yc ) ;」が気になって調べました。
C# では、次のようなコードになると思います。
        private Image MakeImage(int turn)
        {
            Bitmap bmp = new Bitmap(200, 200);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.DrawRectangle(Pens.Brown, new Rectangle(0, 0, 199, 199));
                g.TranslateTransform(center.X, center.Y);    // ここから3行
                g.RotateTransform(turn);                     //
                g.TranslateTransform(-center.X, -center.Y);  // ここまでが、g2.rotate( rr * Math.PI / 180, xc, yc );
                for (int angle = 0; angle < 360; angle += 20)
                {
                    float x = (float)(center.X + radius * Math.Cos((angle/* + turn*/) * Math.PI/180));
                    float y = (float)(center.Y + radius * Math.Sin((angle/* + turn*/) * Math.PI/180));
                    g.FillRectangle(Brushes.LightGreen, x - 4, y - 2, 8, 10);
                    g.DrawLine(Pens.Black, center, new PointF(x, y));
                }
                g.DrawEllipse(Pens.Blue, center.X - radius, center.Y - radius, radius * 2, radius * 2);
            }

            return bmp;
        }

つまり、(xc, yc) を中心に、rr * Math.PI / 180 ラジアン回転させる、と。
で、これを実行すると、次のような結果が得られます。
https://1drv.ms/i/s%21AiQzlIklFkpNjRzmIBtWSpTl-RXt

どういうことかというと、観覧車が回っているのではなく、観覧車を見ている人が回っています。
g.rotate で、これから描くときに指示する座標に対して、演算を行います。
これによって、座標変換による描画の変更、特に拡大縮小や回転を簡単にできるのですが、
今回は「結果を回す」のではなく、「回っているところを描く」のだから、不適切かな、と。
観覧車を回すには、.rotate を削除して、支柱の座標を求める角度に、angle を足しこみます。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -