回転させて値を得るカスタムコントロール

  1. 3 years ago

    Kazuto O

    23 Sep 2014 Pre-Release Testers
    Edited 3 years ago

    日本語ユーザーの方々、ごきげんよう(NHK連ドラの「花子とアン」の主人公の台詞でごきげんよう使いました〜w)

    やってみてうまく行ったコードをさらします。Canvasクラスのコードで、これをスーパークラスにしてXojoの書類に貼付けて動作させて見て下さい。rocanvasというのはキャンバスのスーパークラスです。キャンバス作って、それにコピペしても同じですけれども、クラスにしておけば後々再利用出来るかな?と思いますです。

    動作はMacのPagesとかの角度を変える時に円形のコントロールがありますが、それをまねてみました。他の方法もあるかもしれませんが、三角関数を使って、マウスの位置と中心点の位置から計算して回転する表示と、最後に値をテキストフィールドに表示しています。うまく行かなかった点は、295から360がなんでか分からないのですが、値を得られず、マイナスの値になってしまうので、それを調べて、
    If theNo3<0 Then
    theNo3=theNo3+295+50
    End If
    にしています。
    もう一点は、180/PIを掛けてやると計算不能になるので、概算の180/PI〜〜57.29を計算で使っています。

    書類は以下のURLにあります。
    http://gridwindmusic.digiweb.jp/sample_1.html

    rocanvas
    Class rocanvas Inherits Canvas
    rocanvas.MouseDown:
    Function MouseDown(X As Integer, Y As Integer) As Boolean If X>0 and X<me.Width and Y>0 and Y<me.Height Then
    dx=X
    dy=Y
    Dim theNo As Double
    //クリックした時の角度を取得してPaintにある角度の取得を合わせる
    //setAngle2は回転させ、再度回転させる時の角度を合わせる
    theNo=Sqrt((Pow(dx-me.Width/2,2)+Pow(dy-me.Height/2,2)))
    If me.Height/2>dy Then
    setAngle=Acos((me.Width/2-dx)/theNo)-setAngle2
    else
    setAngle=-Acos((dx-me.Width/2)/-theNo)-setAngle2
    End If
    me.Invalidate() End If
    Return True
    End Function
    rocanvas.MouseDrag:
    Sub MouseDrag(X As Integer, Y As Integer)
    //変数にXとYの値を代入し、PaintをInvalidate()で描画している。
    If X>0 and X<me.Width and Y>0 and Y<me.Height Then
    dx=X
    dy=Y
    End If
    me.Invalidate()

    End Sub
    rocanvas.Paint:
    Sub Paint(g As Graphics, areas() As REALbasic.Rect)
    //rocanvasを任意のCanvasのスーパークラスに設定する

    Dim theNo1,theNo2,theNo3 As Double
    Dim theX,theY,theW As Integer
    //小さい●の位置の設定
    theW=g.Width/2-10
    //回転の中心点を真ん中に
    theX=(g.Width-5)/2
    theY=(g.Height-5)/2
    g.PenWidth=1
    g.PenHeight=1
    g.ForeColor=&c88888800
    //回転の角度を(ラジアン)を取得する。dxとdyの位置から
    //中心点までの距離を計算して、Acosでラジアンを取得
    //三角形の辺の長さを代入して角度を取得している。setAngleの変数は
    // MouseDownで取得し、その差からクリックした所から回転を始めるようにしている。
    theNo1=Sqrt((Pow(dx-g.Width/2,2)+Pow(dy-g.Height/2,2)))
    If g.Height/2>=dy Then
    theNo2=Acos((g.Width/2-dx)/theNo1)-setAngle

    else
    theNo2=-Acos((dx-g.Width/2)/-theNo1)-setAngle

    End If
    //setAngle2に角度を保存して、MouseDownで値を計算し
    //再度回転させる時に角度の値を合わせている。
    setAngle2=theNo2
    //背景の円を描画
    g.FillOval 5,5,g.Width-10,g.Height-10
    //回転を示す円を描画して、中心点からの位置を計算して
    //描画する
    g.ForeColor=&cFFFFFF00
    g.FillOval theX+Floor(theW*Cos(theNo2)),theY+Floor(theW*Sin(theNo2)),5,5
    //<角度をLabel1に表示>(Window1にLabel1を作って下さい)
    //回転の角度を表示する。57.29は180/PIの概算値
    //180/PIを掛けると少数の桁数が大きくなってうまく計算できない。
    //5で割って5を掛けることによって、5度ごとの値にしている。
    theNo3=Floor(theNo2*57.2957/5)*5 Mod 360
    If theNo3<0 Then
    theNo3=theNo3+295+50
    End If
    //値を表示
    Window1.Label1.Text=Str(theNo3)

    End Sub
    //クラスのプロパティを以下で設定します。
    dx As Integer
    dy As Integer
    setAngle As Double
    setAngle2 As Double
    End Class

  2. Yoshitaka M

    23 Sep 2014 Pre-Release Testers, Xojo Pro

    Ohshima様、ごきげんよう。

    面白そうなコントロールですね。今夜試してみます。
    ツィッターなどで紹介できるページがありますか?

  3. Kazuto O

    23 Sep 2014 Pre-Release Testers

    MURAOKA様 ごきげんよう

    上の発言の中のリンクに同じ内容で説明とダウンロードできるようにしました。
    これです
    http://gridwindmusic.digiweb.jp/sample_1.html
    プラグイン無しで、こんな事が出来るって感じです。
    ご興味もっていただいてうれしいです。

  4. Kazuto O

    24 Sep 2014 Pre-Release Testers

    If theNo3<0 Then
    theNo3=theNo3+295+50
    End If

    これ無くていいみたいです。なんだろう?前はなんか値変だったんですが、今見てみたらちゃんとなってますね〜

  5. Kazuto O

    24 Sep 2014 Pre-Release Testers

    なんか
    If theNo3<0 Then
    theNo3=theNo3-theNo3
    End If

    って変な感じですけど、これだとうまく0〜355表示するみたいです。逆回りにしたら何故マイナスになるのか分からないです〜
    この部分、コメントアウトしてみてみて下さい。リンクのページはファイル差し替えました。

  6. Kazuto O

    24 Sep 2014 Pre-Release Testers

    ウ〜ン、やっぱりよく分からないけれど、
    If theNo3<0 Then
    theNo3=theNo3-theNo3
    End If

    これは無くていいみたいです。でも動作がどうも不安定な気もします〜

  7. Yoshitaka M

    24 Sep 2014 Pre-Release Testers, Xojo Pro
    Edited 3 years ago

    えーと、シンプルにしてみました〜

    **** MouseDown ****
    Me.GetValue( X, Y )
    Me.Invalidate( )
    Return True

    **** MouseDrag ****
    Me.GetValue( X, Y )
    Me.Invalidate( )

    **** Paint ****
    dim x, y As Double
    Const PI=3.14159265358979323846264338327950
    Dim DEG2RAD As Double // DEG→RAD 変換用

    DEG2RAD = PI / 180

    // 確認用外枠
    g.ForeColor = &c333333
    g.FillRect( 0, 0, g.Width, g.Height )

    // 大きな円
    g.ForeColor = &c888888
    g.FillOval( 0, 0, g.Width, g.Height )

    // 小さな円の座標を計算 COS(x) の x には 現在の角度をRADに変換したものを渡し
    // g.Width/2 をかけて半径方向に引き伸ばし、ちょっと内側に白丸を描きたいので0.9をかける
    // 座標は左上基準なので、g.Width / 2 をたして位置を半径分だけフトして中心基準にする
    // 白丸半径分だけ左上にしないといけないので、 x, y とも半径分を引く
    x = ( Cos( Me.value * DEG2RAD ) * g.Width/2 * 0.9 ) + g.Width / 2 - 5
    y = ( Sin( Me.value * DEG2RAD ) * g.Height/2 * 0.9 ) + g.Height / 2 - 5

    // 小さな円を描く
    g.ForeColor = &cFFFFFF
    g.FillOval( x, y, 10, 10 )

    // 値を描画する
    Window1.Label1.Text = Str( Me.value )

    **** 新メソッド GetValue( X As Integer, Y As Integer ) ****
    Dim RAD2DEG As Double // RAD→DEG 変換用
    Const PI=3.14159265358979323846264338327950

    RAD2DEG = 180 / PI
    // クリックされた位置から見て、中心がどの方向にあるかを求める。
    // シューティングゲームで敵が自分に弾を打つのと同じ原理
    Me.Value = Atan2( Y - (Me.Height / 2), X - (Me.Width / 2) ) * RAD2DEG

    // 負の値は 360 を足して正に補正する
    If Me.value < 0 Then Me.value = Me.value + 360

    **** 新プロパティ ****
    value As Integer // 角度の計算結果を保存する。こうしておくと、このコントロールのプロパティ値として取り出せる。

    という感じですが、いかがでしょ?

  8. Kazuto O

    24 Sep 2014 Pre-Release Testers

    MURAOKAさん ありがとうです。なるほど〜
    試してみます。

  9. Kazuto O

    24 Sep 2014 Pre-Release Testers

    試してみました。うまくいきました!

    Me.Value = Atan2( Y - (Me.Height / 2), X - (Me.Width / 2) ) * RAD2DEG

    なるほど、Atan2使えばいいんですね。マウスドラッグとクリック時点で角度を求めて、Paint内では計算しないということですね。
    勉強になりました。
    これ使ってもいいですか?

  10. Yoshitaka M

    25 Sep 2014 Pre-Release Testers, Xojo Pro
    Edited 3 years ago

    どんどん使ってください〜。
    どこかに記事のエントリーができたらURLを教えて下さい。公式アカウントからツィートさせていただきますね。

    個人的には、Paint などの描画イベントはなるべく早く抜けた方が良いと思っています。
    なので、計算等は、描画イベント内ではやらないほうが良いかもしれません。
    考えが古いかもしれませんが……。
    (描画は垂直帰線が画面下端から画面頭に帰るまでに完了しないと、とか、体に染み付いている。←どれだけ古いんだか)
    --
    村岡義高

  11. Kazuto O

    25 Sep 2014 Pre-Release Testers

    ありがとうございます。
    えっと、記事はMURAOKAさんのコードも使っていいんですよね。ふたつの方法という感じで書いてみようと思います。しばし時間を下さい。先のリンクのページは分かりずらかったので、直しますね。

    >(描画は垂直帰線が画面下端から画面頭に帰るまでに完了しないと、とか、体に染み付いている。←どれだけ古いんだか)

    なるほど、そういう事があるんですね。なんかXojoのサンプル書類なんかだと、Paint内でばんばん計算しちゃってるのがありますよね?OSXの比較暗とかのやつですけども。なるほど、描画から速く抜けるというのは、参考にします。

    しかし、コードって同じような事が出来ても全くロジックが違うものなんですね。勉強になりましたです。
    ではでは

  12. Yoshitaka M

    25 Sep 2014 Pre-Release Testers, Xojo Pro
    Edited 3 years ago

    はい、私のコードはどんどん使ってあげてください。大したコードでもないので……。
    あーいえ、垂直帰線がどうのというのは、昔 X68000 でゲームを作っていた頃のお話です(苦笑)

    あと、コーディングは流派がありますので、各個人が良かれと思うコーディングをすればよいかと思います、はい。
    皆さんそれぞれのバックグラウンドがあるので、そういったことを聞き合ったりするのも楽しいものです。

  13. Kazuto O

    25 Sep 2014 Pre-Release Testers

    文章追加して、整理してみました〜

    http://gridwindmusic.digiweb.jp/sample_1.html

    TextAreaのHTMLのものを使ってコード表示してます。

    >あと、コーディングは流派がありますので、各個人が良かれと思うコーディングをすればよいかと思います、はい。

    ああ、そうですよね。私の感覚だと俳句をひねる感じに似てるなぁと思います。こうも出来るし、ここをこうするという事だったりして。なるべく簡潔なコードにしたいなぁと思ってますけれど、なかなか難しいですね。

or Sign Up to reply!