Válí se ti projekty v šuplíku? Dostaň je mezi lidi a získej cool tričko a body na profi IT kurzy v soutěži ITnetwork summer 2017!
Přidej si svou IT školu do profilu a najdi spolužáky zde na síti :)
Avatar
matesax
Redaktor
Avatar
matesax:22.1.2013 8:58

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:22.1.2013 22:32

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:23.1.2013 10:36

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):23.1.2013 10:57

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:23.1.2013 11:04

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:23.1.2013 11:46

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:23.1.2013 11:57

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:23.1.2013 12:05

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):23.1.2013 12:13

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:23.1.2013 12:17

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):23.1.2013 12:22

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:23.1.2013 12:25

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:23.1.2013 12:28

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:23.1.2013 13:26

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:23.1.2013 14:27

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:23.1.2013 14:36

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):23.1.2013 15:37

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.