Diskuze: Obě zarovnání

C# .NET .NET (C# a Visual Basic) Obě zarovnání American English version English version

Avatar
matesax
Redaktor
Avatar
matesax:

Dobrý den,
dělám UI pro konzoli - a jde to parádně. Nejprve jsem se zalekl práce s textem - jak to budu měřit, ale naštěstí se vše počítá podle znaků - nikoli podle px. Zarovnávám text doprostřed stránky - v určitém boxu. Takže každý text inteligentně rozseparuji - tak aby řádky byly rozděleny v mezerách a ne uprostřed slova. Nevyhnul jsem se cyklu a v něm jsem vypisoval rovnou každou řádku - tím jsem mohl pokaždé nastavit X pozici kurzoru. Takže jsem celý text zarovnal v X pozici. Jenže potřebuji zarovnat i v Y rovině. Když ale neznám výsledný text, musle jsem se vzdát vypisování rovnou v cyklu, a v cyklu každý řádek ukládám do stringu. Pak vypisuji víceřádkový string - tím jej mohu zarovnat v Y rovině, ale zase ne v X. Zarovná se jen první řádek - protože se na něj vztahuje nastavení kurozoru. Jak bych měl zarovnat i zbylé řádky? Děkuji.

 
Odpovědět 22.1.2013 8:58
Avatar
matesax
Redaktor
Avatar
matesax:

Není to ještě ideální, ale řešení již mám:

using System;

namespace ConsoleExtra.Controls
{
        public enum Align
        {
                Left = 0,
                Center = 1,
                Right = 2
        }

        public class MessageBox
        {
                private static string Equally(string text, int lineLength, string whiteSpaceLine, Align textAlign)
                {
                        return String.Format("{0," + lineLength + "}", text + whiteSpaceLine.Substring(text.Length + ((int)(0.5F * (float)textAlign * (lineLength - text.Length)))));
                }

                public static void Show(string text)
                {
                        Show(text, " █ ", Align.Center);
                }

                public static void Show(string text, Align textAlign)
                {
                        Show(text, " █ ", textAlign);
                }

                private static void WriteLine(int tab, string text)
                {
                        Console.CursorLeft = tab;
                        Console.WriteLine(text);
                }

                public static void Show(string text, string border, Align textAlign)
                {
                    int length,
                                fullLength,
                                margin = Console.WindowWidth - 20,
                                tab = (Console.WindowWidth - (margin + 2 * border.Length)) / 2;

                        string whiteSpaceLine = new string(' ', margin),
                                startLine = border + Equally(" ", margin, whiteSpaceLine, textAlign) + border,
                                endLine;

                        fullLength = startLine.Length;

                        Action writeText = delegate() { WriteLine(tab, startLine); };

                        for (int start = 0; start < text.Length; start += length + 1)
                    {
                                try
                                {
                                        length = text.Substring(start, margin).LastIndexOf(' ');

                                if (length == -1)
                                    length = margin;
                                }
                                catch
                                {
                                        length = text.Length - start;
                                }

                                string line = border + Equally(text.Substring(start, length), margin, whiteSpaceLine, textAlign) + border;

                                fullLength += line.Length;

                                writeText += delegate() { WriteLine(tab, line); };
                    }

                        Console.ForegroundColor = ConsoleColor.Black;
                        Console.BackgroundColor = ConsoleColor.Gray;

                        endLine = border + Equally(" ", margin, whiteSpaceLine, textAlign) + border;

                        fullLength += endLine.Length;

                        writeText += delegate() { WriteLine(tab, endLine); };

                        Console.CursorTop = (Console.WindowHeight -  fullLength / (margin + 2 * border.Length)) / 2;

                        writeText();

                        Console.ResetColor();
                }
        }
}
Editováno 22.1.2013 22:34
 
Nahoru Odpovědět 22.1.2013 22:32
Avatar
lcet.m
Člen
Avatar
lcet.m:

Už jsem ti to psal někde jinde - nespojuj stringy pomocí +. Podívej se na StringBuilder http://msdn.microsoft.com/…builder.aspx a na string.Format http://msdn.microsoft.com/….format.aspx (ten koukám někdy používáš, nechápu teda proč ne vždycky?)

Dál, když někde používáš stringové konstanty (" █ ", " " ...), měl bys je mít taky jako konstanty nadeklarované, jinak úplně zbytečně děláš pořád nové instance Stringu (možná to zoptimalizuje kompiler, ale nespoléhal bych na to).

Jako poslední bych zase doporučil schovat si "výkonný" kód za interface a ten tvůj MessageBox (imho ne moc dobře zvolené jméno třídy, která píše do konzole, ale co už) tahat přes nějakou factory. Budeš tím mít šanci v budoucnu implementovat nějaká lepší řešení, což by dle mého mělo přijít :)

 
Nahoru Odpovědět 23.1.2013 10:36
Avatar
Odpovídá na lcet.m
Luboš Běhounek (Satik):

Dokud nespojuje více než cca 5 stringů, tak ať klidně používá +, rychlostně to vychází nastejno, až u většího množství se začne projevovat výhoda stringbuilderu.

Nahoru Odpovědět 23.1.2013 10:57
:)
Avatar
matesax
Redaktor
Avatar
Odpovídá na lcet.m
matesax:

Border není konstanta - jelikož každý box může mít svůj okraj - jen dělám defaultní hodnoty, když uživateli bude záležet jen na některých faktech. StringBulider/For­mat jsou jen hezky zabalené objekty - když nepotřebuji nic speciálního, co již za mne tyto objekty vyřešily, nevidím důvod jejich používání.

Zbytečné inicializace a jiné konstrukce byly již dávno smazány - jak jsem psal - teprve jsem dořešil onen problém - ale bylo již hodne pozdě, takže dál jsem pokračval ráno. Celé jsem to pořádně pročistil.

OOP pojmenovávání je geniálni v tom, že pro každý objekt budou platit stejné názvy... Viz. funkce Text pro všechny Fomrs.Control. Chci dělit - cokoliv - bude to vždy Split, chci to a to - bude to vždy to a to... Rozdíl bude jen v namespace/třídě...

EDIT:

Ano - kdybych měl skutečně co stavět - rozsáhlý text, řeším to jinak - ale tady skoro o nic nejde...

Editováno 23.1.2013 11:07
 
Nahoru Odpovědět 23.1.2013 11:04
Avatar
Kit
Redaktor
Avatar
Odpovídá na lcet.m
Kit:

Na těch pár stringů je to fuk, optimalizace je v daném případě zbytečná.

Nahoru Odpovědět 23.1.2013 11:46
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
lcet.m
Člen
Avatar
lcet.m:

Počkat, měl jsem dojem, že to má být vypisování obsahu HTML dokumentů do konzole. Tak jestli zrovna to je "pár stringů"... Můžu se optat, kde jsi vzal těch "cca 5 stringů"? Netvrdím, že to není pravda, ale zajímalo by mě, jestli to je jen odhad, nebo co?

 
Nahoru Odpovědět 23.1.2013 11:57
Avatar
Kit
Redaktor
Avatar
Odpovídá na lcet.m
Kit:

Dokud to nejsou megabajty dat, tak je to fakt jedno. Dokumenty HTML bývají poměrně krátké.

Nahoru Odpovědět 23.1.2013 12:05
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Odpovídá na lcet.m
Luboš Běhounek (Satik):

Zkoušel jsem spojit 200 jednoznakových Stringů a tam plus trvalo dvojnásobek času než stringbuilder.

Teď jsem zkoušel "realističtější" obsahy stringů (a menší počet spojování) a vyhrává jednoznačně plus:

