Department of InformatiX
Microsoft .NET Micro Framework Tools & Resources

Včera jsem dal k dispozici ovládací prvek jménem ButtonTextBox, jenž vám umožňuje zadávat textový vstup. Ale jak už víte, tlačítko není klávesa...

IButtonTranslator

...takže musíme přeložit stisknutí klávesy do nějakých vstupních dat, ať už znaků, slov, čísel nebo čehokoliv. Jednou cestou by bylo nadefinovat stovky tlačítek a každému z nich přiřadit znak (například by se dala v enumu použít přímo hodnota znaku, pak by stačilo hodnoty převádět na znak, např. takto), ale to bychom asi nebyli velcí přátelé, jelikož byste nutili tlačítka být jako klávesy!

Ale většina z vás již jistě viděla zařízení s přiměřeně malým počtem kláves k zadávání všech znaků: mobilní telefon. Inspirován tímto řešením jsem se rozhodl udělat tento jednoduchý interface:

public interface IButtonTranslator { bool GetText(Button button, int pressedCount, out string text); bool GetNumber(Button button, out int number); }

S takovou třídu byste mohli vzít jakékoliv tlačítko, počet jeho stisknutí a na základě těchto informací získat písmeno, které představují. To je to, co by měla dělat metoda GetText, vracející true, pokud se jí to podařilo, nebo false pokud žádné odpovídající písmeno nenašla. Ve skutečnosti jsme v projektu používali out char, ale abychom drželi krok s Windows Presentation Foundation, změnil jsem to na string a upravil k tomu i text box (ve WPF totiž můžete jako vstup dostat celý text naráz, například z rozpoznávání řeči nebo rukopisu, případně z IME).

Metoda GetNumber je pak spíš na ulehčení života pro případ, že chcete pracovat výhradně s číselným vstupem (zmíněný text box ji třeba využívá při nastavení AllowNumbersOnly na true).

SequentialButtonTranslator

Zkusíme teď nějakou konkrétní implementaci. Obvykle se dává tlačítkům řada po sobě jdoucích čísel, jako třeba zde:

public enum Numpad { Tlačítko0 = 1, // nemůžeme začít na nule, protože ta odpovídá Button.None, což není platné tlačítko Tlačítko1, Tlačítko2, Tlačítko3, Tlačítko4, Tlačítko5, Tlačítko6, Tlačítko7, Tlačítko8, Tlačítko9 }

Tak proč toto pořadí nevyužít při převádění? Například metoda GetNumber by mohla vypadat velmi jednoduše:

public bool GetNumber(Button button, out int number) { number = (int)button - 1; return (number > 0) && (number < 10); }

A jak s písmeny? Ponecháme teď možnost celého řetězce stranou a zaměříme se pouze na znaky. Na telefonu reprezentuje každé tlačítko až čtyři písmena - znaky. Takže bychom je mohli spojit do řetězce a ty dát do pole. A aby jsme drželi pořadí, seřaďme je stejně jako tlačítka:

string[] CharacterData = new string[] { "+0", // znaky pro Tlačítko0 " .?!,1", // Tlačítko1 "abc2", // Tlačítko2 "def3", // Tlačítko3 "ghi4", // Tlačítko4 atd. ... }

GetText by pak mohla pracovat zhruba takto:

public bool GetText(Button button, int pressedCount, out string text) { try { text = CharacterData[(int)button - 1].Substring(pressedCount, 1); return true; } catch { return false; } }

To mimochodem není příliš dobrý styl psaní kódu, měli bychom spíše chybám zabránit předem než řídit try catchem chod programu (navíc vyvolání výjimky je časově nákladné). No a když přidáme konfigurovatelné první tlačítko (místo onoho - 1 koeficientu) a cyklické získávání znaků (tj. jakoby řetězec byl abc2abc2abc2abc2....), máme celou třídu SequentialButtonTranslator! Tato implementace je k dispozici buď v demo projektu text boxu nebo si ji můžete stáhnout přímo odsud.

Příklad s více tlačítky

Abyste viděli o něco komplikovanější použití než je v demu, zde je ukázka pro práci s více tlačítky:

SequentialButtonTranslator ButtonTranslator = new SequentialButtonTranslator(); ButtonTranslator.FirstCharacterButton = (Button)Numpad.Button0; // převedení našeho enumu na Button ButtonTranslator.CharacterData = new string[] { // na vlastní definici znaků můžete použít resources pro snadnou lokalizaci Resources.GetString(LetterData.Button0), // +-()0 Resources.GetString(LetterData.Button1), // .:,-1?!/@ Resources.GetString(LetterData.Button2), // abcáč2 Resources.GetString(LetterData.Button3), // defďéě3 Resources.GetString(LetterData.Button4), // ghií4 Resources.GetString(LetterData.Button5), // jkl5 Resources.GetString(LetterData.Button6), // mnoňó6 Resources.GetString(LetterData.Button7), // pqrsřš7 Resources.GetString(LetterData.Button8), // tuvťůú8 Resources.GetString(LetterData.Button9) // wxyzýž9 }; ButtonTranslator.FirstNumberButton = (Button)KeypadButton.NumPad0; ButtonTranslator.NumberData = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

A to je vše co potřebujete k používání SequentialButtonTranslatoru s tlačítky jako na telefonu. Pokud ji však chcete použít dohromady s ButtonTextBoxem, pozor na ovládání (např. šipka vlevo/vpravo je přiřazená k tlačítkům VK_LEFT/VK_RIGHT), vyberte svým tlačítkům nějakou řadu volných čísel.

Comments
Sign in using Live ID to be able to post comments.