一段时间后,C#中的模拟时钟变得无响应 [英] analog clock in c# gets unresponsive after a while

查看:56
本文介绍了一段时间后,C#中的模拟时钟变得无响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

我用c#编写了一个模拟时钟,它可以工作,但是几秒钟后,它就变得毫无反应了.我认为这与Clock类的timer_tick方法有关.我在下面发布了代码,对德国的评论表示抱歉,如果您愿意,我会翻译它们.

 使用系统;
使用 System.Collections.Generic;
使用 System.Linq;
使用 System.Text;
使用使用System.Windows.Forms;
使用使用System.Drawing;
使用 System.Drawing.Design;
使用 System.Drawing.Drawing2D;

命名空间 Stoppuhr
{
     class 程序
    {
        // 私有静态标签digiZeit =新标签(); 
        // 私有静态计时器digi = new Timer(); 
        私有 静态 Form frm;
        私有 静态时钟;

        公共程序(大小大小)
        {
            initComponents(大小);
            frm.Size =大小;
            clock.Location = 点( new 大小(frm.ClientRectangle.Size.Width/ 6 ,frm.ClientRectangle.Size.Height/ 6 )));
            //  digi.Interval = 1000; 
            //  digi.Start(); 
            //  digiZeit.Location = new Point(frm.Size.Width/2,frm.Size.Height-(frm. Size.Height)/10); 
            //  frm.FormBorderStyle = FormBorderStyle.FixedDialog; 
            //  frm.Controls.Add(digiZeit); 
            frm.Controls.Add(clock);
            //  digiZeit.AutoSize = true; 
            //  digiZeit.Font =新字体("Arial",20); 
            //  digi.Tick + =新的EventHandler(digi_Tick); 
            frm.BackColor =颜色.灰色;
            frm.TransparencyKey =颜色.灰色;
            frm.FormBorderStyle = FormBorderStyle.None;
            frm.ShowDialog();
        }
        公共 静态  void  Main(字符串 [] args)
        {
            程序uhr = 程序( new 大小( 400  400 )));
        }

        私有 静态  void  initComponents(大小)
        {
            frm = 表格();
            时钟= 时钟(大小);
        }

        // 静态void digi_Tick(对象发送者,EventArgs e)
        //  {
        //  digiZeit.Text = DateTime.Now.Hour +:" + DateTime.Now.Minute +:" + DateTime.Now.Second; 
        // } 
    }

     class 时钟:面板
    {
        /*   *
         * Eigenschaften eines Clock-Objektes
         * */
        私有 静态 Zeiger sekunde;
        私有 静态 Zeiger分钟;
        私有 静态 Zeiger眩晕;
        私有 静态计时器tmr;
        私有 静态 Ziffernblatt blatt;
        私有 静态  int 计数器;
        私有 静态 PaintEventArgs豌豆;
        

        
        /*   *
         *标准Konstruktor der Klasse时钟
         * */
        公共时钟(大小大小)
        {
            .Size=大小;
            initComponents();
            initZeiger();
             .SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true );
            tmr =  Timer();
            tmr.Interval =  1000 ;
            tmr.Start();
        }

        /*   *
         *初始化
         * */
        私有 无效 initComponents()
        {
            blatt =  Ziffernblatt( this  .Size);
            sekunde =  Zeiger(笔(Color.Black, 2 ));
            分钟=  Zeiger(笔(Color.Red, 4 ));
            stunde =  Zeiger(笔(Color.Blue, 5 ));
            counter =  0 ;
        }
        

        /*   *
         * Zeiger-Eigenschaften beim开始设定
         * */
        私有 无效 initZeiger()
        {
            sekunde.Laenge =  140 ;
            sekunde.Size =  .Size;

            minutes.Laenge =  140 ;
            minutes.Size =  .Size;

            stunde.Laenge =  100 ;
            stunde.Size =  .Size;

            sekunde.Winkel = DateTime.Now.Second *  6 ;
            minutes.Winkel = DateTime.Now.Minute *  6 ;
            stunde.Winkel =(DateTime.Now.Hour% 12 )*  30 ;
        }

        /*   *
         * Methodeüberschreibtdie OnPaint-Methode eines面板
         * */
        受保护的 覆盖  void  OnPaint(PaintEventArgs e)
        {
            基本 .OnPaint(e);
            豌豆= e;
            blatt.paint(e);
            sekunde.paint(e);
            minutes.paint(e);
            stunde.paint(e);
            tmr.Tick + =  EventHandler(tmr_Tick);
        }

        /*   *
         * Nach jedem Tick des Tickers stelle Winkel von Zeigern um ...
         * */
        私有 无效 tmr_Tick(对象发​​件人,EventArgs e)
        {
            sekunde.Winkel = DateTime.Now.Second *  6 ;
            minutes.Winkel = DateTime.Now.Minute *  6 ;
            stunde.Winkel =(DateTime.Now.Hour% 12 )*  30 ;
            .刷新();
        }
    }

     Ziffernblatt:面板
    {
        /*   *
         *标准Konstruktor eines Ziffernblatts
         * */
        公共 Ziffernblatt(大小)
        {
             .BackColor = Color.Transparent;
            // 方法设置了Ziffernblatts 
             .Size = 大小(size.Width-size.Width/ 3 );
            //  this.BorderStyle = BorderStyle.FixedSingle; 
        }

        /*   *
         *基于OnPaint-Override Methode的受保护方法修饰符
         * */
        公共 无效绘画(PaintEventArgs e)
        {
             .OnPaint(e);
        }

        /*   *
         * Methodeüberschreibtdie OnPaint Methode eines面板
         * */
        受保护的 覆盖  void  OnPaint(PaintEventArgs e)
        {
            .处置();
            基本 .OnPaint(e);

            //  Verschiebe 0,0 Mitte des Panels中的坐标
            e.Graphics.TranslateTransform( this  .Size.Width/ 2  2 );
            刷子=刷子.黑色;
            矩形rect = 矩形(-5,-5, 11 //  Zeichne die Striche des Ziffernblatts 
             for ( int  x =  1 ; x <  =  60 ; x ++)
            {
                Pen pen =  Pen(Color.Black, 2 );
                e.Graphics.DrawLine(pen, 0 ,-this.Height/ 2  this .高度/.高度/ 20 )));
                e.Graphics.RotateTransform( 6 );
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                // 吉德(Jede)6°,塞恩·斯特里奇(Einen Strich)
                如果((x% 5 )==  0 )
                {
                    e.Graphics.DrawLine(pen, 0 ,-this.Height/ 2  this .高度/.高度/ 10 ));
                }
                // 杰德(Jede)90°定座艾琳·狄更·斯特里奇(
                如果((x% 15 )==  0 )
                {
                    pen.Width =  5 ;
                    e.Graphics.DrawLine(pen, 0 ,-this.Height/ 2  this .高度/.高度/ 10 ));

                    e.Graphics.DrawString(" 字体("  11 ),-5,-( this .高度/ 2 - 9 ));
                }
            }
        }
    }

     class  Zeiger:面板
    {
        /*   *
         * Eigenschaften eines Zeigers
         * */
        笔笔;
         int 
         int  breite;
         int 温克尔;

        /*   *
         *标准Konstruktor Eines Zeigers
         * */
        公共 Zeiger(Pen pen)
        {
            laenge =   int ();
            breite =   int ();
             .pen = pen;
        }

        /*   *
         *设置和获取方法-Eigenschaft eines Zeigers
         * */
        公共  int 
        {
            获取 {返回 }
            设置 {laenge = ; }
        }

        /*   *
         *设置并获取Winkel-Eigenschaft方法论Zeigers
         * */
        公共  int  Winkel
        {
            获取 {返回 winkel; }
             set  {winkel =  value ; }
        }

        /*   *
         *基于OnPaint-Override Methode的受保护的修饰方法
         * */
        公共 无效绘画(PaintEventArgs e)
        {
             .OnPaint(e);
        }

        /*   *
         * OnPaint Methode eines面板上的Methode dient demÜberschreibender
         * */
        受保护的 覆盖  void  OnPaint(PaintEventArgs e)
        {
            .处置();
            图形g = e.Graphics;
            //  Setze Position and Winkel eines Zeigers 
            g.ResetTransform();
            g.TranslateTransform( this  .Width/ 3  this .Height/ 3 );
            g.RotateTransform(winkel);
            //  Zeichne einen Zeiger 
            g.DrawLine(笔, 0  0  0 ,-this.Laenge);
        }
    }
} 



