「質問への追記・修正依頼」でも既にご指摘にありましたが、Windows Formsアプリケーションですね。
あくまでその線で、ご提示のコードの問題点から回答させていただきます。
FormクラスにおけるOnPaint
は、描画が必要になったタイミングでシステム側から呼ばれます。ご提示のコードではSystem.Timers.Timer
タイマーの初期化やブラシの初期化をしていますが、プログラムの動作中は何度も呼ばれる可能性があるので、ここで初期化相当の処理をするのは適切ではありません。おそらくはFormのコンストラクター内か、Formのロード時に呼ばれるOnLoad
メソッド内で実行するのが適当でしょう。
時計としての描画は、今回の場合1秒ごとに現在時刻を更新したい訳ですから、OnTimedEvent
内で表示日時を更新できるようにする必要があります。具体的にはOnTimedEvent
内で現在日時を取得した後、描画領域を無効状態にしてシステムからOnPaint
が再度呼ばれるようにします。ここで気を付けなければならないのがUIのスレッド内でないとフォーム自体を含めたUIのテキストボックス等のコントロールを操作できないことです。
以下はなるべく元のご提示のコードを生かして修正した例です。
C#
1// Program.cs
2// C> csc Program.cs
3//
4using System;
5using System.Drawing;
6using System.Windows.Forms;
7
8namespace WinForm1
9{
10 class Program : Form
11 {
12 private string Tim;
13 private Font font;
14 private SolidBrush sb;
15 private System.Timers.Timer timer;
16
17 // Formのロード時に呼ばれる
18 protected override void OnLoad(EventArgs e)
19 {
20 base.OnLoad(e);
21
22 font = new Font("MS UI Graphics", 18);
23 sb = new SolidBrush(Color.Black);
24
25 timer = new System.Timers.Timer();
26 timer.Interval = 1000;
27 timer.Elapsed += OnTimedEvent;
28 timer.Enabled = true;
29 }
30
31 // Formの再描画が必要になると呼ばれる
32 protected override void OnPaint(PaintEventArgs e)
33 {
34 base.OnPaint(e);
35
36 e.Graphics.DrawString(Tim, font, sb, 20, 20);
37 }
38
39 private void OnTimedEvent(object source,
40 System.Timers.ElapsedEventArgs e)
41 {
42 DateTime time = DateTime.Now;
43 Tim = time.ToLongTimeString();
44
45 // このタイマーイベント内ではUIを更新できないので、
46 // UI(メイン)メインスレッド内でInvalidate()を実行する。
47 this.BeginInvoke(new Action(() =>
48 {
49 // 描画領域を無効にして、再描画を促す
50 Invalidate();
51 }));
52 }
53
54 static void Main(string[] args)
55 {
56 Program form = new Program();
57 form.Size = new Size(600, 400);
58 form.StartPosition =
59 FormStartPosition.CenterScreen;
60 form.BackColor = Color.FromArgb(0x80, 0x80, 0xFF);
61
62 Application.Run(form);
63 //Windowsフォームの描画
64 }
65 }
66}
67
タイマーについてはSystem.Timers.Timer
の他にFormで使いやすいSystem.Windows.Forms.Timer
もあります。
**追記しました:2019/01/01 04:34 **
コンソールアプリケーションとしての時計サンプルです。現在時刻を表示しますが、改行はせず、行頭に復帰(CR/carriage return)することで同じ行に現在時刻を表示し続けます。
C#
1// Program.cs
2//
3// C> csc Program.cs
4//
5using System;
6
7namespace ConApp1
8{
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 while (true)
14 {
15 string s = DateTime.Now.ToLocalTime().ToLongTimeString();
16 Console.Write("\x0d" + s);
17 System.Threading.Thread.Sleep(1000);
18 }
19 }
20 }
21}
実行例です。終了はCTRL+Cで強制終了してください。