none
Looking for a more efficient alternative to TextBox objects to display data in form. RRS feed

  • Question

  • Hello,

     I am developing an application that interacts with a toy quad-rotor helicopter.  Approximately 30 times a second the helicopter sends data to my application which I am displaying in a Windows Form using a TextBox control for each individual parameter in the data.

     To display a parameter in its textbox I have been creating a String object to format the parameter and passing that to the TextBox::Text property of the control.  For example:

    tbxAltitude->Text = String::Format("{0}", data->Altitude); 

     My concern that I have is that each time I update the 40+parameters displayed in my form I am forced to create a new String object on the garbage collected heap for each parameter.  Even if I lower the update rate to something more reasonable that still seems less than an ideal solution.

     Can anyone suggest a better approach that would avoid allocating all those String objects on the GC heap?  I looked at the possibility of using (actually reusing) a StringBuilder object to do the formatting but a String object is still required to configure a TextBox.  The only other idea I have at the moment is to look into creating my own custom control that might allow me to update the text more efficiently.

     If anyone could offer some suggestions or point me in a better direction I would really appreciate it.

     Thank you.


    Wednesday, July 11, 2012 9:44 PM

Answers

  • It sounds like you're doing a lot of the "receive data and calculate" work in the GUI thread.   You might get better perceptual performance if you do that in a separate thread and store the values in your data object in the format they will be displayed.

    so 30 times a second:

    data->Altitude = ParseAltituteFromSocketData();  // or whatever
    data->Heading = ParseHeadingFromSocketData()

    then on a timer..maybe 4 times a second?  let the gui refresh it's info from the pre-formatted values:

    txtAltitude.Text = data->Altitude;
    txtHeading.Text = data->Heading;


    This signature unintentionally left blank.

    Thursday, July 12, 2012 9:43 AM

All replies

  • I actually wouldn't worry about this unless you're finding real problems at runtime.

    You'll be creating a lot of string "garbage", but the lifetime of these strings is very, very short.  It's unlikely that they'll get promoted out of Gen0, which will mean the GC will be very fast.

    If you really must avoid this, you'll likely have to use a completely different presentation mechanism which would require doing your own rendering.  To get smooth, clean presentation at very high framerates would likely require you to do the drawing with DirectX or something similar (which could also avoid the need for the managed layer entirely here), but would require significant development effort.  I would not do this unless you find, after profiling, this is problematic.  (Note that, even using the managed GDI drawing in Windows Forms, you'll have to create strings, since the text rendering expects string data...)


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Wednesday, July 11, 2012 10:04 PM
    Moderator
  • A Textbox is usually used for data entry.  You seem to be displaying data.  Are you sure you don't want labels. 
    Wednesday, July 11, 2012 10:07 PM
  • A Textbox is usually used for data entry.  You seem to be displaying data.  Are you sure you don't want labels. 

    This is a very good point - 

    Also, numbers changing at 30fps is VERY hard to read - you may want to consider buffering and/or rounding the data, only changing when values are different, and maybe limiting the display refresh rate (even if the underlying data is changing fast).


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Wednesday, July 11, 2012 10:11 PM
    Moderator
  • Interesting...I guess I really don't have a good feel for how much overhead the garbage collection mechanism introduces.  Actually I did run into a performance issue - a good 3 second pause in which nothing was being sent to the helicopter which in turn caused it to close its socket connection.  During one of those long pauses I halted the program in the debugger and noticed that a high-priority GC Finalizer thread was present.

    That being said, I'm not certain that my GUI is responsible for any of the performance issues, but I thought it might be something that I could at least remove from the equation.

    Thanks for taking the time to respond.

    Thursday, July 12, 2012 1:08 AM
  • Yes, that is a good point.  It had occurred to me at one time but then I noticed that the Label::Text property was a String, just as with the TextBox class.  Overall however, it still might be a better choice than a TextBox.
    Thursday, July 12, 2012 1:14 AM
  • Yes, it is not very useful when the least significant digit in the control is a blur ;)  I already have that on my list of things to do, and it will probably get moved up the priority list after this discussion!
    Thursday, July 12, 2012 1:17 AM
  • It sounds like you're doing a lot of the "receive data and calculate" work in the GUI thread.   You might get better perceptual performance if you do that in a separate thread and store the values in your data object in the format they will be displayed.

    so 30 times a second:

    data->Altitude = ParseAltituteFromSocketData();  // or whatever
    data->Heading = ParseHeadingFromSocketData()

    then on a timer..maybe 4 times a second?  let the gui refresh it's info from the pre-formatted values:

    txtAltitude.Text = data->Altitude;
    txtHeading.Text = data->Heading;


    This signature unintentionally left blank.

    Thursday, July 12, 2012 9:43 AM
  • It sounds like you're doing a lot of the "receive data and calculate" work in the GUI thread.   You might get better perceptual performance if you do that in a separate thread and store the values in your data object in the format they will be displayed.

    so 30 times a second:

    data->Altitude = ParseAltituteFromSocketData();  // or whatever
    data->Heading = ParseHeadingFromSocketData()

    then on a timer..maybe 4 times a second?  let the gui refresh it's info from the pre-formatted values:

    txtAltitude.Text = data->Altitude;
    txtHeading.Text = data->Heading;


    This signature unintentionally left blank.

    Thanks Nick, that's a great idea.

    I do actually have a separate thread that is responsible for updating the GUI.  However, at the "GUI update" rate (currently as fast as new data is coming in) that thread simply gets a copy of the data it is interested in and then marshals a call to a method of the form class that formats the display values and updates the various TextBox controls in the context of the thread that created them.  As you suggest, it would be a better idea to pre-format the display data in the non-GUI thread so that the GUI thread only needs to load it into the appropriate controls.

    Thursday, July 12, 2012 6:10 PM