如您所见,在初始化表单后,我用一个时钟对象填充了该对象,该对象又包含3个Zeiger(时钟指针)对象和ziffernblatt(数字轮)对象.然后将这4个对象放入时钟面板.我在timer_tick方法中实现了一个计数器,并注意到一段时间后它积累了巨大的价值.这就是为什么我认为错误在于所述方法.

我希望您可以在这里指示正确的方向...

解决方案

在每个Clock.OnPaint中,您添加一个新的计时器事件处理程序. AFAIK您只需要一个事件处理程序即可触发刷新.

在Clock ctor中尝试以下操作:

 tmr = 计时器();
tmr.Interval =  1000 ;
tmr.Tick + =  EventHandler(tmr_Tick);
tmr.Start(); 



然后从Clock.OnPaint()


 受保护的 替代  void  OnPaint(PaintEventArgs e)
{
    基本 .OnPaint(e);
    豌豆= e;
    blatt.paint(e);
    sekunde.paint(e);
    minutes.paint(e);
    stunde.paint(e);
    tmr.Tick + =  EventHandler(tmr_Tick);
} 


有您的问题!

您每当时钟更改一次,就向处理程序列表添加一个处理程序!

您会惊奇地发现它变得没有反应"?特别是当所有的Tick处理程序刷新显示时,这会导致绘制?


