====== 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]]