質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

2回答

1065閲覧

別スレッドで現在日時と時刻をラベルに1秒ごとに表示したい

hj_petricall

総合スコア2

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2022/10/26 03:40

編集2022/10/26 04:41

前提

Visual Studio 2022 で Windows Forms アプリを .NET 6.0で作成しています。
Timerはデザインのツールボックスから引っ張ってきたものです。

C#でフォームをロードしたときにメインの処理とは別スレッドで現在時刻を1秒ごとに更新して表示するシステムを作っています。
スレッドスタート→スレッド内でTime_Tickのスタートを行い画面の表示までは行ったのですが、肝心の画面表示後に1秒ごとに時間が更新されません。

こちら解決策等ございますでしょうか…。
ご教示いただけますと幸いです。

実現したいこと

・別スレッドでyyyy/MM/dd HH:mm:ssの形式でラベルに対して1秒ごとに時刻を表示したい

発生している問題・エラーメッセージ

画面表示後に現在時刻が1秒ごとに更新されない

該当のソースコード

private void Form1_Load(object sender, EventArgs e) { DateTime time = DateTime.Now; lblTime.Text = String.Format(time.ToString("yyyy/MM/dd ") + time.ToLongTimeString()); Thread timerClock = new Thread(new ThreadStart(TimerThread)); timerClock.Start(); //後続処理 } private void TimerThread() { Timer1.Interval = 1000;//1秒ごとに更新 Timer1.Start();//Timer1_Tickが実行されるはず } private void Timer1_Tick(object sender, EventArgs e) { DateTime time = DateTime.Now; lblTime.Text = String.Format(time.ToString("yyyy/MM/dd ") + time.ToLongTimeString()); } }

試したこと

1.lblTimeに現在時刻を表示し1秒ごとに更新(フォーマットは「yyyy/MM/dd HH:mm:ss」)を別スレッドで行いたいので、Timer_tickイベントを実行するスレッド「TimerThread」を作成
2.TimerThreadをフォームロードイベント内でnewしてスレッドをStart()で実行→TimerThread内のTimer1.Start();で画面が表示されたのですが、Timer1_Tickのイベントが始まらず、画面上の現在時刻が更新されません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YAmaGNZ

2022/10/26 03:49

timer1のイベントハンドラは設定されたのでしょうか? timer1がどのようなタイマーか分かりませんが、別スレッドで開始したからと言ってイベントは別スレッドで発生するような作りになっているのでしょうか? また、コントロールを触るのでしたら結局UIスレッドで実行しないといけないわけですがどのようにお考えなのでしょうか?
hj_petricall

2022/10/26 04:06

すみません、スレッド内のtimer1はTimer1でした。 Timer1.Start();でTimer1_Tickイベントが実行されるイメージです。
退会済みユーザー

退会済みユーザー

2022/10/26 04:10

何を何で作っているかぐらいは書けませんか? (例: Visual Studio 2022 で Windows Forms アプリをターゲットフレームワーク .NET Framework 4.8 で作っています) それから、Timer と言っても、System.Threading, System.Timers, System.Windows.Forms, System.Web.UI 名前空間に属するものなどいろいろありますが、何なのかを書きましょう。
hj_petricall

2022/10/26 04:17 編集

>何を何で作っているかぐらいは書けませんか? Visual Studio 2022 で Windows Forms アプリを .NET 6.0で作成しています。 >それから、Timer と言っても、System.Threading, System.Timers, System.Windows.Forms, System.Web.UI 名前空間に属するものなどいろいろありますが、何なのかを書きましょう。 すみません、初学者のためあまり詳しくはわからないのですが、Timerはデザインのツールボックスから引っ張ってきたものです。
退会済みユーザー

退会済みユーザー

2022/10/26 04:35

上記は追加情報として質問欄を編集して追記願います。ここはコメント欄ですし、初期画面では閉じているので見ない人もいますので。
hj_petricall

2022/10/26 04:42

こちらのサイトの使い方をあまりわかっておらず申し訳ございません。 いま追記いたしました。
退会済みユーザー

退会済みユーザー

2022/10/26 04:52

> Timerはデザインのツールボックスから引っ張ってきたものです。 であれば、その Timer は System.Windows.Forms 名前空間のもので、Microsoft のドキュメントによると "Timer は、ユーザー定義の間隔でイベントを発生させるために使用されます。この Windows タイマは、UI スレッドを使用して処理を実行するシングルスレッド環境に合わせて設計されています" ということで、UI スレッドでないと動かない(別スレッドでは動かない)と思うのですが?
KOZ6.0

2022/10/26 06:03

UI スレッドは、ひとつのプロセスでひとつしか存在が許されていないわけではなく、複数作っても問題ありません。 Application クラスはマルチスレッドに対応しています。 個々のスレッドが独立して動いているぶんには問題ありません。 「シングルスレッド環境に合わせて設計されています」というのは、「別スレッドから操作されることを想定して作っていませんよ。」ということです。 問題が発生するのは、他のスレッドで作成されたコンポーネントを操作したときです。 もっとも、そういう話をするまでもなく、質問で提示されたコードでは、Timer1.Start(); したあとスレッドが終了しているので動くわけはありません。
退会済みユーザー

退会済みユーザー

2022/10/26 22:48

質問者さん、その後無言ですが、回答が出ているのでそれらに対するフィードバックを返してください。役に立った/立たなかったぐらいはすぐに返せるのでは? 役に立たなかったならどこがダメかを書くとより期待に近い回答が出てくるかも。とにかく無言は NG です。
guest

回答2

0

Timerはデザインのツールボックスから引っ張ってきたものです。

であれば、その Timer は System.Windows.Forms 名前空間のもので、Microsoft のドキュメントによると "Timer は、ユーザー定義の間隔でイベントを発生させるために使用されます。この Windows タイマは、UI スレッドを使用して処理を実行するシングルスレッド環境に合わせて設計されています" ということで、UI スレッドでないと動かない(別スレッドでは動かない)と思うのですが?

やりたいことが良く分かってないのでハズレかもしれませんが・・・

C#でフォームをロードしたときにメインの処理とは別スレッドで現在時刻を1秒ごとに更新して表示する

Form 上に配置した Label を「別スレッドで現在時刻を1秒ごとに更新」するという目的を果たすためだけななら、System.Windows.Forms.Timer に代えて System.Threading.Timer を使ってはいかがですか? 

System.Threading.Timer の callback に指定されたメソッドは、ThreadPool スレッド(UI スレッドとは別のスレッド)で呼び出されます。

コード例は以下のような感じ。

C#

1namespace WinFormsApp3 2{ 3 public partial class Form2 : Form 4 { 5 System.Threading.Timer timer; 6 TimerCallback timerDelegate; 7 8 public Form2() 9 { 10 InitializeComponent(); 11 12 label1.Text = $"UI Thread ID {Thread.CurrentThread.ManagedThreadId}, " + 13 $"Time: {DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}"; 14 15 this.timerDelegate = new TimerCallback(ReportTime); 16 this.timer = new System.Threading.Timer(timerDelegate, null, 0, 1000); 17 18 // UI スレッドとは別の ThreadPool スレッドで呼び出される 19 void ReportTime(object? state) 20 { 21 int id = Thread.CurrentThread.ManagedThreadId; 22 this.Invoke((Action)(() => 23 label2.Text = $"Thread ID {id}, " + 24 $"Time: {DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}")); 25 } 26 } 27 } 28}

実行結果は:

イメージ説明

投稿2022/10/26 05:52

編集2022/10/26 06:31
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

別スレッドでタイマーを動かしたり表示をするには別スレッドでメッセージループを回す必要があります。

(1) タイマー表示するフォームを作成

デザイナで作っても良いですが、他フォームの子ウインドウにするので TopLevel プロパティを False にしてください。

C#

1using System; 2using System.Drawing; 3using System.Windows.Forms; 4 5class TimerForm : Form 6{ 7 readonly Timer timer1 = new Timer(); 8 9 public TimerForm() { 10 FormBorderStyle = FormBorderStyle.None; 11 TopLevel = false; 12 } 13 14 protected override void OnLoad(EventArgs e) { 15 base.OnLoad(e); 16 timer1.Interval = 1000; 17 timer1.Tick += Timer1_Tick; 18 timer1.Start(); 19 } 20 21 private void Timer1_Tick(object? sender, EventArgs e) { 22 Invalidate(); 23 } 24 25 protected override void OnFormClosed(FormClosedEventArgs e) { 26 base.OnFormClosed(e); 27 timer1.Stop(); 28 timer1.Dispose(); 29 } 30 31 protected override void OnPaint(PaintEventArgs e) { 32 base.OnPaint(e); 33 using (var b = new SolidBrush(ForeColor)) { 34 e.Graphics.DrawString(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), 35 Font, b, ClientRectangle); 36 } 37 } 38}

(2) メインフォームでスレッドを立ち上げます。
その際、メインフォームのウインドウハンドルをスレッドに渡し、SetParent API でメインフォームの子ウインドウにします。

C#

1using System; 2using System.Drawing; 3using System.Runtime.InteropServices; 4using System.Threading; 5using System.Windows.Forms; 6 7public partial class Form1 : Form 8{ 9 public Form1() { 10 InitializeComponent(); 11 } 12 13 private void Form1_Load(object sender, EventArgs e) { 14 var th = new Thread(new ParameterizedThreadStart(TimerTHread)); 15 th.SetApartmentState(ApartmentState.STA); 16 th.Start(Handle); 17 } 18 19 [DllImport("user32.dll", SetLastError = true)] 20 private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 21 22 private void TimerTHread(object? args) { 23 IntPtr mainFormHandle = (args is IntPtr) ? (IntPtr)args : IntPtr.Zero; 24 var timerForm = new TimerForm { 25 Location = new Point(0, 0), 26 Size = new Size(200, 100) 27 }; 28 SetParent(timerForm.Handle, mainFormHandle); 29 Application.Run(timerForm); 30 } 31 32 private void button1_Click(object sender, EventArgs e) { 33 // 重い処理 34 Thread.Sleep(10000); 35 } 36}

こうしてできたウインドウはメインウインドウで重い処理を実行しても時刻は更新されます。

投稿2022/10/26 04:45

編集2022/10/26 10:23
KOZ6.0

総合スコア2639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問