解决方案是您不应该在该行上放置

 tmr.Tick + =  EventHandler(tmr_Tick); 


在Clock的OnPaint方法中.
相反,您应该将其放在Clock .ctor中,紧挨着行

 tmr.Start(); 



OnPaint可能会被调用一百万次,因此tmr_Tick-EventHandler的调用计数将呈指数增长.


hey guys,

i wrote an analog clock in c#, it works but after a few seconds it gets really unresponsive. i think this has something to do with the timer_tick method of the clock class. i posted the code below, sorry for the german comments, i will translate them if you want.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;

namespace Stoppuhr
{
    class Program
    {
        //private static Label digiZeit = new Label ();
        //private static Timer digi = new Timer ();
        private static Form frm;
        private static Clock clock;

        public Program (Size size)
        {
            initComponents (size);
            frm.Size = size;
            clock.Location = new Point ( new Size ( frm.ClientRectangle.Size.Width / 6, frm.ClientRectangle.Size.Height / 6 ) );
            //digi.Interval = 1000;
            //digi.Start ();
            //digiZeit.Location = new Point ( frm.Size.Width / 2, frm.Size.Height - ( frm.Size.Height ) / 10 );
            //frm.FormBorderStyle = FormBorderStyle.FixedDialog;                                    
            //frm.Controls.Add ( digiZeit );
            frm.Controls.Add ( clock );
            //digiZeit.AutoSize = true;
            //digiZeit.Font = new Font ( "Arial", 20 );
            //digi.Tick += new EventHandler ( digi_Tick );
            frm.BackColor = Color.Gray;
            frm.TransparencyKey = Color.Gray;
            frm.FormBorderStyle = FormBorderStyle.None;
            frm.ShowDialog ();
        }
        public static void Main ( String [] args )
        {
            Program uhr = new Program ( new Size ( 400, 400 ) );
        }        

        private static void initComponents (Size size)
        {
            frm = new Form ();            
            clock = new Clock (size);            
        }

        //static void digi_Tick ( object sender, EventArgs e )
        //{
        //    digiZeit.Text = DateTime.Now.Hour + ":" + DateTime.Now.Minute + ":" + DateTime.Now.Second;
        //}       
    }

