简体   繁体   English

如何在文本框中显示从串行端口接收的数据而文本不会在Visual Studio C#中消失?

[英]How to display data received from serial port in a textbox without the text disappearing in Visual Studio C#?

So, I'm trying to develop a simple application in visual C# which gets data from serial port and displays it in a textbox (to monitor temperature). 因此,我试图在Visual C#中开发一个简单的应用程序,该应用程序从串行端口获取数据并将其显示在文本框中(以监视温度)。 I'm acquiring and displaying the data successfully, using the DataReceived event to update a global string variable and a timer to update the text field on my text box, as shown: 我正在成功获取和显示数据,使用DataReceived事件更新全局字符串变量,并使用计时器更新文本框上的文本字段,如下所示:

    private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
    {
        try
        {
            globalVar.updateTemp = port.ReadLine(); //This is my global string
        }
        catch (IOException)
        {
        }
        catch (InvalidOperationException)
        {
        }
        catch (TimeoutException)
        {
        }
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        tempDisplayBox.Text = globalVar.updateTemp; //This is my textbox updating
    }

The only issue I have is that the value shown in the textbox keeps flashing, making it hard to read. 我唯一的问题是,文本框中显示的值一直闪烁,很难读取。 My timer is set to trigger every 10 ms (which should be fast enough, right?). 我的计时器设置为每10毫秒触发一次(应该足够快,对吧?)。 Is there any way to make it more stable? 有什么方法可以使其更稳定吗? I realize this may be a newb question, but to be fair I am a newb :) Any help is appreciated! 我意识到这可能是个问题,但老实说,我是个问题:)任何帮助,我们都感激不尽! Thanks! 谢谢!

Do you really need it updating every 10ms ? 您真的需要每10ms更新一次吗? What about every 500 ms or if not that then 100ms . 500 ms100ms 100ms will require your update method run 10 times less and therefore update 10 times less. 100ms将需要您的更新方法运行少10倍,因此更新少10倍。 The flickering you are expiriencing is due to the refresh speed. 您正在经历的闪烁是由于刷新速度。 You could create custom method which will only update the temp only when target Label or textBox value is different than source port . 您可以创建自定义方法,仅在目标LabeltextBox值与源port不同时才更新温度。 But that will only sort the flickering when temp is steady, when temp will start vary it will bring back the flickering. 但这只会在温度稳定时对闪烁进行分类,当温度开始变化时,它将恢复闪烁。 Good luck ;-) 祝好运 ;-)

UPDATE UPDATE

Hi I tried to reproduce the conditions and could not make my textbox nor Label flash. 嗨,我试图重现条件,但无法使我的文本框或标签闪烁。 The way I tested it was by assigning int ntick = 0; 我测试它的方法是分配int ntick = 0; and then increment the ++ntick; 然后增加++ntick; inside of the timer_tick method. timer_tick方法内部。 The results didn't make any of the controls flash and were updated even every milisecond at some point. 结果并没有使任何控件闪烁,并且甚至在每毫秒内更新一次。 I also tried string.Format to put some load on the method. 我还尝试使用string.Format对方法施加一些负担。 Is your app responsive? 您的应用程序反应灵敏吗?

The trick is to use double buffering. 诀窍是使用双缓冲。 This way the operating system will redraw the Control off-screen, and only show the control when it is fully redrawn. 这样,操作系统将在屏幕外重绘该控件,并且仅在完全重绘后才显示该控件。

I have had the same problem, and solved it by extending the TextBox control like this: 我遇到了同样的问题,并通过扩展TextBox控件来解决此问题,如下所示:

