Některé možností pro snadnou tvorbu úlohy
Transkript
Některé možností pro snadnou tvorbu úlohy
Některé možností pro snadnou tvorbu úlohy Petr Novák ([email protected]) Verze 1.01.00 (30.03.2015) Obsah 1 Základní plocha úlohy ...................................................................................................................... 1 1.1 Grid .......................................................................................................................................... 1 1.2 Canvas...................................................................................................................................... 3 1.3 Společné .................................................................................................................................. 5 1.3.1 Velikost podkladu ............................................................................................................ 5 1.3.2 Obrázek jako podklad ...................................................................................................... 5 1.4 Speciální efekty........................................................................................................................ 6 1.4.1 Canvas + Grid ................................................................................................................... 6 2 Text .................................................................................................................................................. 6 3 Další celkem užitečné poznámky ..................................................................................................... 7 4 Poznámky ........................................................................................................................................ 7 1 Základní plocha úlohy Základní plocha úlohy může být tvořena v podstatě libovolným grafickým prvkem pocházejícím od „Systém.Windows.FrameworkElement“. Zde jsou uvedeny některé nejčastěji používané grafické prvky pro základní plochu úlohy a příkladu jejich využití. 1.1 Grid Vložení vlastního grafického prvku „Grid“ do základního „Grid“ vytvářeného frameworkem je následující: // použití „Grid“ (mřížka) jako základní plochy úlohy taskGUIItems[…] = new TaskGUIItem() { number = …, guiItem = EnumGUIItem.Grid }; Do vlastního vloženého „Grid“ lze přidat libovolný počet řádků a sloupců pomocí: Grid grid = taskGUIItems[EnumNumber.First]; // vymazaní všech existujících řádků grid.RowDefinitions.Clear(); // tolik řádků kolik je potřeba for (int i = 0; i < rows_number; i++) { // do seznamu řádků se přidá nový / další řádek grid.RowDefinitions.Add( // vložení jednoho nového řádku new RowDefinition() // jeho šířka je v podstatě 10% (vysvětleno dále) { Height = new GridLength(10, GridUnitType.Star) }); } // vymazaní všech existujících sloupců grid.ColumnDefinitions.Clear(); // tolik sloupců kolik je potřeba for (int i = 0; i < columns_number; i++) { // do seznamu sloupců se přidá nový / další sloupec grid.ColumnDefinitions.Add( // vložení jednoho nového sloupce new ColumnDefinition() // jeho šířka je v podstatě 10% (vysvětleno dále) { Width = new GridLength(10, GridUnitType.Star) }); } Při zadání šířky pro řádek i sloupec se používá (mimo jiné): // šířka je (přesně) 10 obrazových bodů GridLength(10) // šířka je minimálně 10 obrazových bodů, ale roztáhne se poměrově k celku GridLength(10, GridUnitType.Star) Pokud je zadáno samotné číslo bez „GridUnitType.Star“, tak jde o počet obrazových bodů, jak bude řádek, nebo sloupec široký bez ohledu na celkovou velikost / plochu „Grid“ (i toho podkladového z framework). Je-li použito současně „GridUnitType.Star“, tak dřívější zadané číslo označuje minimální velikost a jakýsi poměr roztažení tohoto řádku / sloupce pokud je šířka / výška „Grid“ vetší než součet základních velikostí všech vytvořených řádků / sloupců. Při použití „GridUnitType.Star“ je vhodné čísla považovat, pro jednoduchost, za procenta a to následovně: // tento řádek při roztahování new RowDefinition() { Height = // tento řádek při roztahování new RowDefinition() { Height = // tento řádek při roztahování new RowDefinition() { Height = bude zabírat 20% z new GridLength(20, bude zabírat 20% z new GridLength(20, bude zabírat 60% z new GridLength(60, celkové výšky „Grid“ GridUnitType.Star) }); celkové výšky „Grid“ GridUnitType.Star) }); celkové výšky „Grid“ GridUnitType.Star) }); Celkově tedy 100% pro snazší orientaci. Při roztahování „Grid“ příslušným směrem se boudou vytvořená řádky / sloupce rovněž automaticky roztahovat v zadaném procentuálním poměru. Vložit jakýkoli grafický prvek do vlastního „Grid“ lze následovně: // prvek přidávaný do „Grid“ Image img = new Image(); // jeho přidání pouze pokud již v „Grid“ není if (!g.Children.Contains(img)) g.Children.Add(img); // nastavení umístění na tento sloupec (čísla jsou 0, 1, 2, …) Grid.SetColumn(img, columnNumber); // nastavení umístění na tento řádek (čísla jsou 0, 1, 2, …) Grid.SetRow(img, rowNumber); Pokud je potřeba umístit vkládaný prvek přes několik řádků (na výšku) nebo několik sloupců (na šířku) od zadaného počátečního, lze použít následující: // prvek bude vložen přes 5 sloupců, bude tedy zabírat, 5 sloupců (na šířku) Grid.SetColumnSpan(img, 6); // prvek bude vložek přes 6 řádků, bude tedy zabírat 6 řádků (na výšku) Grid.SetRowSpan(img, 6); Poznámky: - Pro kontrolu vytvoření požadovaných řádků / sloupců lze snadno nastavit zobrazení jejich kontrolních obrysů pomocí grid.ShowGridLines = true. - Pro kontrolu skutečné velikosti vytvořeného „Grid“ je vhodné nastavit pro něho nějaké pozadí, například grid.Background = new SolidColorBrush(Colors.LightGray). Zejména při ladění úlohy. 1.2 Canvas Vložení vlastního grafického prvku „Canvas“ do základního „Grid“ vytvářeného frameworkem je následující: // použití „Grid“ (mřížka) jako základní plochy úlohy taskGUIItems[…] = new TaskGUIItem() { number = …, guiItem = EnumGUIItem.Canvas }; Na „Canvas“ lze přidat téměř jakýkoli grafický prvek, například: // vytvořená grafického prvku „Image“ Image img = new Image(); // jeho vložení na „Canvas“ taskGUIItems[EnumNumber.First].canvas.Children.Add(frmElmSet); // horizontální souřadnice středu (ve skutečnosti se nastavuje levý-horní roh) Canvas.SetLeft(img, positionX - img.Width / 2); // vertikální souřadnice středu (ve skutečnosti se nastavuje levý-horní roh) Canvas.SetTop(img, positionY - img.Height / 2); Často může být požadavek na přesun grafických prvků po „Canvas“. Toto lze uskutečnit následovně (využití položky „Tag“ je popsáno dále): // událost při stisku tlačítka myši na „Image“ img.MouseLeftButtonDown += (sender, e) => { // událost je od „Image“ Image imgTemp = (Image)sender; // vyzvednutí informací o tomto „Image“ ClassMyInfo classMyInfo = (ClassMyInfo)imgTemp.Tag; // tímto „Image“ se nyní pohybuje classMyInfo.moveYes = true; // uložení místa uchycení tohoto „Image“ (pro hezký přesun, třeba za jeho roh) classMyInfo.moveOrig.X = // pozice kurzoru na „Canvas“ v ose X (double)e.GetPosition(taskGUIItems[EnumNumber.First].canvas).X – // odečtení levého rohu umístění „Image“ na „Canvas“ Canvas.GetLeft(image); // obdobně pro osu Y classMyInfo.moveOrig.Y = (double)e.GetPosition(taskGUIItems[EnumNumber.First].canvas).Y – Canvas.GetTop(image); // myš bude svázána s tímto prvkem po dobu jeho pohybu (velmi vhodné) image.CaptureMouse(); }; // událost při posunu „Image“ img.MouseMove += (sender, e) => { // událost je od „Image“ Image imgTemp = (Image)sender; // vyzvednutí informací o tomto „Image“ ClassMyInfo classMyInfo = (ClassMyInfo)imgTemp.Tag; // pouze pokud se tímto „Image“ (již) pohybuje if (classMyInfo.moveYes == true) { // nastavení jeho nové pozice v ose X (podle počátečního uchopení) Canvas.SetLeft(image, // aktuální pozice myši na „Canvas“ (double)e.GetPosition(taskGUIItems[EnumNumber.First].canvas).X – // odečtení ofsetu při jeho uchopení classMyInfo.moveOrig.X); // obdobně pro osu Y Canvas.SetTop(image, (double)e.GetPosition(taskGUIItems[EnumNumber.First].canvas).Y – classMyInfo.moveOrig.Y); } }; // událost při uvolnění tlačítka myši na „Image“ img.MouseLeftButtonUp += (sender, e) => { // událost je od „Image“ Image imgTemp = (Image)sender; // vyzvednutí informací o tomto „Image“ ClassMyInfo classMyInfo = (ClassMyInfo)imgTemp.Tag; // tímto „Image“ se již nepohybuje classMyInfo.moveYes = false; // myš již není vázána na tento „Image“ frmElmUserTemp.ReleaseMouseCapture(); }; Třída „ClassMyInfo“ může být pro tuto ukázku následující: public class Connection { // příznak zda se objektem právě pohybuje public bool moveYes = false; // pozice uchopení objektu před jeho pohybem public Point moveOrig = new Point(); // další vlastní položky // … } 1.3 Společné … 1.3.1 Velikost podkladu U vlastního grafického prvku lze nastavit jeho skutečnou velikost. Nejjednodušší je jeho roztažení na maximální velikost podle políčka v podkladovém „Grid“ z framework pomocí: // roztažení na maximální velikost podle podkladového políčka z „Grid“ canvas.HorizontalAlignment = HorizontalAlignment.Stretch; canvas.VerticalAlignment = VerticalAlignment.Stretch; Případně vystředit na střed políčka v podkladovém „Grid“ z framework pomocí: // vystředění podle podkladového políčka z „Grid“ canvas.HorizontalAlignment = HorizontalAlignment.Center; canvas.VerticalAlignment = VerticalAlignment.Center; Pokud je požadavek na nastavení nějaké přesnější velikosti vloženého prvku, například pro formát použitého podkladového obrázku, lze programový kód v metodě „TaskOnSizeChange()“ vytvořit takto: // aby byl zachován poměr stran u obrázku použitého pro 'Background' // měřítko podle nejmenší velikost v některém směru (šířka / výška) double scale = Math.Min( // maximální možné měřítko pro šířku TaskGridGlobal.ColumnDefinitions[0].ActualWidth / backgroundImage.RowWidth(), // maximální možné měřítko pro výšku TaskGridGlobal.RowDefinitions[0].ActualHeight / backgroundImage.RowHeight()); // nastaveni velikosti 'Canvas' podle menšího zjištěného měřítka taskGUIItems[EnumNumber.First].canvas.Width = backgroundImage.RowWidth() * scale; taskGUIItems[EnumNumber.First].canvas.Height = backgroundImage.RowHeight() * scale; 1.3.2 Obrázek jako podklad Jakýkoli obrázek lze použít jako podklad například pro „Canvas“, „Grid“ a další. Tvorba je následující: // načtení obrázku jako binární pole (byte[]) byte[] imageBytes = await iFramework.ServerAppDataFiles.LoadFilesAsBinary(path, name); // vytvoření „Image“ například pro vložení do „Grid“ nebo „Canvas“ Image image = new Image() { // pomocná metoda poskytne binární data pro vytvoření „Image“ Source = XUtils.Graphics.ImageCommon.BitmapImageFromBytes(imageBytes) }; // obrázek bude vložen jako pozadí pro … grid / canvas.Background = // pozadí bude formou štětce typu „ImageBrush“ new ImageBrush() { // štětec bude tvořen tímto obrázkem ImageSource = image, // roztažení obrázku na velikost podkladu, zachování poměru stran Stretch = Stretch.Uniform }; 1.4 Speciální efekty … 1.4.1 Canvas + Grid Pokud bychom chtěli umístit nějaké grafické komponenty defaultně do mřížky („Grid“), ale přitom umožnit s nimi plynule pohybovat mezi jeho políčky pomocí myší lze postupovat následovně: - - Do základového políčka frameworku vložíme „Canvas“. Velikost nastavíme podle potřeby. Na „Canvas“ vložíme (ještě) „Grid“ o zcela stejné velikosti jako dříve vložený „Canvas“. „Grid“ by měl mít průsvitné pozadí („Background = Transparent“). V „Grid“ vytvoříme tolik políček, kolik potřebujeme pro vložení defaultně umístěných grafických prvků (obrázky, čtverce, …). Tedy vložíme a nastavíme jejich pozice v „Grid“. Pokud se uchopí grafický prvek myší (stisk tlačítka myši), tak jej odejmeme z „Grid“ (z políčka), vypočteme jeho aktuální souřadnici levého horního rohu podle pozice políčka, kde se nacházel v „Grid“ a vložíme jej na „Canvas“ na tuto souřadnici (na bodové souřadnice). Při pohybu myši (držení a přesunu grafického prvku) používáme pouze bodové pozice z „Canvas“. Pokud je grafický prvek upuštěn (uvolnění tlačítka myši), tak jej odebereme z „Canvas“ (bodové souřadnice) a vložíme jej zpět na „Grid“ (políčka) a to do políčka, jemuž je poslední známá souřadnice z „Canvas“ nejblíže. Takto zle zcela snadno vytvořit velmi efektivní přesun grafických prvků mezi políčky v „Grid“ pomocí přetažení myší. 2 Text Při zobrazení textu je vhodné znát několik velmi užitečných zásad. Pokud chce, aby se text stále zobrazovat co největší možná a to sám od sebe postupujeme takto (možná to jde i jednodušeji): // „Border“ umožňuje nastavit pozadí pod text Border border = new Border() { // nastavení pozadí pod text Background = XUtils.Graphics.SolidColorBrushes.GetByColor(Colors.LightGray), // do „Border“ je vložen „Viewbox“, který vše v sobě roztáhne na max. velikost Child = new Viewbox() { // ve „Viewbox“ je vložen „TextBlock“ pro snadné zobrazení textu Child = new TextBlock() { // zobrazovaný text Text = „…“, // text bude tučný (dobře viditelný) FontWeight = FontWeights.Bold, // text bude zarovnaný na střed v „TextBlock“ TextAlignment = TextAlignment.Center, // text bude touto barvou Foreground = XUtils.Graphics.Brushes.GetSolidColorBrush(Colors.Black) } } }; V tomto případě se není nutno vůbec starat o velikost fontu v „TextBlock“. Ten obsažený text vždy zvětší na takové největší font, aby byl „TextBlock“ zadaným texten zcela vyplněn. 3 Další celkem užitečné poznámky Každý grafický prvek obsahuje položky zvanou „Tag“ do které lze vložit svoji zcela vlastní hodnotu. Význam této položky je neocenitelný, pokud programátor pochopí její využití. Například vytvoříme grafický prvek „Image“, „Rectangle“, „Line“, ... Současně vytvoříme nějakou svoji třídu obsahující informace o tomto grafickém prvku s názvem „ClassMyInfo“. Při tvorbě grafického prvku (a jeho umístění na „Canvas“) do jeho položky „Tag“ vložíme obsah naší třídy „ClassMyInfo“: // vytvoření „Image“ a vložení do jeho položky „Tag“ odkaz na vlastní třídu Image img = new Image() { Tag = new ClassMyInfo(…) } Poté při stisku tlačítka na tomto grafickém prvku velmi snadno z položky „Tag“ vyzvedneme všechny potřebné informace: // událost při kliku na „Image“ img.MouseLeftButtonDown += (sender, e) => { // parametr „Sender“ přetypovat na „Image“ (víme, že jde o „Image“) Image imgTemp = (Image)sender; // z „Image“, z jeho položky „Tag“ vyzvedneme odkaz na naší třídu ClassMyInfi classMyInfo = (ClassMyInfo)imgTemp.Tag; // zpracování … Není tedy vůbec nutno vytvářet nějaké složité slovníky, v nich uchovávat ukazatele na spoustu grafických prvků a při kliku na nějaký prvek tento slovník procházet pro zjištění na který grafický prvek byl ve skutečnosti klik vykonán. Stačí každému grafickému prvku do položky „Tag“ vložit odkaz na třídu nesoucí jeho informace, tu poté vyzvednout a podle toto s grafickým prvkem zacházet. 4 Poznámky - Téměř každý grafický prvek obsahuje položky „Padding“ a „Margin“. První představuje prázdný okraj vně prvku a druhý prázdný kraj uvnitř prvku (pro vložení dalšího prvku do jeho - vnitřku). Lze zadat pouze jednu stejnou hodnotu pro všechny čtyři strany „Padding = new Thickness(šířka)“ nebo pro každou stranu zvlášť „Padding = new Thickness(levá, horní, pravá, dolní)“. Pokud u některého grafického prvku nelze nastavit „Border…“ (kraj) nebo „Background…“ (pozadí), protože je prostě neobsahují, tak lze původní grafický prvek umístiti do „Border“ a v něm tyto vlastnosti nastavit podle potřeby. Grafický prvek „Border“ umožňuje vytvořit nejen libovolně barevné a široké okraje, ale rovněž i zaoblené.