• 0

[C#] Output command line app progress bar to textbox on one line


Question

I got a program that I'd like to output to a textbox but I'm having an issue with the progress bar. All the stdout from the app displays correctly except once I get to a progress bar:


00
00
00
01
01
01
02
02
02
etc...
[/CODE]

I made this code to handle it:

[CODE]
string o = "";
string pattern = @"(\d{1,2}\%)";
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
while (!process.HasExited)
{
StringBuilder output = new StringBuilder(process.StandardOutput.ReadLine());
MatchCollection matches = rgx.Matches(o);
if (output.ToString () != o){
if (matches.Count > 0)
{
this.txtOutputLog.AppendText(output + System.Environment.NewLine);
}
else
{
this.txtOutputLog.AppendText(output + System.Environment.NewLine);
}
Application.DoEvents();
}
o = output.ToString();
}
[/CODE]

but still get this:

[CODE]
01
02
03
04
05
[/CODE]

How can I get the progress bar to print on one line? I've also tried using "\r".

21 answers to this question

Recommended Posts

  • 0

AppendText, as its name suggests, adds text after whatever existing text is already there. What you're trying to do if I understand well is to replace existing text (the progress indicator) with new text. For this purpose, you could take the existing text, extract everything but the last 2 characters (with String.Substring), add the 2 replacement characters to the resulting string, and set the textbox's Text value to this new string.

  • 0

Right, I was using AppendText to read the output in real time, line by line. I didn't know what code to use to replace the last line (progress bar). I can get a progress bar on the one line but need to keep all the other output as well.

ie. simple setting this.txtOutputLog.Text = (output); works but won't keep the previous output.

this.txtOutputLog.Text += (output); looks weird and also setting this.txtOutputLog.Text += messes with the textbox focus.

  • 0

something like

txtbox.Text = txtbox.Text.Substring(0, txtbox.Text.Length - 2);
txtbox.AppendText(newCounterValue);
[/CODE]

Substring allows to select which part of a string you want, you can use it to select everything except the characters you want to replace and add the replacement characters after that.

  • 0
  On 13/04/2013 at 00:37, Dr_Asik said:

something like

txtbox.Text = txtbox.Text.Substring(0, txtbox.Text.Length - 2);
txtbox.AppendText(newCounterValue);
[/CODE]

Substring allows to select which part of a string you want, you can use it to select everything except the characters you want to replace and add the replacement characters after that.

This seems to work OK

[CODE]
this.txtOutputLog.Text = this.txtOutputLog.Text.Substring(0, this.txtOutputLog.Text.Length - 11);
this.txtOutputLog.AppendText(o);
[/CODE]

Textbox seems to flicker slightly...

  • 0

You don't need a background worker to use a progress bar any more than to use a textbox. What you need a background worker for is having your long-running operation not block the UI thread so the application remains responsive.

  • 0
  On 13/04/2013 at 01:03, DPyro said:

Ya I was thinking about doing that but would need to figure out how to add the background worker etc.

Could just use the Application.DoEvents() function to do your updates to a progress bar without a background worker. This will stop the gui from locking, but you won't need to use a Background worker.. which is really just a thread with training wheels.

  • 0
  On 13/04/2013 at 01:16, firey said:

Could just use the Application.DoEvents() function to do your updates to a progress bar without a background worker. This will stop the gui from locking, but you won't need to use a Background worker.. which is really just a thread with training wheels.

With easy options like BackgroundWorker (.NET 2) and async in C# (C# 5) now there's really no reason to use DoEvents() anymore, which is an error-prone hack. It may be easy to write, but it's hell to debug. The UI thread is for the UI, using it to perform long-running operations is just bad design.
  • 0

This is all just standard string manipulation, I suggest you take a look at the String class, specifically methods like Trim, Substring, Replace, Concat, Join and Split. For instance here you could store the last entry you added in a temporary string and do a Replace of that with the new one you want. Or you could split by newline characters, exclude the last line, join the result and add the replacement at the end. There are many ways to go about this.

  • 0
  On 13/04/2013 at 01:29, Dr_Asik said:

With easy options like BackgroundWorker (.NET 2) and async in C# (C# 5) now there's really no reason to use DoEvents() anymore, which is an error-prone hack. It may be easy to write, but it's hell to debug. The UI thread is for the UI, using it to perform long-running operations is just bad design.

While I agree with that, it would be a working hack he could use without learning bw's and async stuff.

  • 0

TextBox isn't a very good control to use for console output. It looks like what you're trying to do is simulate a console to display the output from a CLI application you're running in a process. I would recommend using a ListBox instead. You can use the ListBox.Items.Add() method to add each line as it's output then when you get to your progress parsing you can use

ListBox.Items[ListBox.Items.Count - 1] = "<whatever you want>";

to replace the line with the new value. Then only that particular line might flicker. :)

Your second problem is a regular expression issue. If the CLI app's output is different you'd have to match it differently as well. Match(@"(\d+)%.*" ) should get you just the percentage number from your example.

  • 0

Ok the listbox works good but as you said it does flicker quite a bit.

EDIT:

I added this to select the last line which gets rid of the flicker, but how do I change the selected color so that you can't tell it's selected


lstOutputLog.SelectedIndex = lstOutputLog.Items.Count - 1;
[/CODE]

Edited by DPyro
  • 0

Should be clear that I'm replacing:


lstOutputLog.Refresh();
[/CODE]

With:

[CODE]
lstOutputLog.SelectedIndex = lstOutputLog.Items.Count - 1;
[/CODE]

Unless there's a better way to update the listbox after each line is added...

  • 0

You don't need to select anything. You can just change the last line in the Listbox with the code I posted. It will make the last line say "<whatever you want>" the way it is so you would want to use the percentage that you parsed from the process's output instead of the example string. After it doesn't match anymore (i.e.: the process is complete) you can continue logging whatever else it might print using the listbox's Add() method.

  • 0
  On 14/04/2013 at 03:05, GreyWolf said:

You don't need to select anything. You can just change the last line in the Listbox with the code I posted. It will make the last line say "<whatever you want>" the way it is so you would want to use the percentage that you parsed from the process's output instead of the example string. After it doesn't match anymore (i.e.: the process is complete) you can continue logging whatever else it might print using the listbox's Add() method.

This is what I have, but if I don't refresh the listbox somehow then nothing is displayed until the process has ended.


while (!process.HasExited)
{
string pattern = @"(\d+)%.*";
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
StringBuilder output = new StringBuilder(process.StandardOutput.ReadLine());
Match Match = rgx.Match(output.ToString ());
if (!Match.Success)
{
lstOutputLog.Items.Add(output + "\n");
}
else
{
lstOutputLog.Items[lstOutputLog.Items.Count - 1] = (output);
}
}
[/CODE]

The other issue I'm having is that the output freezes every couple of seconds. Think it has something to do with the buffer being filled up and waiting to be flushed. :/

  • 0
  On 14/04/2013 at 05:41, DPyro said:

The other issue I'm having is that the output freezes every couple of seconds. Think it has something to do with the buffer being filled up and waiting to be flushed. :/

So I added this to the cli program which is written in c/c++, which fixes the freezing of stdout


setvbuf(stdout, NULL, _IONBF, 0);
[/CODE]

Only issue I have is that I have to set

[CODE]lstOutputLog.SelectionMode = SelectionMode.One;[/CODE]

at the beginning and

[CODE]lstOutputLog.SelectionMode = SelectionMode.None;[/CODE]

at the end so that the listbox isn't selectable. At the end of program run, the log scrolls back to the top :wacko:

  • 0
  On 14/04/2013 at 05:41, DPyro said:

This is what I have, but if I don't refresh the listbox somehow then nothing is displayed until the process has ended.

That's normal, because you're keeping the UI thread busy doing your loop, it cannot do anything else during that. It cannot even repaint itself. That's why the UI thread is for updating the UI and responding to user events, not performing your long-running computations.

There are different ways to go about fixing this. The classical, most correct way is to spawn a background thread; there many tutorials with full code on how to do this, example: this.

Alternatively, you could still do this on the UI thread, but one small part at a time, for instance by passing what forms the body of your while loop to a timer. This will cause this code to execute repeatedly, but will let the UI execute as it wishes between each two calls.

There's as also, as firey pointed out, a hack that consists of calling Application.DoEvents() in your loop; this effectively triggers a full UI update from the currently executing UI update; as long it doesn't end up calling back into your code, it shouldn't lead to horrifying things. Note the use of conditionals there; this isn't a reliable way, which can cause your app to randomly behave in ways you don't understand. I don't recommend this approach unless you really know what you're doing (and if you did you'd probably never choose this approach).

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • Nintendo Switch 2 launches, where to buy and a list of games that it may not support by Sayan Sen Nintendo announced the Switch 2 back in early April this year and then followed that up with more details related to performance and hardware features later. The company touted 10x the performance of the Switch. However, on the flip side, the battery suffers, and you also need new microSD Express cards for storage. For those who need a refresher, here are the technical specification details of the Switch 2: Specification Details Dimensions Approx. 166mm x 272mm x 13.9mm (with Joy-Con 2 attached); Maximum thickness from control stick tip to ZL/ZR buttons: 30.7mm Weight Approx. 401g (console only); Approx. 534g (with Joy-Con 2 controllers attached) Screen 7.9-inch capacitive touch LCD; 1920x1080 resolution; HDR10 support; VRR up to 120 Hz CPU/GPU Custom processor made by NVIDIA Storage 256 GB UFS (a portion reserved for system use) Communication Wireless LAN (Wi‑Fi 6), Bluetooth; Wired LAN available in TV mode via dock Video Output Up to 3840x2160 at 60 fps via HDMI in TV mode; Supports 120 fps at lower resolutions; HDR10 enabled Audio Output Linear PCM 5.1 channel via HDMI; Stereo speakers Microphone Built-in monaural microphone with noise cancellation, echo cancellation and auto gain control Buttons POWER and Volume buttons USB Ports 2 USB Type-C ports (bottom port for charging/dock connection; top port for accessories/charging) Audio Jack 3.5mm stereo mini plug (CTIA standard) Game Card Slot Supports both Nintendo Switch 2 and Nintendo Switch game cards Expansion Slot microSD Express card slot (compatible with cards up to 2 TB; other microSD cards can copy screenshots and videos) Sensors Accelerometer, gyroscope, brightness sensor Battery Lithium-ion, 5220 mAh; Approx. 2–6.5 hours lifetime; 3-hour charge time in sleep mode Dock Approx. 115mm x 201mm x 51.2mm; Weight: approx. 383g For those looking to get one, major retailers like Walmart, GameStop, Best Buy, and Target have all confirmed that they will have limited console stock from time to time so you will need to be on alert and check back. Nintendo has also published a full list of games that may not work on the Switch 2: Borderlands 3 Chrono Cross: The Radical Dreamers Edition Crash Bandicoot N-Sane Trilogy Guilty Gear XX Accent Core Plus R KarmaZoo Marvel vs. Capcom Fighting Collection: Arcade Classics Mortal Kombat 1 Overwatch 2 Star Wars: Knights of the Old Republic II: The Sith Lords Star Wars Republic Commando Super Mega Baseball 4 Tombi! Special Edition Tony Hawk's Pro Skater 1+2 Touhou Genso Wanderer Reloaded Ty the Tasmanian Tiger HD Warriors: Abyss However, keep in mind that Nintendo last updated the support list last month on May 27th and the company may still be testing these. So keep an eye on the official list of games on this webpage here on Nintendo's site. Have you managed to pick up the Nintendo Switch 2? Let us know in the comments.
    • Court orders Apple to keep web links in the App Store, eroding its iOS payment monopoly by Fiza Ali Apple has been ordered to continue permitting web links and external payment options in the App Store after its bid to halt court’s ruling was declined today by a higher court. Earlier this year, in April, a federal judge decreed that Apple must allow developers to include web links in their iOS apps, remove restrictions on link formatting, and enable external payment methods without taking a commission on transactions. Apple immediately appealed and sought an injunction to delay implementation of the order while the case progressed. However, the United States Court of Appeals has now refused Apple’s emergency request to stay the district court’s order. In its decision, the panel held that Apple had not demonstrated a sufficient likelihood of success on appeal, nor that it would suffer irreparable harm if the order were enforced. The court also considered potential prejudice to other parties and the public interest, concluding that an immediate suspension was not warranted. This ruling makes it much harder for Apple to overturn the April decision, which came from a lawsuit initiated by Epic Games. Epic first sued Apple’s App Store policies in 2020, claiming that the company’s restrictions harmed competition. While Epic did not prevail on every count, the court did rule that Apple must allow developers to inform users of alternative purchasing options at better prices. Despite that narrow victory, Apple repeatedly failed to conform to the terms from the original 2021 ruling, prompting the judge in April to issue a more detailed order outlining precisely how the App Store must be “opened up”. In response to the April ruling, prominent third-party apps have swiftly implemented web-based purchasing links. Both Spotify and Amazon’s Kindle app now include buttons directing users to purchase subscriptions via their websites, bypassing Apple’s in-app payments. Additionally, Fortnite has made a comeback on iOS after around five years, presenting users with the choice between Apple’s in-app payment system and Epic’s own payment and rewards mechanism. According to Epic CEO Tim Sweeney, there is presently a 60:40 split in usage favouring Apple’s system over Epic’s, though the gap appears to be narrowing. An Apple spokesperson, Olivia Dalton, issued a statement expressing the company’s disappointment: For now, Apple must comply with the existing injunction. Unless the Appeals Court later overturns the ruling, developers can continue to include web payment links, and Apple’s longstanding monopoly over iOS payment processing may continue to erode. The ultimate resolution will depend on the outcome of the ongoing appeals, which could set a significant precedent for how app marketplaces operate in the future. Source: The Verge
    • Reddit posts are all public, no login(therefore no agreeing to contract) to view the content. It's like the equivalent of sitting in a library and writing down notes from a textbook without signing it out and they start suing you for writing notes.
  • Recent Achievements

    • Rookie
      GTRoberts went up a rank
      Rookie
    • First Post
      James courage Tabla earned a badge
      First Post
    • Reacting Well
      James courage Tabla earned a badge
      Reacting Well
    • Apprentice
      DarkShrunken went up a rank
      Apprentice
    • Dedicated
      CHUNWEI earned a badge
      Dedicated
  • Popular Contributors

    1. 1
      +primortal
      397
    2. 2
      +FloatingFatMan
      177
    3. 3
      snowy owl
      170
    4. 4
      ATLien_0
      167
    5. 5
      Xenon
      134
  • Tell a friend

    Love Neowin? Tell a friend!