首页 > 后端开发 > C++ > 如何每 30 秒从后台线程安全地更新一次 GUI?

如何每 30 秒从后台线程安全地更新一次 GUI?

Linda Hamilton
发布: 2025-01-10 10:20:42
原创
375 人浏览过

How to Safely Update a GUI from a Background Thread Every 30 Seconds?

安全地从后台线程每30秒更新一次GUI

本文探讨如何在应用程序中安全地使用线程,避免错误,实现每30秒从后台线程更新GUI的需求。

用户最初尝试使用BackgroundWorker并在while循环中运行它,但由于后台工作线程不是STA线程而导致异常。

正确的做法是将数据库调用与GUI更新分开。数据库调用应在后台线程(使用BackgroundWorker)中执行。调用完成后,触发进度事件通知主线程更新GUI。

用户提供的代码展示了这种方法:

<code class="language-C#">public class UpdateController
{
    private UserController _userController;
    private BackgroundWorker _backgroundWorker;

    // ...

    public void Update()
    {
        _backgroundWorker.RunWorkerAsync();
    }

    void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // UI 更新
        _userController.UpdateUsersOnMap();
        Update(); // 此处存在潜在问题,递归调用可能导致堆栈溢出
    }

    public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        // 大型数据库任务
    }
}</code>
登录后复制

然而,用户面临另一个挑战:如何每30秒触发一次更新。在RunWorkerCompleted事件处理程序中添加10秒的休眠不可行,因为它会冻结GUI。

为了解决这个问题,可以使用一个Timer定期调用Update方法,该方法依次启动数据库调用和随后的GUI更新。 更佳方案是避免在RunWorkerCompleted中递归调用Update(),而是使用System.Timers.TimerSystem.Windows.Forms.Timer来控制更新频率。 这将确保GUI保持响应,并避免潜在的堆栈溢出错误。

建议的改进代码结构如下 (使用 System.Timers.Timer):

<code class="language-C#">public class UpdateController
{
    private UserController _userController;
    private BackgroundWorker _backgroundWorker;
    private System.Timers.Timer _timer;

    public UpdateController()
    {
        _backgroundWorker = new BackgroundWorker();
        _backgroundWorker.DoWork += backgroundWorker_DoWork;
        _backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;

        _timer = new System.Timers.Timer(30000); // 30秒
        _timer.Elapsed += Timer_Elapsed;
        _timer.AutoReset = true;
    }

    public void Start()
    {
        _timer.Start();
    }

    private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        _backgroundWorker.RunWorkerAsync();
    }

    void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // UI 更新,确保在UI线程执行
        _userController.BeginInvoke(new Action(() => _userController.UpdateUsersOnMap()));
    }

    public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        // 大型数据库任务
    }
}</code>
登录后复制

这个改进的代码利用Timer来控制更新频率,避免了递归调用带来的风险,并使用BeginInvoke确保UI更新在UI线程上执行,从而保证GUI的响应性。 记住在适当的时候调用 _timer.Stop() 来停止定时器。

以上是如何每 30 秒从后台线程安全地更新一次 GUI?的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板