Creare un grafico con il componente gb.chart
Indice
Introduzione
gb.chart di Fabien Bodard è un componente instabile un tantinello buggato, praticamente abbandonato perché l’autore si è ripromesso di rifarlo da capo. Nell’attesa del nuovo vediamo come possiamo usare al meglio quello che abbiamo e che comunque soddisfa molto il sottoscritto. Di seguito creeremo un grafico sia a colonne che a linee (di confronto mese per mese) sul fatturato degli ultimi dieci anni di un’ipotetica azienda, alla fine invieremo il o i grafici a gb.report per la stampa. Vi invito a visionare il test di esempio (FTest) scritto da Bodard stesso presente all’interno del componente che ne affronta tutti gli aspetti e non solo una parte come invece fa questo progetto.
Nota: nella Software farm è presente il progetto qui descritto.
Progetto ChartReport
Avviamo Gambas e creiamo un progetto grafico nominandolo ChartReport (questo è il nome nella farm) o in qualunque altro modo vi aggrada. In Progetto > Proprietà > Componenti mettiamo la spunta a gb.chart e a gb.report2.
Il funzionamento dell'applicazione
Per meglio comprendere il codice vediamo una breve spiegazione sul funzionamento. All’apertura si crea il grafico a colonna se i colori vanno bene lo salviamo oppure prima di farlo cambiamo i colori di default con quelli personalizzati, possiamo volendo creare anche il grafico a linee e salvarlo. Alla fine agiamo sul pulsante anteprima di stampa che manda il o i grafici al report.
Il disegno della finestra FMain
Nella scheda Fmain.form della IDE, in Proprietà impostiamo: Arrangement = Vertical.
Dalla scheda Container posta al disotto delle proprietà clicchiamo su Panel per poi disegnarlo sulla finestra, lasciando un po si spazio in basso per potervi disegnare una HBox con dei pulsanti, e lo impostiamo:
- Arrangement = Horizontal
- Expand = True
Come detto, prelevandolo dalla scheda Container, disegniamo sotto il Panel un HBox con altezza 32.
Sempre dalla scheda Container disegnamo all’interno di Hbox partendo da sinistra uno Spring, in alternativa potete disegnare un Panel con proprietà: Expand = True.
Prelevandoli dalla scheda Form, continuiamo disegnando quattro pulsanti con rispettivamente le seguenti proprietà:
Primo pulsante da sinistra:
- Name = btnPrint
- Autoresize = True
- Picture = icon:/small/preview
- Text = Print
- ToolTip = Print preview
Secondo pulsante:
- Name = btnSavePicture
- Autoresize = True
- Text = Save chart
- ToolTip = Save current chart
Terzo pulsante:
- Name = btnColors
- Autoresize = True
- ToolTip = ChangeColors
Quarto pulsante
- Name = btnType
- Autoresize = True
- ToolTip = Change view
Per finire disegnamo in senso orizzontale un separatore fra il Panel e Hbox lasciando l’altezza predefinita (8).
Il codice della finestra Fmain
Nella scheda Fmain.class della IDE scriviamo questo codice:
Property Read sHead As String Property Read sPicPaths As String[] Private $sPicPaths As New String[] Private $sHead As String Public Sub Form_Open() Dim aMonths As String[] = [("January"), ("February"), ("March"), ("April"), ("May"), ("June"), ("July"), ("August"), ("September"), ("October"), ("November"), ("December")] Dim aTurn2009 As Float[] = ReturnTurnover(54000.00, 55999.00) Dim aTurn2010 As Float[] = ReturnTurnover(55620.00, 57120.00) Dim aTurn2011 As Float[] = ReturnTurnover(56732.00, 58800.00) Dim aTurn2012 As Float[] = ReturnTurnover(58434.00, 60000.00) Dim aTurn2013 As Float[] = ReturnTurnover(59603.00, 61200.00) Dim aTurn2014 As Float[] = ReturnTurnover(60795.00, 62500.00) Dim aTurn2015 As Float[] = ReturnTurnover(62618.00, 63600.00) Dim aTurn2016 As Float[] = ReturnTurnover(63871.00, 64989.00) Dim aTurn2017 As Float[] = ReturnTurnover(65150.00, 66300.00) Dim aTurn2018 As Float[] = ReturnTurnover(66450.00, 67700.00) $sHead = ("Report 2019") DeletePic Me.Width = Screen.Width - 200 Me.Height = Screen.Height - 200 Chart.CountDataSets = 10 Chart.XAxe.Font = Font["Sans Serif,14"] Chart.YAxe.Font = Font["Sans Serif,14"] Chart.YAxe.MinValue = 22000.00 Chart.YAxe.MaxValue = 68000.00 Chart.YAxe.Step = 2000 With Chart.Colors.Values .Add(Color.Red) .Add(Color.Blue) .Add(Color.Green) .Add(Color.Cyan) .Add(Color.Orange) .Add(Color.Gray) .Add(Color.DarkBlue) .Add(Color.Yellow) .Add(Color.Violet) .Add(Color.Pink) .Add(Color.LightGray) .Add(Color.DarkGreen) End With btnColors_Click Chart.Headers.Values = aMonths Chart[0].Values = aTurn2009 Chart[0].Text = "2009" Chart[1].Values = aTurn2010 Chart[1].Text = "2010" Chart[2].Values = aTurn2011 Chart[2].Text = "2011" Chart[3].Values = aTurn2012 Chart[3].Text = "2012" Chart[4].Values = aTurn2013 Chart[4].Text = "2013" Chart[5].Values = aTurn2014 Chart[5].Text = "2014" Chart[6].Values = aTurn2015 Chart[6].Text = "2015" Chart[7].Values = aTurn2016 Chart[7].Text = "2016" Chart[8].Values = aTurn2017 Chart[8].Text = "2017" Chart[9].Values = aTurn2018 Chart[9].Text = "2018" Chart.Title.Font = Font["Sans Serif,30,Bold"] Chart.Title.Text = ("Turnover 2009 - 2018") Chart.Legend.Visible = True Chart.Legend.Font = Font["Sans Serif,14"] Chart.Legend.Position = Align.Bottom Chart.YAxe.ShowIntervalLines = True Chart.BackGround = Color.RGB(176, 220, 241) btnType_Click End Public Sub DrawingArea1_Draw() Chart.Width = DrawingArea1.ClientWidth Chart.Height = DrawingArea1.ClientHeight Chart.Draw() End Private Function ReturnTurnover(fMin As Float, fMax As Float) As Float[] Dim aTurnover As New Float[] Dim fRes As Float Randomize For i As Integer = 1 To 12 fRes = Rnd(fMin, fMax) If i = 2 Then fRes = fRes - ((fRes / 100) * 6) Else If i = 8 Then fRes = fRes - ((fRes / 100) * 50) Endif aTurnover.Add(Round(fRes, -2)) Next Return aTurnover End Public Sub btnType_Click() If btnType.Text = ("Lines") Then Chart.Legend.Title = ("The color of the years") Chart.Type = ChartType.Lines btnType.Text = ("Columns") Else Chart.Legend.Title = ("The color of the months") Chart.Type = ChartType.Columns btnType.Text = ("Lines") Endif DrawingArea1.Refresh() End Public Sub btnColors_Click() If btnColors.Text = ("Custom colors") Then Chart.Colors.Style = Chart.Colors.Custom btnColors.Text = ("Default colors") Else Chart.Colors.Style = Chart.Colors.Auto btnColors.Text = ("Custom colors") Endif DrawingArea1.Refresh() End Private Function sPicPaths_Read() As String[] Return $sPicPaths End Public Sub btnSavePicture_Click() ' Vuott tip Dim pic As Picture pic = Desktop.Screenshot(DrawingArea1.ScreenX, DrawingArea1.ScreenY, DrawingArea1.Width, DrawingArea1.Height) $sPicPaths.Push("/tmp/chart-pic" & CStr($sPicPaths.Count + 1) & ".png") pic.Save($sPicPaths[$sPicPaths.Max], 50) End Public Sub btnPrint_Click() If $sPicPaths.Count > 0 Then Report1.Preview DeletePic Me.Close Endif End Private Sub DeletePic() Dim s As String For Each s In Dir("/tmp", "chart-pic*.png", gb.File) Try Kill "/tmp" &/ s Next End Private Function sHead_Read() As String Return $sHead End
Diamo uno sguardo a quanto abbiamo appena scritto:
Per prima cosa abbiamo creato due proprietà di sola lettura per poter passare al report il titolo della relazione e le path delle immagini del o dei grafici.
Qui viene tutto simulato attraverso il codice ma nella realtà i dati saranno il frutto di interrogazioni a un database o qualcosa di simile.
Pertanto, all’apertura, attraverso la funzione ReturTurnover creiamo i fatturati mese per mese e li assegnamo ai rispettivi vettori (array).
Anche se non dovrebbe servire in quanto lo facciamo già in btnPrint_Click(), attraverso la routine DeletePic eliminiamo eventuali immagini di grafici presenti nella cartella tmp.
Impostiamo il grafico per 10 set di dati (i dieci anni confrontati).
Impostiamo i font e i valori minimo e massimo (di anni e fatturato) per gli assi del grafico orizzontale (ascisse) e verticale (ordinate).
Impostiamo l’intervallo dei valori in base al quale verrà suddiviso il fatturato e lo sfondo.
Per avere i colori personalizzati uno differente dall’altro, occorre impostarli sui dati più alti mostrati dai grafici in questo caso i 12 mesi.
Agendo sul pulsante btnColors impostiamo i colori di default e la scritta del pulsante stesso.
Passiamo il vettore dei mesi come valori per l’asse delle ascisse.
E passiamo i vettori degli anni come valori per l’asse delle ordinate.
Impostiamo il font del titolo e passiamo il valore.
Mostriamo la leggenda alla base del grafico impostandone il font.
Mostriamo le linee degli intervalli di valore.
Diamo un colore allo sfondo.
E alla fine dell’evento Open solleviamo l’evento btnType_Click per mostrare il grafico a colonne.
Infatti btnType_click alterna la creazione dei grafici a colonna e a linee a seconda di quanto scritto nella proprietà Text, alla fine attiva l’evento DrawingArea_Draw con DrawingArea1.Refresh.
Ogni volta che agiamo sul pulsante btnSavePicture per salvare le immagini nella cartella tmp, usiamo uno dei codici suggeriti da vuott in questa pagina:
https://www.gambas-it.org/wiki/index.php?title=Generare_un_file_immagine_da_una_DrawingArea
btnPrint_Click apre l’anteprima del Report, come detto cancella le immagini inviate al report e alla chiusura della finestra report chiude l’applicazione.
Le scritte in inglese sono avvolte da parentesi per poterle tradurre e creare un progetto internazionale. Per renderlo tale, al momento della creazione del progetto basta spuntare la casella Il progetto è traducibile, se non lo abbiamo fatto basta andare al menu Progetto > Proprietà > Opzioni e swithcciare su Il progetto è traducibile, nella IDE appare il nuovo pulsante Traduci e se ci clicchiamo sopra possiamo tradurre le scritte fra parentesi nell’apposita finestra.
Il disegno della finestra Report
Nel browser sulla sinistra della IDE clicchiamo col tasto destro del mouse sulla cartella Sorgenti > Nuovo > Report… e scegliamo OK nella finestra che appare e propone Report1. Doppio click su Report1 per farne apparire la finestra.
Dalla ToolBox scheda Report scegliamo una ReportLabel e disegnamola sulla finestra. Diamogli le proprietà:
- Alignement = Center
- Fixed = True (serve a ripetere il contenuto della label su tutte le pagine)
- Height = 10mm
Dalla scheda Container scegliamo un ReportVBox e disegnamolo appena sotto la label dando True alla proprietà Expand.
Appena sotto disegnamo un’altra label con le stesse proprietà della prima ma con in più:
- Text = ="Page " & page & " on " & pages (la scritta deve comprendere = il quale indica al report che trattasi di funzione).
Il codice del Report
Agiamo sulla freccia oppure sul tasto funzione F12 per passare a Report1.class e scriviamo:
Public Sub Report_Open() Dim s As String Dim hRepIm As ReportImage ReportLabel1.Text = FMain.sHead If FMain.sPicPaths.Count > 1 Then Report1.Orientation = Printer.Portrait For i As Integer = 0 To FMain.sPicPaths.Max s = FMain.sPicPaths[i] hRepIm = New ReportImage(ReportVBox1) hRepIm.Alignment = Align.Center hRepIm.Height = "11cm" hRepIm.Stretch = Report.Proportional hRepIm.Image = Image.Load(s) Next Else Report1.Orientation = Printer.Landscape s = FMain.sPicPaths[0] hRepIm = New ReportImage(ReportVBox1) hRepIm.Alignment = Align.Center hRepIm.Expand = True hRepIm.Stretch = Report.Proportional hRepIm.Image = Image.Load(s) Endif End
Anche qui diamo uno sguardo a quanto abbiamo appena scritto.
Nell’evento di apertura del report passiamo alla prima label il testo per l’intestazione del report. Se abbiamo disegnato più di un grafico allora la pagina del report si posiziona in verticale altrimenti in orizzontale. Per ogni percorso di immagine di grafico disegnamo nel ReportVBox una ReportImage con le seguenti proprietà:
- Alignement = Align.Center
- Expand = True
- Stretch = Report.Proportional
- Image = Image.Load(<percorso/immagine>)
Fatto, ora possiamo avviare il progetto per constatarne il corretto funzionamento.