    class Clock : Panel
    {
        /**
         * Eigenschaften eines Clock-Objektes
         * */
        private static Zeiger sekunde;
        private static Zeiger minute;
        private static Zeiger stunde;
        private static Timer tmr;
        private static Ziffernblatt blatt;
        private static int counter;
        private static PaintEventArgs pea;
        

        
        /**
         * Standard Konstruktor der Klasse Clock
         * */
        public Clock ( Size size )
        {            
            this.Size = size;
            initComponents ();
            initZeiger ();
            this.SetStyle ( ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true );
            tmr = new Timer ();
            tmr.Interval = 1000;
            tmr.Start ();
        }

        /**
         * Eigenschaften initialisieren
         * */
        private void initComponents ()
        {
            blatt = new Ziffernblatt ( this.Size );
            sekunde = new Zeiger ( new Pen ( Color.Black, 2 ) );
            minute = new Zeiger ( new Pen ( Color.Red, 4 ) );
            stunde = new Zeiger ( new Pen ( Color.Blue, 5 ) );
            counter = 0;            
        }
        

        /**
         * Zeiger-Eigenschaften beim Start setzen
         * */
        private void initZeiger ()
        {
            sekunde.Laenge = 140;
            sekunde.Size = this.Size;

            minute.Laenge = 140;
            minute.Size = this.Size;

            stunde.Laenge = 100;
            stunde.Size = this.Size;

            sekunde.Winkel = DateTime.Now.Second * 6;
            minute.Winkel = DateTime.Now.Minute * 6;
            stunde.Winkel = ( DateTime.Now.Hour % 12 ) * 30;
        }

        /**
         * Methode überschreibt die OnPaint-Methode eines Panels
         * */
        protected override void OnPaint ( PaintEventArgs e )
        {            
            base.OnPaint ( e );
            pea = e;
            blatt.paint (e);
            sekunde.paint ( e );
            minute.paint ( e );
            stunde.paint ( e );
            tmr.Tick += new EventHandler ( tmr_Tick );            
        }

        /**
         * Nach jedem Tick des Tickers stelle Winkel von Zeigern um...
         * */
        private void tmr_Tick ( object sender, EventArgs e )
        {         
            sekunde.Winkel = DateTime.Now.Second * 6;
            minute.Winkel = DateTime.Now.Minute * 6;
            stunde.Winkel = ( DateTime.Now.Hour % 12 ) * 30;
            this.Refresh ();
        }        
    }

    class Ziffernblatt : Panel
    {    
        /**
         * Standard-Konstruktor eines Ziffernblatts
         * */
        public Ziffernblatt ( Size size )
        {
            this.BackColor = Color.Transparent;
            //Methode setzt die Größe eines Ziffernblatts
            this.Size = new Size ( size.Width - size.Width / 3, size.Height - size.Height / 3 ); 
            //this.BorderStyle = BorderStyle.FixedSingle;
        }

        /**
         * Methode dient dem umgehen des protected-Modifikators der OnPaint-Override Methode
         * */
        public void paint ( PaintEventArgs e )
        {
            this.OnPaint ( e );
        }

