C# 如何使用一个线程来更新c中Windows窗体中的面板#
我有一个StillClock类,它是一个面板,实现如下:C# 如何使用一个线程来更新c中Windows窗体中的面板#,c#,multithreading,winforms,clock,C#,Multithreading,Winforms,Clock,我有一个StillClock类,它是一个面板,实现如下: public class StillClock: Panel { private int hour; private int minute; private int second; /** Construct a default clock with the current time*/ public StillClock() { this.Size= new Size(200,200);
public class StillClock: Panel {
private int hour;
private int minute;
private int second;
/** Construct a default clock with the current time*/
public StillClock() {
this.Size= new Size(200,200);
this.Paint += OnPaint;
setCurrentTime();
}
/** Construct a clock with specified hour, minute, and second */
public StillClock(int hour, int minute, int second) {
this.hour = hour;
this.minute = minute;
this.second = second;
}
/** Return hour */
public int getHour() {
return hour;
}
/** Set a new hour */
public void setHour(int hour) {
this.hour = hour;
this.Refresh();
}
/** Return minute */
public int getMinute() {
return minute;
}
/** Set a new minute */
public void setMinute(int minute) {
this.minute = minute;
this.Refresh();
}
/** Return second */
public int getSecond() {
return second;
}
/** Set a new second */
public void setSecond(int second) {
this.second = second;
this.Refresh();
}
/** Draw the clock */
private void OnPaint(object sender, PaintEventArgs e) {
Graphics g = e.Graphics;
// Initialize clock parameters
int clockRadius =
(int)(Math.Min(this.Size.Width , this.Size.Height ) * 0.8 * 0.5);
float xCenter = Size.Width / 2.0f;
float yCenter = Size.Height / 2.0f;
// Draw circle
Pen pen = new Pen(Color.Black);
g.DrawEllipse(pen,xCenter - clockRadius, yCenter - clockRadius,
2 * clockRadius, 2 * clockRadius );
g.DrawString( "12", new Font("System", 8), new SolidBrush(Color.Black), xCenter - 5f, yCenter - clockRadius + 12f -10);
g.DrawString("9", new Font("System", 8), new SolidBrush(Color.Black), xCenter - clockRadius + 3f, yCenter + 5f - 10);
g.DrawString("3", new Font("System", 8), new SolidBrush(Color.Black), xCenter + clockRadius - 10f, yCenter + 3f - 10);
g.DrawString("6", new Font("System", 8), new SolidBrush(Color.Black), xCenter - 3f, yCenter + clockRadius - 3f - 10);
// Draw second hand
int sLength = (int)(clockRadius * 0.8);
int xSecond = (int)(xCenter + sLength *
Math.Sin(second * (2 * Math.PI / 60)));
int ySecond = (int)(yCenter - sLength *
Math.Cos(second * (2 * Math.PI / 60)));
g.DrawLine(new Pen(Color.Red), xCenter, yCenter, xSecond, ySecond);
// Draw minute hand
int mLength = (int)(clockRadius * 0.65);
int xMinute = (int)(xCenter + mLength *
Math.Sin(minute * (2 * Math.PI / 60)));
int yMinute = (int)(yCenter - mLength *
Math.Cos(minute * (2 * Math.PI / 60)));
g.DrawLine(new Pen(Color.Blue), xCenter, yCenter, xMinute, yMinute);
// Draw hour hand
int hLength = (int)(clockRadius * 0.5);
int xHour = (int)(xCenter + hLength *
Math.Sin((hour % 12 + minute / 60.0) * (2 * Math.PI / 12)));
int yHour = (int)(yCenter - hLength *
Math.Cos((hour % 12 + minute / 60.0) * (2 * Math.PI / 12)));
g.DrawLine(new Pen(Color.Black), (float)xCenter, (float)yCenter, (float)xHour, (float)yHour);
}
public void setCurrentTime() {
// Construct a calendar for the current date and time
Thread.sleep(1000);
// Set current hour, minute and second
this.hour = DateTime.Now.Hour;
this.minute = DateTime.Now.Minute;
this.second = DateTime.Now.Second;
}
}
我必须继承类ClockAnimationUsingThread from类StillClock来开发一个动画时钟,使用Thread对象每1000毫秒设置一次StillClock的时间
我试着这样做:
public class ClockAnimationUsingThread : StillClock
{
public ClockAnimationUsingThread()
{
Thread thread1 = new Thread(new ThreadStart(this.setCurrentTime));
thread1.Start();
}
}
然后:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var panel = new ThreadedClock_ClassLibrary.ClockAnimationUsingThread();
this.Controls.Add(panel);
}
}
在Form1类中,但启动后,它只生成静态时钟,根本不更新它。为了纠正此问题并显示线程如何工作,请执行以下操作: 这样做:
public class ClockAnimationUsingThread : StillClock
{
public ClockAnimationUsingThread()
{
}
public void Start()
{
Thread thread1 = new Thread(new ThreadStart(this.setCurrentTime));
thread1.Start();
}
}
那么这个,
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var panel = new ThreadedClock_ClassLibrary.ClockAnimationUsingThread();
this.Controls.Add(panel);
panel.Start();
}
}
我把它放在一个循环中,这样线程将每1000毫秒持续更新一次,如果你将线程设置为后台线程,那么当应用程序关闭时,它将中止。如果不想让它等待,那么需要在while循环中放入一些布尔属性,然后在关闭表单时将其设置为false
public void setCurrentTime() {
// Construct a calendar for the current date and time
while(true){
// Set current hour, minute and second
this.Invoke((MethodInvoker) delegate {
this.hour = DateTime.Now.Hour;
this.minute = DateTime.Now.Minute;
this.second = DateTime.Now.Second;
});
Thread.sleep(1000);
}
}
您必须让UI线程知道它需要重新绘制时钟。只需添加:
this.Invalidate();
这是线程安全的,不需要调用UI线程。请注意,每秒只运行一次微秒级的代码就消耗掉整个线程是非常浪费的。一个简单的计时器也可以完成这项工作,而且要便宜得多。当然,当窗口关闭时,您不应该让线程继续运行,这也解决了您的关机问题。您是否尝试过在面板上调用
Refresh()
或Redraw()
?除非您使用的是Invokes,否则我认为控件不会自动更新(甚至可能不会)。注意您是如何在小时设置程序中调用this.Refresh()
,而不是其他程序的?您不应该尝试从不“拥有”该UI的后台线程更新WinForms UI。改为调用.BeginInvoke。您需要显示您的方法“setCurrentTime”@RobertHarvey,您的确切意思是将.Refresh()或.Redraw()放在哪里?请查看您的setHour()
方法。请参见此处的this.Refresh()
?但是,请注意其他人的警告,您可能需要调用这些操作。在创建窗口句柄之前,不能对控件调用Invoke或BeginInvoke。要将代码移出构造函数,请创建一个名为Start()的新方法。将线程创建代码放在那里,在添加面板等后调用Start()。我同意你的答案。。。我应该这么说!我的回答是正确的,我被卷入了试图修正他的密码中。这个密码只是为了练习。这不是生产或任何东西。我只是想知道如何通过一个线程对象来实现这一点,它必须搞乱GUI。好吧,指出你在练习时做了一些非常错误的事情应该是相关的。可能会变成坏习惯。请结束你的问题。