====== Další druhy panelů ====== ===== Základní třída pro pohyblivé panely ===== V programu z minulého týdnu jsem upravil třídu **Area** tak, \\ aby zadanému panelu přidala kód pro pohyb pomocí myši Třídy pro jednotlivé panely jsou ozdvozené ze třídy **UserControl** \\ ( Když byly odvozené ze třídy //Area//, \\ která někdy ještě nemusela být přeložena, \\ tak //VisualStudio// nemohlo zobrazit panel v "design" režimu. ) Nyní třídy pro jednotlivé panely v konstruktoru zavolají ** new Area (this); ** \\ třída //Area// připojí své metody jako reakci na pohyb myši nad příslušným panelem. Pohyb panelu pomocí levého tlačítka myši \\ a zvětšování pomocí prostředního tlačítka \\ u některých panelů funguje jen na barevném okraji panelu, \\ uvnitř je umístěn jiný grafický prvek jako např. takulka s daty. Samotná třída //Area// není odvozena z vizuálního prvku. public class Area { private Control control; public Area (Control control0) { control = control0; control.MouseDown += Area_MouseDown; control.MouseMove += Area_MouseMove; control.MouseUp += Area_MouseUp; } private int X0, Y0; private bool press = false; private void Area_MouseDown (object sender, MouseEventArgs e) { X0 = e.X; Y0 = e.Y; press = true; } private void Area_MouseMove (object sender, MouseEventArgs e) { if (press) { if (e.Button == MouseButtons.Left) { control.Left += e.X - X0; control.Top += e.Y - Y0; } else if (e.Button == MouseButtons.Middle) { control.Width += e.X - X0; control.Height += e.Y - Y0; X0 = e.X; Y0 = e.Y; } } } private void Area_MouseUp (object sender, MouseEventArgs e) { press = false; } } [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/tree/master/Diagram|gitlab]] ===== Panel s obrázky ===== Původní kód z kapitoly o pohyblivých panelech jsem přemístil do třídy **ImageArea** odvozené ze třídy **UserControl**. public partial class ImageArea : UserControl { public ImageArea (string path = "") { InitializeComponent (); new Area (this); if (path != "") BackgroundImage = new Bitmap (path); } private void colorMenuItem_Click (object sender, EventArgs e) { colorDialog.Color = this.BackColor; if (colorDialog.ShowDialog () == DialogResult.OK) BackColor = colorDialog.Color; } private void imageMenuItem_Click (object sender, EventArgs e) { if (openDialog.ShowDialog () == DialogResult.OK) { BackgroundImage = new Bitmap (openDialog.FileName); } } private void borderMenuItem_Click (object sender, EventArgs e) { borderMenuItem.Checked = ! borderMenuItem.Checked; if (borderMenuItem.Checked) BorderStyle = BorderStyle.FixedSingle; else BorderStyle = BorderStyle.None; } private void stretchMenuItem_Click (object sender, EventArgs e) { stretchMenuItem.Checked = ! stretchMenuItem.Checked; if (stretchMenuItem.Checked) BackgroundImageLayout = ImageLayout.Stretch; else BackgroundImageLayout = ImageLayout.None; } } ===== HTML panel ===== Třída **HtmlArea** obsahuje komponentu typu **WebBrowser** umístěnou na celé ploše panelu. Konstruktor má jako parametr cestu k //html// souboru, který v panelu zobrazí. \\ //WebBrowser// cestu k souboru dostane jak typ **Uri**, kde uvedeme //file:// a zpětná lomítka nahradíme obyčejnými lomítky. Panelu ještě přídáme vlastnost **Browser**, která dovoluje pouze číst odkaz na komponentu //webBrowser// a nedovoluje zápis. \\ Vlastnost se objeví v tabulce **PropertyGrid** mezi vlastnostmi panelu v oddělení //Data// public partial class HtmlArea : UserControl { public HtmlArea (string path) { InitializeComponent (); new Area (this); webBrowser.Url = new Uri ("file:///" + path.Replace ('\\', '/').Replace("//", "/")); } [ Category ("Data") ] public WebBrowser Browser { get => webBrowser; } } {{diagram_html.png}} ===== Textový panel ===== Podobně třída **TextArea** obsahuje **TextBox** zobrazujícíobsah textového souboru. V konstruktoru funkce **File.ReadAllText** přečte obsah celého souboru a výsledkem je jeden řetězec znaků. Vlastnost **TextBox** poskytuje odkaz na textovou komponentu, jen je funkce **get** zapsána trochu jinak, než v předchozím odstavci. public partial class TextArea : UserControl { public TextArea (string path) { InitializeComponent (); new Area (this); textBox.Text = File.ReadAllText (path); } [Category ("Data")] public TextBox Editor { get { return textBox; } } } ===== Tabulka s daty připomínající spreadsheet ===== V tomto panelu se o zobrazení postará komponenta **grid** typu **DataGridView** V konstruktoru se pokusíme přečíst soubor obsthující data oddělená čárkami **(.csv)** * Funkce **File.ReadAllLines** načte celý textový soubor a uloží ho do pole řetězců znaků **lines** * Nejprve musíme najít nejdelší řádku a určit maximální počet sloupců * Do komponenty //grid// snadno přidáváme řádky jako seznam řetězců **List < string >** * Připravíme si seznam **complete**, který bude obsahovat seznamy tvořící jednotlivé řádky **List < List < string > >** * Proměnná //complete// je jen ukazatel inicializovaný na //null//, celý seznam seznamů musíme ještě vytvořit List< List < string > > complete = new List < List < string > > (); * Projdeme jednotlivé řádky, které máme v poli //lines// * Pro každou řádku vytvoříme zatím prázdný seznam **data**, do kterého budeme přidávat jednotlivé sloupce * Funkce **line.Split (',')** rozdělí řádku, v místech kde jsou čárky, na jednotlivé textové položky **item** * Položky //item// přidáme do seznamu //data// * Do proměnné **cnt** uložíme pocět položek v seznamu **data.Count** * V proměnné **columns** skladujeme dosud největší počet sloupců * Seznam //data// představující jednu řádku přidáme do seznamu seznamů //complete// foreach (string line in lines) { List data = new List (); foreach (string item in line.Split (',')) { data.Add (item); } int cnt = data.Count; if (cnt > columns) columns = cnt; complete.Add (data); } * Komponentě **grid** typu **GridView** nastavíme počet sloupců * A potom můžeme přidávat jednotlivé řádky, které metodou **ToArray** převedeme na pole řetězců grid.ColumnCount = columns; foreach (var data in complete) grid.Rows.Add (data.ToArray()); Celý panel zobrazující tabulku dat public TableArea (string path) { InitializeComponent (); string [] lines = File.ReadAllLines (path); int columns = 0; List< List < string > > complete = new List < List < string > > (); foreach (string line in lines) { List data = new List (); foreach (string item in line.Split (',')) { data.Add (item); } int cnt = data.Count; if (cnt > columns) columns = cnt; complete.Add (data); } grid.ColumnCount = columns; foreach (var data in complete) grid.Rows.Add (data.ToArray()); } [ Category ("Data") ] public DataGridView Table { get => grid; } } ===== Panel s grafy ==== Grafy zobrazí komponenta **chart** typu **Chart** Na webu jsem nalezl krátký příklad jak zobrazit sloupcový graf se třemi hodnotami // http://csharpexamples.com/c-chart-control-example/ chart.Series.Clear (); chart.Titles.Add (""); Series data = chart.Series.Add ("first"); data.Points.Add (10); data = chart.Series.Add ("second"); data.Points.Add (20); data = chart.Series.Add ("third"); data.Points.Add (30); Nebo kruhový diagram // https://stackoverflow.com/questions/34104484/how-to-build-a-pie-chart-based-on-int-values chart.Series.Clear (); Series data = chart.Series.Add (""); data.ChartType = SeriesChartType.Pie; data.Points.AddXY ("first", 10); data.Points.AddXY ("second", 20); data.Points.AddXY ("third", 30); * Graf vymažeme a do proměnné **data** dáme odkaz na pomocný objekt s daty * Funkce **File.ReadAllLines** načte do pole **lines** jednotlivé řádky * Řádky rozdělíme na položky oddělené čárkami, pole položek se jmenuje **items** * Poznamenáme si počet položet na řádce do proměnné **cnt** * Do proměnné **value** uložíme první položku, pokud existuje * Do **name** uložíme druhou položku, obě jako řetězec znaků * Funkce **int.TryParse** převede řetěrec znaků na celé číslo a uloží do proměnné **number**, pokud převédst lze * Jméno a hodnotu přidáme do grafu **data.Points.AddXY (name, number);** public partial class ChartArea : UserControl { public ChartArea (string path) { InitializeComponent (); new Area (this); chart.Series.Clear (); Series data = chart.Series.Add (""); string[] lines = File.ReadAllLines (path); foreach (string line in lines) { string [] items = line.Split (','); int cnt = items.Length; string value = (cnt >= 1) ? items[0] : ""; string name = (cnt >= 2) ? items[1] : ""; int number = 0; int.TryParse (value, out number); data.Points.AddXY (name, number); } } [ Category ("Data")] public Chart Chart { get => chart; } } {{diagram_chart.png}} [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/tree/master/Diagram|gitlab]] [[http://kmlinux.fjfi.cvut.cz/~culikzde/pw/Diagram2020.zip|zip]]