        /**
         * Methode überschreibt die OnPaint Methode eines Panels
         * */
        protected override void OnPaint ( PaintEventArgs e )
        {
            this.Dispose ();
            base.OnPaint ( e );

            //Verschiebe 0,0 Koordinate in die Mitte des Panels
            e.Graphics.TranslateTransform ( this.Size.Width / 2, this.Size.Height / 2 );
            Brush brush = Brushes.Black;
            Rectangle rect = new Rectangle ( -5, -5, 11, 11 );

            e.Graphics.FillRectangle ( brush, rect );

            //Zeichne die Striche des Ziffernblatts
            for ( int x = 1; x <= 60; x++ )
            {
                Pen pen = new Pen ( Color.Black, 2 );
                e.Graphics.DrawLine ( pen, 0, -this.Height / 2, 0, -( this.Height / 2 - this.Height / 20 ) );
                e.Graphics.RotateTransform ( 6 );
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                //Jede 6°, setze einen Strich
                if ( ( x % 5 ) == 0 )
                {
                    e.Graphics.DrawLine ( pen, 0, -this.Height / 2, 0, -( this.Height / 2 - this.Height / 10 ) );
                }
                //Jede 90° setze einen dicken Strich
                if ( ( x % 15 ) == 0 )
                {
                    pen.Width = 5;
                    e.Graphics.DrawLine ( pen, 0, -this.Height / 2, 0, -( this.Height / 2 - this.Height / 10 ) );

                    e.Graphics.DrawString ( "II", new Font ( "Arial", 11 ), brush, -5, -( this.Height / 2 - this.Height / 9 ) );
                }
            }
        }
    }

    class Zeiger : Panel
    {
        /**
         * Eigenschaften eines Zeigers
         * */
        Pen pen;
        int laenge;
        int breite;
        int winkel;

        /**
         * Standard Konstruktor eines Zeigers
         * */
        public Zeiger ( Pen pen )
        {
            laenge = new int ();
            breite = new int ();
            this.pen = pen;
        }

        /**
         * set und get Methoden der laenge-Eigenschaft eines Zeigers
         * */
        public int Laenge
        {
            get { return laenge; }
            set { laenge = value; }
        }

        /**
         * set und get Methoden der winkel-Eigenschaft eines Zeigers
         * */
        public int Winkel
        {
            get { return winkel; }
            set { winkel = value; }
        }

        /**
         * Methode dient dem Umgehen des protected-Modifikators der OnPaint-Override Methode
         * */
        public void paint ( PaintEventArgs e )
        {
            this.OnPaint ( e );
        }

        /**
         * Methode dient dem Überschreiben der OnPaint Methode eines Panels
         * */
        protected override void OnPaint ( PaintEventArgs e )
        {
            this.Dispose ();
            Graphics g = e.Graphics;
            //Setze Position und Winkel eines Zeigers
            g.ResetTransform ();
            g.TranslateTransform ( this.Width / 3, this.Height / 3 );
            g.RotateTransform ( winkel );
            //Zeichne einen Zeiger
            g.DrawLine ( pen, 0, 0, 0, -this.Laenge );
        }
    }
}



as you can see, after i initialize a form i populate it with a clock-object which in turn holds 3 Zeiger(clock hand) objects and a ziffernblatt(number wheel) object. these 4 objects are then put into the clock-panel. i implemented a counter in the timer_tick method and noticed that it accumulated a huge value after a while. this is why i think the fault lies in said method.

i hope you can point me in the right direction here...

解决方案

in each Clock.OnPaint you add a new timer eventhandler. AFAIK you only need one single eventhandler to trigger the refresh.

Try the following in the Clock ctor:

tmr = new Timer ();
tmr.Interval = 1000;
tmr.Tick += new EventHandler ( tmr_Tick );
tmr.Start ();



And remove

tmr.Tick += new EventHandler ( tmr_Tick );

from the Clock.OnPaint()


protected override void OnPaint ( PaintEventArgs e )
{
    base.OnPaint ( e );
    pea = e;
    blatt.paint (e);
    sekunde.paint ( e );
    minute.paint ( e );
    stunde.paint ( e );
    tmr.Tick += new EventHandler ( tmr_Tick );
}


There is your problem!

You are adding a handler to the handler list every single time the clock changes!

And you are surprised it "becomes unresponsive"? Particularly when all of the Tick handlers refresh the display, and this cause a Paint?


The solution is that you shouldn''t put the line

tmr.Tick += new EventHandler ( tmr_Tick );


in the OnPaint method of the Clock.
Instead you should put it in the Clock .ctor just before the line

tmr.Start ();



OnPaint will be called maybe a million times, so the call count of the tmr_Tick-EventHandler will rise exponentially.


这篇关于一段时间后,C#中的模拟时钟变得无响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