• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:【C#】フォームをなめらかに移動)

C#でフォームをなめらかに移動する方法は?

このQ&Aのポイント
  • C#でフォームを移動させる際にアニメーションを付ける方法について説明します。
  • 移動するスピードの変化を防ぐためには、Timerを使用して一定の間隔でフォームを移動させることが重要です。
  • .NET Framework 4.0およびVisual Studio 2010を使用している場合、以下のコードを参考にしてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.3

新しいコードではTimerは使っていないのですね? 私の環境には2005 Proしか入っていないのでTaskについては実行環境がありません。 代わりに補足に提示されたコードを使って2005 Proで動くコードを書いてみました。 ※2010で動くかどうかはわかりません。 以下Form1というFormにbutton1というButtonを貼り付けたコードです。 using System; using System.Drawing; using System.Windows.Forms; using System.Threading; namespace WindowsApplication1 {  public partial class Form1 : Form  {   Thread subThread;   ThreadStart subThreadStart;   EventWaitHandle subButtonEvent;   EventWaitHandle subExitEvent;   public Form1()   {    InitializeComponent();    subThreadStart = new ThreadStart(threadRun);    subThread = new Thread(subThreadStart);    subButtonEvent = new EventWaitHandle(false, EventResetMode.AutoReset);    subExitEvent = new EventWaitHandle(false, EventResetMode.AutoReset);    subThread.Start();   }   protected override void OnClosed(EventArgs e)   {    subExitEvent.Set(); // スレッド終了通知   }   private void button1_Click(object sender, EventArgs e)   {    subButtonEvent.Set(); // button1が押されたときの処理   }   void threadRun()   {    while (true)    {     int index = EventWaitHandle.WaitAny(new WaitHandle[] { subButtonEvent, subExitEvent });     if (index == 0)     {      // 貴方のソースコード      Point BeforeLocation = this.DesktopLocation;      int StartTime = System.Environment.TickCount;      int Time;      int EndTime;      int dx;      for (int i = 0; i <= this.Width - 3; i += dx)      {       EndTime = System.Environment.TickCount;       Time = EndTime - StartTime;       StartTime = System.Environment.TickCount;       dx = (int)(Time / 2 + 1);       Invoke((MethodInvoker)delegate()       {        this.DesktopLocation = new Point(this.DesktopLocation.X - dx, this.DesktopLocation.Y);        this.Refresh();        Application.DoEvents();       });      }      Invoke((MethodInvoker)delegate()      {       this.DesktopLocation = new Point(BeforeLocation.X - this.Width + 3, this.DesktopLocation.Y);      });     }     else if (index == 1)     {      // スレッド終了      break;     }    }   }  } }

wararyo
質問者

お礼

解決しました! 丁寧なご回答本当にありがとうございました。

その他の回答 (2)

回答No.2

>Intervalを20程にしたTimerを使う方法でも試してみましたが、あまり変わりませんでした。 もしかして、 for (int i = 0; i <= this.Width; i += 15) {   this.DesktopLocation = new Point(this.DesktopLocation.X - 15, this.DesktopLocation.Y); this.Refresh(); } を、Timer の tick イベントにそのまま記述しただけ、ってことでしょうか? Time を使用すると、PC の性能にはほとんど依存しないはずだと思います。 using System; using System.Drawing; using System.Windows.Forms; namespace MoveForm { public partial class Form1 : Form { private int _destination; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { _destination = this.Location.X - this.Width; this.timer1.Interval = 20; this.timer1.Start(); } private void timer1_Tick(object sender, EventArgs e) { if (_destination < this.DesktopLocation.X) { this.DesktopLocation = new Point(this.DesktopLocation.X - 15, this.DesktopLocation.Y); this.Refresh(); } else { this.timer1.Stop(); } } } }

wararyo
質問者

お礼

ありがとうございます。 一回の移動で使う時間が20msecを超えているのかと思い、TimerのIntervalを長くしてみましたら、ダメでした。 なぜでしょう…

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.1

>これをどのPCでもスピードの変化がなくアニメーションできるようにするにはどうすればよいでしょうか? どのPCでもというのは不可能です。 CPUだけに注目してもATOMとCorei7では処理速度が異なりますし、例え同じPC環境であっても バックグラウンドで動いているアプリケーション(例えばウイルス対策ソフト)もあり Windowsの場合一つのプロセスがCPUを占有することは出来ないからです。 >Intervalを20程にしたTimerを使う方法でも試してみましたが、あまり変わりませんでした。 あまり変わらなくみえるのは、少なくとも遅いほうのPCで20msecを大きく超える時間がかかっているからだと思います。(処理がまったく間に合っていない) 例えばIntervalを1000msecに設定すれば、どちらのPCの動作も見た目はほとんど変わらなくなるでしょう。 ゲーム等でよく使う手法としては、時間差(あるいは前回のフレームからの時間差)でスクロール量を決定します。 (固定フレームレートで動かす事が保障出来ないからです。) System.Environment.TickCountで起動してからの経過時間を取得できます。 http://msdn.microsoft.com/ja-jp/library/system.environment.tickcount(v=VS.100).aspx int startTime; int startX; private void Form1_Load(object sender, EventArgs e) {  startTime = System.Environment.TickCount;  startX = this.DesktopLocation.X; } private void timer1_Tick(object sender, EventArgs e) {  int elapsedTime = startTime - System.Environment.TickCount;  int xScroll = elapsedTime / 100; // 1秒あたり10ドットスクロール  this.DesktopLocation = new Point(startX + xScroll, this.DesktopLocation.Y); }

wararyo
質問者

お礼

ゲーム等でよく使う手法で解決しました。ありがとうございました。ですが、一回目は正しくアニメーションされるんですが、2回目以降がアニメーションしてくれません。 遅く移動させたところ、for文が終わってから一気に描画されるようです。 どうにかなりませんか? 一応改善したコード載せて起きます。 Point BeforeLocation = this.DesktopLocation; int StartTime = System.Environment.TickCount; int Time; int EndTime; int dx; for (int i = 0; i <= this.Width - 3; i += 1) { EndTime = System.Environment.TickCount; Time = EndTime - StartTime; StartTime = System.Environment.TickCount; dx = (int)(Time / 2 + 1); Invoke((MethodInvoker)delegate(){ this.DesktopLocation = new Point(this.DesktopLocation.X - 1, this.DesktopLocation.Y); this.Refresh(); Application.DoEvents(); }); System.Threading.Thread.Sleep(10); } Invoke((MethodInvoker)delegate() { this.DesktopLocation = new Point(BeforeLocation.X - this.Width + 3, this.DesktopLocation.Y); }); InvokeがあるのはTaskを使って別スレッドで実行しているためです。

wararyo
質問者

補足

ごめんなさい。お礼で書いたコードが間違ってたので、補足に書いてもいいですか。 Point BeforeLocation = this.DesktopLocation; int StartTime = System.Environment.TickCount; int Time; int EndTime; int dx; for (int i = 0; i <= this.Width - 3; i += dx) { EndTime = System.Environment.TickCount; Time = EndTime - StartTime; StartTime = System.Environment.TickCount; dx = (int)(Time / 2 + 1); Invoke((MethodInvoker)delegate(){ this.DesktopLocation = new Point(this.DesktopLocation.X - dx, this.DesktopLocation.Y); this.Refresh(); Application.DoEvents(); }); } Invoke((MethodInvoker)delegate() { this.DesktopLocation = new Point(BeforeLocation.X - this.Width + 3, this.DesktopLocation.Y); }); これが正しいコードです。

関連するQ&A