private void test()
{
      int words = 1000000;

      String[] strings = new String[5] { "Ahoj", "", "Úžasně žluťoučký kůň pěl ďábelské ódy", "x", "Nějaký text" };
      String testString;

      // Plus
      DateTime now = DateTime.Now;
      testString="";
      for (int i = 0; i < words; i++)
      {
          testString = strings[0] + strings[1] + strings[2] + strings[3] + strings[4];
      }

      DateTime then = DateTime.Now;
      this.Text = "Plus: " + (then - now).TotalMilliseconds + "ms";

      // Builder
      now = DateTime.Now;
      testString="";
      for (int i = 0; i < words; i++)
      {
          StringBuilder sb = new StringBuilder();
          sb.Append(strings[0]);
          sb.Append(strings[1]);
          sb.Append(strings[2]);
          sb.Append(strings[3]);
          sb.Append(strings[4]);
          testString = sb.ToString();
      }

      then = DateTime.Now;
      this.Text += ", Builder: " + (then - now).TotalMilliseconds + "ms";

      // Format
      now = DateTime.Now;
      testString = "";
      for (int i = 0; i < words; i++)
      {
          testString = String.Format("{0}{1}{2}{3}{4}", strings[0], strings[1], strings[2], strings[3], strings[4]);
      }

      then = DateTime.Now;
      this.Text += ", Format: " + (then - now).TotalMilliseconds + "ms";
  }

Plus: 187,0107ms
Builder: 301,0172ms
Format: 433,0248m

Editováno 23.1.2013 12:14
Nahoru Odpovědět 23.1.2013 12:13
:)
Avatar
lcet.m
Člen
Avatar
lcet.m:

A co string.Concat? :) nicméně já jsem si to mezitím taky zkusil a vyšlo mi to cca podobně. Tak asi joo, no...

 
Nahoru Odpovědět 23.1.2013 12:17
Avatar
Odpovídá na lcet.m
Luboš Běhounek (Satik):

Concat mi teď vyšel stejně rychlý jako sčítání pomocí plusů :)

Nahoru Odpovědět 23.1.2013 12:22
:)
Avatar
lcet.m
Člen
Avatar
lcet.m:

Dobře dobře dobře, střihám si kšandy :)

 
Nahoru Odpovědět 23.1.2013 12:25
Avatar
Kit
Redaktor
Avatar
Odpovídá na lcet.m
Kit:

cite: "The plus operator compiles into string.Concat."

Nahoru Odpovědět 23.1.2013 12:28
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
lcet.m
Člen
Avatar
lcet.m:

Aaha, aha! Tak to jsem netušil. Vida jak je ten .NET chytrej, já to říkám pořád :) Díky za rozšíření obzorů.

 
Nahoru Odpovědět 23.1.2013 13:26
Avatar
matesax
Redaktor
Avatar
matesax:

Nejlepší na tom je jak mne tu napadáte (celkově), ale sami jste s řešením nepřišli - já ano a jak se ukazuje, nebyl důvod tu diskutovat - a jak jsem psal - to jsem to navíc osekal, přehodil do ještě obecnějšího objektu a zbavil se dalšího náročného elementu (deklaruji jen jednoho delegáta, kterému definuji příkazy souhrnně) - nyní je tam to nejnáročnější jen ten cyklus.

 
Nahoru Odpovědět 23.1.2013 14:27
Avatar
lcet.m
Člen
Avatar
Odpovídá na matesax
lcet.m:

Ale nebreč, tak jsem holt neměl pravdu, Kit mi ukázal proč a je to. Nechci tady exhumovat jedno už skoro zapomenuté vlákno, kdy se ti stalo totéž, ale tak šťastně to nedopadlo :P

EDIT: teda spíš Satik, pardon

Editováno 23.1.2013 14:37
 
Nahoru Odpovědět 23.1.2013 14:36
Avatar
Odpovídá na matesax
Luboš Běhounek (Satik):

Na rozdíl od tebe tu (snad) všichni umíme přiznat svou chybu :)

Nahoru Odpovědět  +1 23.1.2013 15:37
:)
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 17 zpráv z 17.