串口秤量应用显示闪烁问题求助(附代码及效果示例)
解决串口秤量应用TextBox显示闪烁问题
我开发了一款从串口读取数据并在文本框显示的秤量应用,但串口传入的数值显示出现闪烁问题。以下是程序代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO.Ports; using System.Text.RegularExpressions; namespace WindowsFormsApp22 { public partial class Form1 : Form { SerialPort port; public Form1() { InitializeComponent(); // Initialize the serial port. port = new SerialPort("COM13", 9600, Parity.None, 8, StopBits.One); port.Open(); // Add an event handler for the DataReceived event. port.DataReceived += Port_DataReceived; } private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { // Get the data that was received. string data = port.ReadExisting(); string[] parts = data.Split(' '); string weight = parts.Last(); // Remove non-numeric characters from the weight. weight = Regex.Replace(weight, @"[^0-9]", ""); // Trim the leading zeros from the weight. weight = weight.TrimStart('0'); // Update the text box on the main thread. BeginInvoke((Action)(() => { textBox1.Text = weight; textBox1.SelectionStart = textBox1.Text.Length; })); } } }
当前问题:文本框显示的数值频繁闪烁,期望实现稳定显示的效果。
问题根源
闪烁主要来自两个原因:
- 串口
DataReceived事件可能分段返回数据,导致多次触发更新操作,即使数值没有变化也会重复设置文本框内容,引发不必要的重绘 - WinForms的
TextBox默认重绘机制在频繁更新时会出现闪烁
解决方案
以下是修改后的代码,从数据读取、UI更新优化、控件重绘三个层面解决问题:
using System; using System.Text; using System.Windows.Forms; using System.IO.Ports; using System.Text.RegularExpressions; namespace WindowsFormsApp22 { public partial class Form1 : Form { SerialPort port; // 缓存串口数据,确保获取完整的称重帧 private readonly StringBuilder _serialBuffer = new StringBuilder(); // 记录当前显示的数值,避免重复更新UI private string _currentDisplayValue = ""; public Form1() { InitializeComponent(); // 启用TextBox双缓冲,减少重绘闪烁 EnableDoubleBuffering(textBox1); // 初始化串口(注意根据设备实际参数调整) port = new SerialPort("COM13", 9600, Parity.None, 8, StopBits.One); // 设置帧结束符,需匹配秤的输出格式(常见为\r\n) port.NewLine = "\r\n"; port.Open(); port.DataReceived += Port_DataReceived; } /// <summary> /// 启用控件双缓冲的辅助方法 /// </summary> private void EnableDoubleBuffering(Control control) { if (SystemInformation.TerminalServerSession) return; typeof(Control).InvokeMember( "DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.SetProperty, null, control, new object[] { true }); } private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { // 读取本次收到的所有数据并加入缓存 string receivedData = port.ReadExisting(); _serialBuffer.Append(receivedData); // 循环处理所有完整的帧 while (_serialBuffer.ToString().Contains(port.NewLine)) { // 提取第一帧完整数据 int frameEndIndex = _serialBuffer.ToString().IndexOf(port.NewLine); string fullFrame = _serialBuffer.ToString(0, frameEndIndex); // 从缓存中移除已处理的帧 _serialBuffer.Remove(0, frameEndIndex + port.NewLine.Length); // 解析重量数值 string[] parts = fullFrame.Split(' '); string weight = parts.Last(); // 过滤非数字字符 weight = Regex.Replace(weight, @"[^0-9]", ""); // 去除前导零,空值则显示0 weight = string.IsNullOrEmpty(weight.TrimStart('0')) ? "0" : weight.TrimStart('0'); // 仅当数值变化时更新UI,减少重绘次数 if (weight != _currentDisplayValue) { _currentDisplayValue = weight; BeginInvoke((Action)(() => { textBox1.Text = _currentDisplayValue; textBox1.SelectionStart = textBox1.Text.Length; })); } } } } }
修改说明
- 串口数据缓冲:通过
StringBuilder缓存串口数据,直到收到完整的一帧(以换行符为结束标志,需根据秤的实际输出调整),避免分段数据导致的频繁更新 - 数值变化检测:用
_currentDisplayValue记录当前显示的数值,只有当新数值与当前值不同时才更新UI,彻底避免无意义的重绘 - 双缓冲优化:通过反射启用
TextBox的双缓冲特性,减少控件重绘时的闪烁现象 - 空值处理:当解析后重量为空时,自动显示"0",避免文本框内容为空的异常情况
内容的提问来源于stack exchange,提问作者Siamak
相关产品推荐
相关产品推荐