public FastLogBox()
    {
        InitializeComponent();
        _logBoxText = new StringBuilder(150000);

        timer1.Interval = 20;
        timer1.Tick += timer1_Tick;
        timer1.Start();
        SetStyle(ControlStyles.DoubleBuffer, true);
    }

    void timer1_Tick(object sender, EventArgs e)
    {
        if (_timeToClear)
        {
            _logBoxText.Clear();
            _timeToClear = false;
        }

        if (_logQueue.Count <= 0) return;

        while (!_logQueue.IsEmpty)
        {
            string element;
            if (!_logQueue.TryDequeue(out element)) continue;
            {
                _logBoxText.Insert(0, element + "\r\n");
            }
        }
        if (_logBoxText.Length > 150000)
        {
            _logBoxText.Remove(150000, _logBoxText.Length - 150001);
        }
        Text = _logBoxText.ToString();
    }
    public new void Clear()
    {
        _timeToClear = true;
        while (!_logQueue.IsEmpty)
        {
            string element;
            _logQueue.TryDequeue(out element);
        }
    }
    public void AddToQueue(string message)
    {
        _logQueue.Enqueue(message);
    }
}

I also use a timer and a concurrentQueue to avoid using Invoke to update the control from another thread. 我还使用计时器和并发队列,以避免使用Invoke从另一个线程更新控件。 I also use a StringBuilder to prepare the string before putting it into the TextBox. 在将其放入TextBox之前,我还使用StringBuilder来准备字符串。 StringBuilder is faster when building larger strings. 构建较大的字符串时,StringBuilder速度更快。

You can use ReadExisting() to read the whole data at a time. 您可以使用ReadExisting()读取全部数据。 You need to handle DataReceived Event of SerialPort 您需要处理SerialPort DataReceived事件

serialPort1.ReadExisting();

Sample: 样品:

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
           String myData=serialPort1.ReadExisting();
        }

Example Code: Here i would like to show you the code to Read Data(RFID Tag Code which is basically of length 12) 示例代码:在这里,我想向您展示读取数据的代码(RFID标签代码,长度基本上为12)

        String macid  = "";
        private void DoWork()
        {
            Invoke(
                  new SetTextDeleg(machineExe ),
                  new object[] { macid  });
            macid  = "";
        }
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {

            string str1;
            macid += serialPort1.ReadExisting();

            if (macid.Length == 12)
            {
                macid = macid.Substring(0, 10);
                Thread t = new Thread(new ThreadStart(DoWork));
                t.Start();
            }
        }

         public void machineExe(string text)
          {
            TextBox1.Text=text;
          }

Thank you so much for the answers! 非常感谢您的回答! I found a way to work around this issue: Instead of replacing the contents of my textbox by rewriting the TextBox.Text property - which, as HenningNT implied, refreshes the control and causes the flickering - I'm now using the TextBox.AppendText method. 我找到了解决此问题的方法:而不是通过重写TextBox.Text属性来替换文本框的内容-正如HenningNT所暗示的那样,它刷新控件并导致闪烁-我现在使用的是TextBox.AppendText方法。 Though, as I want to display only one line of data at a time, I use the textbox in multiline mode and the Environment.NewLine to jump to a new line before appending the text. 但是,由于一次只显示一行数据,因此在多行模式下使用文本框,并在附加文本之前使用Environment.NewLine跳转到新行。 As for the method of updating, I've gone back to using the timer because with the invoke method was crashing my application when I close the form, for some reason. 至于更新方法,我已经回到使用计时器的原因,因为由于某种原因,当我关闭表单时,invoke方法使应用程序崩溃。 Also, enabling double buffering didn't do me much good, although I guess I was doing it wrong... It still flickers a bit, but it's much better now :) I know this is not really a perfect solution (much more of a workaround), so I'll keep looking for it. 另外,虽然我猜我做错了,但是启用双重缓冲并没有多大帮助。它仍然会闪烁一点,但是现在好多了:)我知道这并不是一个完美的解决方案(更多内容解决方法),因此我将继续寻找它。 If I find it, I'll be sure to update it here ;) My code: 如果找到它,我将确保在这里进行更新;)我的代码:

    private void timer1_Tick(object sender, EventArgs e) //Timer to update textbox
    {
        if (tempDisplayBox.Text != globalVar.updateTemp) //Only update if temperature is different
        {
            try
            {
                tempDisplayBox.AppendText(Environment.NewLine);
                tempDisplayBox.AppendText(globalVar.updateTemp);
            }
            catch (NullReferenceException)
            { 
            }
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM