C # Windows Konsolu Uygulamasında geçerli satırı nasıl güncelleyebilirim?


507

C # içinde bir Windows Konsol Uygulaması oluştururken, geçerli bir satırı genişletmek veya yeni bir satıra gitmek zorunda kalmadan konsola yazmak mümkün mü? Örneğin, bir işlemin tamamlanmaya ne kadar yakın olduğunu gösteren bir yüzde göstermek istersem, yalnızca imleçle aynı satırdaki değeri güncellemek ve her bir yüzdeyi yeni bir satıra koymak zorunda değilim.

Bu bir "standart" C # konsol uygulaması ile yapılabilir mi?


GERÇEKTEN havalı komut satırı arayüzleriyle ilgileniyorsanız curses / ncurses'a göz atmalısınız.
Charles Addis

@CharlesAddis ama curses / ncurses sadece C ++ 'da çalışmıyor mu?
Xam

Yanıtlar:


783

Yalnızca "\r"konsola yazdırırsanız , imleç geçerli satırın başına gider ve yeniden yazabilirsiniz. Bu hile yapmalı:

for(int i = 0; i < 100; ++i)
{
    Console.Write("\r{0}%   ", i);
}

Daha önce orada olan her şeyin silindiğinden emin olmak için sayıdan sonraki birkaç boşluğa dikkat edin.
Ayrıca satırın sonuna "\ n" eklemek istemediğiniz için Write()yerine kullanıldığına dikkat edin WriteLine().


7
(int i = 0; i <= 100; ++ i)% 100'e gidecek
Nicolas Tyler

13
Önceki yazı yeni yazıdan daha uzun olduğunda nasıl başa çıkıyorsunuz? Konsolun genişliğini almanın ve çizgiyi boşluklarla doldurmanın bir yolu var mı?
Drew Chapin

6
@druciferre Başımın tepesinden sorunuza iki cevap düşünebilirim. Her ikisi de geçerli çıktıyı önce bir dize olarak kaydetmeyi ve bunun gibi belirli sayıda karakterle doldurmayı içerir: Console.Write ("\ r {0}", strOutput.PadRight (nPaddingCount, '')); "NPaddingCount", kendiniz ayarladığınız bir sayı olabilir veya önceki çıktının kaydını tutabilir ve nPaddingCount'u, önceki ve akım çıkışı ile geçerli çıkış uzunluğu arasındaki uzunluk farkı olarak ayarlayabilirsiniz. NPaddingCount negatifse, abs (prev.len - curr.len) yapmadığınız sürece PadRight'ı kullanmanız gerekmez.
John Odom

1
@malgm İyi organize edilmiş kod. Bir düzine iş parçacığından herhangi biri istediği zaman konsola yazabiliyorsa, yeni satırlar yazıp yazmamaya bakılmaksızın size sıkıntı verir.
Mark

2
@JohnOdom, yalnızca önceki (bantlanmamış) çıkış uzunluğunu korumanız ve ardından bunu ilk argüman olarak beslemeniz gerekir PadRight(elbette bantlanmamış dizeyi veya uzunluğu kaydetme).
Jesper Matthiesen

254

Sen kullanabilirsiniz Console.SetCursorPositionimlecin konumunu ayarlamak için ve daha sonra mevcut konumda yazın.

Basit bir "döndürücüyü" gösteren bir örnek :

static void Main(string[] args)
{
    var spin = new ConsoleSpinner();
    Console.Write("Working....");
    while (true) 
    {
        spin.Turn();
    }
}

public class ConsoleSpinner
{
    int counter;

    public void Turn()
    {
        counter++;        
        switch (counter % 4)
        {
            case 0: Console.Write("/"); counter = 0; break;
            case 1: Console.Write("-"); break;
            case 2: Console.Write("\\"); break;
            case 3: Console.Write("|"); break;
        }
        Thread.Sleep(100);
        Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
    }
}

Yeni çıktı veya boşluklarla mevcut çıktıların üzerine yazdığınızdan emin olmanız gerekir.

Güncelleme: Örneğin imleci yalnızca bir karakter geriye götürdüğü eleştirildiğinden, bunu açıklığa kavuşturmak için ekleyeceğim: SetCursorPositionBunu kullanarak imleci konsol penceresindeki herhangi bir konuma ayarlayabilirsiniz.

Console.SetCursorPosition(0, Console.CursorTop);

imleci geçerli satırın başına getirir (veya Console.CursorLeft = 0doğrudan kullanabilirsiniz ).


8
Sorun \ r kullanılarak çözülebilir, ancak SetCursorPosition(veya CursorLeft) kullanmak daha fazla esnekliğe izin verir, örneğin satırın başında yazma, pencerede yukarı hareket etme vb. Bu nedenle örneğin çıktı için kullanılabilecek daha genel bir yaklaşımdır. özel ilerleme çubukları veya ASCII grafiği.
Dirk Vollmar

14
Ayrıntılı olmak ve görev çağrısının ötesine geçmek için +1. İyi şeyler teşekkürler.
Copas

1
Bunu yapmanın farklı bir yolunu göstermek için +1. Herkes gösterdi, ve OP sadece bir yüzdeyi güncelliyorsa, bununla sadece tüm satırı yeniden yazmak zorunda kalmadan değeri güncelleyebilirsiniz. OP aslında satırın başına geçmek istediğini söylemedi, sadece imleçle aynı satırda bir şey güncellemek istediğini söyledi.
Andy

1
SetCursorPosition'ın ek esnekliği, döngü kullanıcının fark edebileceği kadar uzunsa, biraz hız ve gözle görülür bir imleç titremesi pahasına gelir. Aşağıdaki test yorumuma bakın.
Kevin

5
Ayrıca satır uzunluğunun konsolun bir sonraki satıra sarılmasına neden olmadığından emin olun, aksi takdirde konsol penceresinden aşağıya doğru çalışan içerikle ilgili sorunlar alabilirsiniz.
Mandrake

84

Şimdiye kadar bunun nasıl yapılacağı konusunda üç rakip alternatifimiz var:

Console.Write("\r{0}   ", value);                      // Option 1: carriage return
Console.Write("\b\b\b\b\b{0}", value);                 // Option 2: backspace
{                                                      // Option 3 in two parts:
    Console.SetCursorPosition(0, Console.CursorTop);   // - Move cursor
    Console.Write(value);                              // - Rewrite
}

Her zaman kullandım Console.CursorLeft = 0, üçüncü seçenekte bir varyasyon, bu yüzden bazı testler yapmaya karar verdim. İşte kullandığım kod:

public static void CursorTest()
{
    int testsize = 1000000;

    Console.WriteLine("Testing cursor position");
    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < testsize; i++)
    {
        Console.Write("\rCounting: {0}     ", i);
    }
    sw.Stop();
    Console.WriteLine("\nTime using \\r: {0}", sw.ElapsedMilliseconds);

    sw.Reset();
    sw.Start();
    int top = Console.CursorTop;
    for (int i = 0; i < testsize; i++)
    {
        Console.SetCursorPosition(0, top);        
        Console.Write("Counting: {0}     ", i);
    }
    sw.Stop();
    Console.WriteLine("\nTime using CursorLeft: {0}", sw.ElapsedMilliseconds);

    sw.Reset();
    sw.Start();
    Console.Write("Counting:          ");
    for (int i = 0; i < testsize; i++)
    {        
        Console.Write("\b\b\b\b\b\b\b\b{0,8}", i);
    }

    sw.Stop();
    Console.WriteLine("\nTime using \\b: {0}", sw.ElapsedMilliseconds);
}

Makinemde aşağıdaki sonuçları elde ediyorum:

  • Arka boşluklar: 25.0 saniye
  • Satır Başı: 28,7 saniye
  • SetCursorPosition: 49.7 saniye

Ayrıca, SetCursorPositionher iki alternatifle de gözlemlemediğim gözle görülür titremeye neden oldu. Bu nedenle, ahlaki mümkün olduğunda arka boşluklar veya satır başı kullanmaktır ve bana bunu yapmanın daha hızlı bir yolunu öğrettiğiniz için teşekkürler , SO!


Güncelleme : Yorumlarda Joel, SetCursorPosition'ın diğer yöntemler doğrusal iken taşınan mesafeye göre sabit olduğunu önermektedir. Daha ileri testler bunun doğru olduğunu teyit eder, ancak sabit zaman ve yavaş hala yavaştır. Testlerimde, konsola uzun bir arka boşluk dizesi yazmak, 60 karakter civarında bir yere kadar SetCursorPosition'dan daha hızlıdır. Bu nedenle geri silme, satırın 60 karakterden kısa bölümlerini değiştirmek için daha hızlıdır ve titremez, bu yüzden \ r over \ r ve üzerindeki ilk onayımla duracağım SetCursorPosition.


4
Söz konusu operasyonun verimliliği gerçekten önemli olmamalı. Her şey kullanıcının fark edemeyeceği kadar hızlı gerçekleşmelidir. Gereksiz mikroptimisasyon kötüdür.
Malfist

@Malfist: Döngünün uzunluğuna bağlı olarak, kullanıcı fark edebilir veya etmeyebilir. Yukarıdaki düzenlemeye eklediğim gibi (yorumunuzu görmeden önce), SetCursorPosition titremeyi başlattı ve diğer seçeneklerin neredeyse iki katı kadar sürüyor.
Kevin

1
Bunun bir mikro optimizasyon olduğunu kabul ediyorum (milyon kez çalıştırmak ve 50 saniye almak hala çok az zaman alıyor), sonuçlar için +1 ve kesinlikle bilmek çok yararlı olabilir.
Andy

6
Benchmark temelde kusurlu. SetCursorPosition () süresi, imlecin ne kadar ilerlediğine bakılmaksızın aynı olabilirken, diğer seçenekler konsolun kaç karakter işlemesi gerektiğine göre değişir.
Joel Coehoorn

1
Bu, mevcut farklı seçeneklerin çok güzel bir özetidir. Ancak, ben \ r kullanırken titrek görüyorum. \ B ile, düzeltilen metin ("Counting:") yeniden yazılmadığından hiçbir titreşim yoktur. Ek \ b eklerseniz ve düzeltme metnini \ b ve SetCursorPosition ile olduğu gibi yeniden yazarsanız da titreyeceksiniz. Joel sözünü ile ilgili: Joel temelde haklı, ancak hala çok uzun satırlarda SetCursorPosition daha iyi performans, ancak fark daha az olur.
Dirk Vollmar

27

Geçerli satırdaki belirli sayıda karakteri yedeklemek için \ b (geri silme) kaçış dizisini kullanabilirsiniz. Bu sadece geçerli konumu taşır, karakterleri kaldırmaz.

Örneğin:

string line="";

for(int i=0; i<100; i++)
{
    string backup=new string('\b',line.Length);
    Console.Write(backup);
    line=string.Format("{0}%",i);
    Console.Write(line);
}

Burada satır , konsola yazılacak yüzde satırdır. İşin püf noktası , önceki çıktı için doğru sayıda \ b karakteri oluşturmaktır.

Bunun \ r yaklaşımına göre avantajı yüzde çıktısı satırın başında olmasa bile çalışır olmasıdır.


1
+1, bu sunulan en hızlı yöntem olduğu ortaya çıkıyor (aşağıdaki test yorumuma bakın)
Kevin

19

\rbu senaryolar için kullanılır.
\r simgesi, imlecin satır başlangıcına geri döndüğü anlamına gelir.
Bu yüzden Windows \n\ryeni çizgi işaretçisi olarak kullanıyor .
\nsizi bir satır aşağı taşır ve satırın başına \rdöndürür.


22
Aslında aslında \ r \ n.
Joel Mueller

14

Sadece divo'nun ConsoleSpinnersınıfıyla oynamak zorunda kaldım . Benimki hiçbir yere özlü değil, ama benimle o sınıfın kullanıcılarının kendi while(true)döngülerini yazmak zorunda kalmadıkları iyi değildi. Bunun gibi bir deneyim için çekim yapıyorum:

static void Main(string[] args)
{
    Console.Write("Working....");
    ConsoleSpinner spin = new ConsoleSpinner();
    spin.Start();

    // Do some work...

    spin.Stop(); 
}

Ve bunu aşağıdaki kodla anladım. Metodumun Start()bloke edilmesini istemediğimden, kullanıcının benzer bir while(spinFlag)döngü yazma konusunda endişelenmesini istemiyorum ve aynı zamanda birden fazla iplikçinin, işlemek için ayrı bir iplik oluşturması gerektiğine izin vermek istiyorum eğirme. Bu da kodun çok daha karmaşık olması gerektiği anlamına geliyor.

Ayrıca, o kadar çok iş parçacığı yapmadım, bu yüzden orada küçük bir hata bıraktım (muhtemelen). Ama şimdiye kadar gayet iyi çalışıyor gibi görünüyor:

public class ConsoleSpinner : IDisposable
{       
    public ConsoleSpinner()
    {
        CursorLeft = Console.CursorLeft;
        CursorTop = Console.CursorTop;  
    }

    public ConsoleSpinner(bool start)
        : this()
    {
        if (start) Start();
    }

    public void Start()
    {
        // prevent two conflicting Start() calls ot the same instance
        lock (instanceLocker) 
        {
            if (!running )
            {
                running = true;
                turner = new Thread(Turn);
                turner.Start();
            }
        }
    }

    public void StartHere()
    {
        SetPosition();
        Start();
    }

    public void Stop()
    {
        lock (instanceLocker)
        {
            if (!running) return;

            running = false;
            if (! turner.Join(250))
                turner.Abort();
        }
    }

    public void SetPosition()
    {
        SetPosition(Console.CursorLeft, Console.CursorTop);
    }

    public void SetPosition(int left, int top)
    {
        bool wasRunning;
        //prevent other start/stops during move
        lock (instanceLocker)
        {
            wasRunning = running;
            Stop();

            CursorLeft = left;
            CursorTop = top;

            if (wasRunning) Start();
        } 
    }

    public bool IsSpinning { get { return running;} }

    /* ---  PRIVATE --- */

    private int counter=-1;
    private Thread turner; 
    private bool running = false;
    private int rate = 100;
    private int CursorLeft;
    private int CursorTop;
    private Object instanceLocker = new Object();
    private static Object console = new Object();

    private void Turn()
    {
        while (running)
        {
            counter++;

            // prevent two instances from overlapping cursor position updates
            // weird things can still happen if the main ui thread moves the cursor during an update and context switch
            lock (console)
            {                  
                int OldLeft = Console.CursorLeft;
                int OldTop = Console.CursorTop;
                Console.SetCursorPosition(CursorLeft, CursorTop);

                switch (counter)
                {
                    case 0: Console.Write("/"); break;
                    case 1: Console.Write("-"); break;
                    case 2: Console.Write("\\"); break;
                    case 3: Console.Write("|"); counter = -1; break;
                }
                Console.SetCursorPosition(OldLeft, OldTop);
            }

            Thread.Sleep(rate);
        }
        lock (console)
        {   // clean up
            int OldLeft = Console.CursorLeft;
            int OldTop = Console.CursorTop;
            Console.SetCursorPosition(CursorLeft, CursorTop);
            Console.Write(' ');
            Console.SetCursorPosition(OldLeft, OldTop);
        }
    }

    public void Dispose()
    {
        Stop();
    }
}

Güzel değişiklik, ancak örnek kod benim değil. Brad Abrams'ın blogundan alınmıştır (cevabımdaki bağlantıya bakınız). Ben sadece SetCursorPosition gösteren basit bir örnek olarak yazılmıştır düşünüyorum. Btw, sadece basit bir örnek olduğunu düşündüğüm şeyle ilgili tartışmaya (olumlu bir şekilde) kesinlikle şaşırdım. Bu yüzden bu siteyi seviyorum :-)
Dirk Vollmar

4

Açıkça bir Satır Başı (\ r) kullanmak yerine satırın başında (örtük veya açık olarak) yerine Yeni Bir Satır (\ n) kullanmak istediğinizi almalısınız. Örneğin:

void demoPercentDone() {
    for(int i = 0; i < 100; i++) {
        System.Console.Write( "\rProcessing {0}%...", i );
        System.Threading.Thread.Sleep( 1000 );
    }
    System.Console.WriteLine();    
}

-1, Soru C # sorar, ben C # yeniden yazmak ve tekrar F # değiştirmek
Malfist

C #'ınızı tekrar F # olarak değiştirmesi yerine bir düzenleme çakışması gibi görünüyor. Değişimi sizinkinden bir dakika sonraydı ve sprintf'e odaklandı.
Andy

Düzenleme için teşekkürler. Bir şeyleri test etmek için F # etkileşimli modunu kullanma eğilimindeyim ve önemli kısımların C #'da aynı olan BCL çağrıları olduğunu düşündüm.
James Hugard

3
    public void Update(string data)
    {
        Console.Write(string.Format("\r{0}", "".PadLeft(Console.CursorLeft, ' ')));
        Console.Write(string.Format("\r{0}", data));
    }

1

MSDN'deki Konsol belgelerinden:

Bu sorunu, Out veya Error özelliğinin TextWriter.NewLine özelliğini başka bir satır sonlandırma dizesine ayarlayarak çözebilirsiniz. Örneğin, C # deyimi, Console.Error.NewLine = "\ r \ n \ r \ n";, standart hata çıktı akışı için satır sonlandırma dizesini iki satırbaşı ve satır besleme sırasına ayarlar. Sonra açıkça C # deyimi Console.Error.WriteLine (); hata çıktı akışı nesnesinin WriteLine yöntemini çağırabilirsiniz.

Yani - bunu yaptım:

Console.Out.Newline = String.Empty;

Sonra çıktıyı kendim kontrol edebiliyorum;

Console.WriteLine("Starting item 1:");
    Item1();
Console.WriteLine("OK.\nStarting Item2:");

Oraya gitmenin başka bir yolu.


Console.Write () yöntemini, NewLine özelliğini yeniden tanımlamadan aynı amaç için kullanabilirsiniz ...
Radosław Gers

1

Bu, dosya oluşturmanın harika görünmesini istiyorsanız çalışır.

                int num = 1;
                var spin = new ConsoleSpinner();
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write("");
                while (true)
                {
                    spin.Turn();
                    Console.Write("\r{0} Generating Files ", num);
                    num++;
                }

Ve bu, aşağıda bazı cevaplardan aldığım ve değiştirdiğim yöntem

public class ConsoleSpinner
    {
        int counter;

        public void Turn()
        {
            counter++;
            switch (counter % 4)
            {
                case 0: Console.Write("."); counter = 0; break;
                case 1: Console.Write(".."); break;
                case 2: Console.Write("..."); break;
                case 3: Console.Write("...."); break;
                case 4: Console.Write("\r"); break;
            }
            Thread.Sleep(100);
            Console.SetCursorPosition(23, Console.CursorTop);
        }
    }

0

İşte bir tane daha: D

class Program
{
    static void Main(string[] args)
    {
        Console.Write("Working... ");
        int spinIndex = 0;
        while (true)
        {
            // obfuscate FTW! Let's hope overflow is disabled or testers are impatient
            Console.Write("\b" + @"/-\|"[(spinIndex++) & 3]);
        }
    }
}

0

Bir satırı güncellemek istiyorsanız, ancak bilgiler bir satırda gösterilemeyecek kadar uzunsa, bazı yeni satırlara ihtiyaç duyabilir. Bu sorunla karşılaştım ve aşağıda bunu çözmenin bir yolu var.

public class DumpOutPutInforInSameLine
{

    //content show in how many lines
    int TotalLine = 0;

    //start cursor line
    int cursorTop = 0;

    // use to set  character number show in one line
    int OneLineCharNum = 75;

    public void DumpInformation(string content)
    {
        OutPutInSameLine(content);
        SetBackSpace();

    }
    static void backspace(int n)
    {
        for (var i = 0; i < n; ++i)
            Console.Write("\b \b");
    }

    public  void SetBackSpace()
    {

        if (TotalLine == 0)
        {
            backspace(OneLineCharNum);
        }
        else
        {
            TotalLine--;
            while (TotalLine >= 0)
            {
                backspace(OneLineCharNum);
                TotalLine--;
                if (TotalLine >= 0)
                {
                    Console.SetCursorPosition(OneLineCharNum, cursorTop + TotalLine);
                }
            }
        }

    }

    private void OutPutInSameLine(string content)
    {
        //Console.WriteLine(TotalNum);

        cursorTop = Console.CursorTop;

        TotalLine = content.Length / OneLineCharNum;

        if (content.Length % OneLineCharNum > 0)
        {
            TotalLine++;

        }

        if (TotalLine == 0)
        {
            Console.Write("{0}", content);

            return;

        }

        int i = 0;
        while (i < TotalLine)
        {
            int cNum = i * OneLineCharNum;
            if (i < TotalLine - 1)
            {
                Console.WriteLine("{0}", content.Substring(cNum, OneLineCharNum));
            }
            else
            {
                Console.Write("{0}", content.Substring(cNum, content.Length - cNum));
            }
            i++;

        }
    }

}
class Program
{
    static void Main(string[] args)
    {

        DumpOutPutInforInSameLine outPutInSameLine = new DumpOutPutInforInSameLine();

        outPutInSameLine.DumpInformation("");
        outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");


        outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");

        //need several lines
        outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");

        outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbb");

    }
}

0

vb.net de aynı çözümü arıyordum ve bunu buldum ve harika.

ancak @JohnOdom, bir öncekinin geçerli olandan daha büyük olması durumunda boşlukları işlemek için daha iyi bir yol önerdiğinden ..

vb.net bir işlev yapmak ve birisi yardım alabilir düşündüm ..

İşte benim kod:

Private Sub sPrintStatus(strTextToPrint As String, Optional boolIsNewLine As Boolean = False)
    REM intLastLength is declared as public variable on global scope like below
    REM intLastLength As Integer
    If boolIsNewLine = True Then
        intLastLength = 0
    End If
    If intLastLength > strTextToPrint.Length Then
        Console.Write(Convert.ToChar(13) & strTextToPrint.PadRight(strTextToPrint.Length + (intLastLength - strTextToPrint.Length), Convert.ToChar(" ")))
    Else
        Console.Write(Convert.ToChar(13) & strTextToPrint)
    End If
    intLastLength = strTextToPrint.Length
End Sub

Burada yerel bir statik değişkenin VB özelliğini kullanabilirsiniz: Static intLastLength As Integer.
Mark Hurd

0

Yazdığım çözümün hız için optimize edilip edilemeyeceğini görmek için bunu araştırıyordum. Sadece mevcut satırı güncellemekle kalmayıp geri sayım sayacım vardı. İşte benimle geldim. Birisi için yararlı olabilir

            int sleepTime = 5 * 60;    // 5 minutes

            for (int secondsRemaining = sleepTime; secondsRemaining > 0; secondsRemaining --)
            {
                double minutesPrecise = secondsRemaining / 60;
                double minutesRounded = Math.Round(minutesPrecise, 0);
                int seconds = Convert.ToInt32((minutesRounded * 60) - secondsRemaining);
                Console.Write($"\rProcess will resume in {minutesRounded}:{String.Format("{0:D2}", -seconds)} ");
                Thread.Sleep(1000);
            }
            Console.WriteLine("");

0

@ E.Lahu Solution esinlenerek, yüzde ile bir çubuk ilerleme uygulanması.

public class ConsoleSpinner
{
    private int _counter;

    public void Turn(Color color, int max, string prefix = "Completed", string symbol = "■",int position = 0)
    {
        Console.SetCursorPosition(0, position);
        Console.Write($"{prefix} {ComputeSpinner(_counter, max, symbol)}", color);
        _counter = _counter == max ? 0 : _counter + 1;
    }

    public string ComputeSpinner(int nmb, int max, string symbol)
    {
        var spinner = new StringBuilder();
        if (nmb == 0)
            return "\r ";

        spinner.Append($"[{nmb}%] [");
        for (var i = 0; i < max; i++)
        {
            spinner.Append(i < nmb ? symbol : ".");
        }

        spinner.Append("]");
        return spinner.ToString();
    }
}


public static void Main(string[] args)
    {
        var progressBar= new ConsoleSpinner();
        for (int i = 0; i < 1000; i++)
        {
            progressBar.Turn(Color.Aqua,100);
            Thread.Sleep(1000);
        }
    }

0

İşte s soosh ve 0xA3'ün cevapları. Döndürücüyü güncellerken konsolu kullanıcı mesajlarıyla güncelleyebilir ve ayrıca geçen bir zaman göstergesine sahiptir.

public class ConsoleSpiner : IDisposable
{
    private static readonly string INDICATOR = "/-\\|";
    private static readonly string MASK = "\r{0} {1:c} {2}";
    int counter;
    Timer timer;
    string message;

    public ConsoleSpiner() {
        counter = 0;
        timer = new Timer(200);
        timer.Elapsed += TimerTick;
    }

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

    public void Stop() {
        timer.Stop();
        counter = 0;
    }

    public string Message {
        get { return message; }
        set { message = value; }
    }

    private void TimerTick(object sender, ElapsedEventArgs e) {
        Turn();
    }

    private void Turn() {
        counter++;
        var elapsed = TimeSpan.FromMilliseconds(counter * 200);
        Console.Write(MASK, INDICATOR[counter % 4], elapsed, this.Message);
    }

    public void Dispose() {
        Stop();
        timer.Elapsed -= TimerTick;
        this.timer.Dispose();
    }
}

kullanım böyle bir şeydir:

class Program
{
    static void Main(string[] args)
    {
        using (var spinner = new ConsoleSpiner())
        {
            spinner.Start();
            spinner.Message = "About to do some heavy staff :-)"
            DoWork();
            spinner.Message = "Now processing other staff".
            OtherWork();
            spinner.Stop();
        }
        Console.WriteLine("COMPLETED!!!!!\nPress any key to exit.");

    }
}

-1

SetCursorPositionYöntemi diğer iki yöntem yoktur çoklu iş parçacığı senaryoda, çalışır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.