none
Colorare grafico RRS feed

  • Domanda

  • Ciao,

    sto cercando di riprodurre in vb quanto sono riuscito a fare in excel. Mi spiego: partendo da un grafico a dispersione inserito in un foglio excel, utilizzando degli shapes sono riuscito a disegnare dei rettangoli colorati e rappresentare la forma desiderata. 

    In vb 2010, non riesco ad ottenere lo stesso risultato. La strada degli shapes non sembra percorribile. Tra l'altro utilizzando un ciclo for per disegnare uno dopo l'altro gli shapes riesco a visualizzare solo l'ultimo e non tutti.

    Sto provando con 

    Dim GraphicsA As System.Drawing.Graphics
                GraphicsA = Sezione.CreateGraphics
                Dim PenColor As New System.Drawing.Pen(System.Drawing.Color.Black)
                Dim blueBrush As New SolidBrush(Color.LightBlue)
                GraphicsA.FillRectangle(blueBrush, 10, 10, 200, 200)
                GraphicsA.DrawRectangle(PenColor, 10, 10, 200, 200)

    Dove poi penso di sostituire i punti 10,10,200,200 con i punti della serie...ma anche qui mi imbatto in un altro problema: i punti della mia serie hanno i decimali (double) e DrawRectangle invece richiede un intero  (Integer).

    Qualche suggerimento? Lo scopo è quello di colorare il grafico.

    Grazie

    mercoledì 25 gennaio 2017 15:45

Risposte

Tutte le risposte

  • Vanno bene anche in virgola mobile:

    Public Class Form1
    
        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
            e.Graphics.FillRectangle(Brushes.Gold, 100.4F, 50.5F, 60, 80.4F)
        End Sub
    
    End Class
    

    mercoledì 25 gennaio 2017 22:02
  • Grazie mile BlueLed, hai perfettamente ragione!

    Ne approfitto per chiedere perché non riesco a individuare le coordinate del punto della serie del grafico per passarlo al rettangolo da disegnare.

    In excel facevo così:

                           

          Set myCht = ActiveChart

          Xleft = myCht.PlotArea.InsideLeft
          Xwidth = myCht.PlotArea.InsideWidth
          Ytop = myCht.PlotArea.InsideTop
          Yheight = myCht.PlotArea.InsideHeight

          Xmin = myCht.Axes(1).MinimumScale
          Xmax = myCht.Axes(1).MaximumScale
          Ymin = myCht.Axes(2).MinimumScale
          Ymax = myCht.Axes(2).MaximumScale

          Set mySrs = myCht.SeriesCollection(1)
          Npts = mySrs.Points.Count
     For Ipts = 1 To Npts

          Xnode = Xleft + (mySrs.XValues(Ipts) - Xmin) * Xwidth / (Xmax - Xmin)
          Ynode = Ytop + (Ymax - mySrs.Values(Ipts)) * Yheight / (Ymax - Ymin)
          Set myBuilder = myCht.Shapes.BuildFreeform(msoEditingAuto, Xnode, Ynode)
     Next

     Set myShape = myBuilder.ConvertToShape

    Sbaglio se in vb sostituisco con?:

     Xleft = Sezione.ChartAreas(0).InnerPlotPosition.X
     Xwidth = Sezione.ChartAreas(0).InnerPlotPosition.Width
     Ytop = Sezione.ChartAreas(0).InnerPlotPosition.Y
     Yheight = Sezione.ChartAreas(0).InnerPlotPosition.Height 

     Xmin = Sezione.ChartAreas(0).AxisX.Minimum
     Xmax = Sezione.ChartAreas(0).AxisX.Maximum
     Ymin = Sezione.ChartAreas(0).AxisY.Minimum
     Ymax = Sezione.ChartAreas(0).AxisY.Maximum


    giovedì 26 gennaio 2017 15:34
  • E' probabile che i valori non sono espressi in pixel e li dovrai convertire con ValueToPixelPosition come in questo post:

    http://stackoverflow.com/questions/7283394/ms-charts-getting-the-real-innerplotposition/7301999

    giovedì 26 gennaio 2017 16:00
  • Grazie,

    hai perfettamente ragione, convertendo i punti con ValueToPixelPosition ottengo esattamente la posizione corretta per il rettangolo da disegnare sopra il grafico.

    Però succede questo: la chart è contenuta in una form con scroll. Quando scrollo la form i rettangoli disegnati si cancellano...come posso fare affinché non succeda..e anche quando stampo la form, stampo la chart ma non i rettangoli...come posso risolvere? 

    Ho provato a mettere il disegno del rettangolo nell'evento paint della chart ma a quel punto non visualizzo nemmeno la chart.

    Dove sbaglio? Idee?

    Grazie

    martedì 31 gennaio 2017 15:31
  • Ti crei un controllo dove disegnare ed aggiungi il controllo al Form. Farai in modo di comunicare al controllo i valori che verranno utilizzati per il disegno.

    Ecco un controllo personalizzato:

    Class Disegno
        Inherits Control
    
        Public Sub New()
            DoubleBuffered = True
        End Sub
    
        Protected Overrides Sub OnPaintBackground(ByVal pevent As PaintEventArgs)
    
        End Sub
    
        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
            e.Graphics.Clear(Color.White)
            e.Graphics.FillRectangle(Brushes.Gold, 6, 6, 20, 30)
        End Sub
    
    End Class

    martedì 31 gennaio 2017 15:52
  • Ancora una volta la strada che mi hai indicato è giusta..

    ho fatto come mi hai consigliato, creando un nuovo controllo e associandolo al Form..il tuo esempio funziona bene, quindi sto cercando di adattarlo alla creazione dei rettangoli sulla chart..

    però mi è successo questo...testando il controllo, mi è sparito tutto il contenuto della Form. Il codice c'è ma nella finestra di progettazione la form è vuota. Non riesco a ripristinare la Form come in precedenza. Addirittura il debug funziona, ma la finestra è vuota.

    C'è qualcosa che posso controllare o non mi resta che ripartire con un nuovo progetto? 

    Grazie

    mercoledì 1 febbraio 2017 17:17
  • Nell' "esplora soluzione" c'è un pulsante che ti permette di mostrare "tutti i file".  Se cerchi tra i file, troverai il designer del form, tipo Form1.Designer.vb . Lì c'è il codice che mostra contenuto ed inizializzazione del form. (Può essere che hai aggiunto il nuovo controllo sopra tutti gli altri).
    mercoledì 1 febbraio 2017 21:47
  • Sì, anch'io ho guardato nel Form1.Designer.vb è purtorppo mancavano pezzi di codice...non so come sia successo, ma riscrivendoli, ho recuperato tutta la form.

    Ho ripreso il tuo consiglio del controllo..funziona ma con questo limite:

    come dicevo, i rettangoli vengono disegnati con un ciclo sopra la chart e quando scrollavo la form che contiene la chart sparivano. Ora con il controllo, quando scrollo, spariscono e poi vengono ridisegnati ma non sempre interamente..nel senso che se lo scroll avviene lentamente..vengono ridisegnati i rettangoli solo in parte (infatti non appena viene visualizzato sulla form il controllo, inizia il disegno dei rettangoli, e se la chart non è visualizzata interamente, alcuni punti, non essendo ancora disegnati non passano al ciclo che disegna il rettangolo).

    Tra l'altro non so come passare in stampa i rettangoli...ma mi viene questa idea: se passassi ad un controllo picturebox il disegno del grafico e dei rettangoli? Secondo te è possibile farlo...poi avrei solo da stampare la picturebox...e anche il problema dello scroll del form non ci sarebbe..almeno credo. Solo che non so se si possa disegnare chart e rettangoli in una picturebox...

    Cosa ne pensi...sono fuori strada?

    Grazie...i tuoi consigli sono ottimi e preziosi


    giovedì 2 febbraio 2017 16:01
  • Bisogna vedere come colleghi i dati della chart al controllo che li disegna. Quando disegni con CreateGraphics, come hai mostrato all'inizio, il disegno non è persistente. Se disegni in OnPaint il disegno diventa persistente, ma devi tenere memorizzati o saper recuperare i dati ogni volta che OnPaint viene chiamato. Prima risolvi questa cosa, poi puoi dedicarti alla stampa.
    giovedì 2 febbraio 2017 21:40
  • I tuoi consigli sono sempre illuminanti..grazie.

    Purtroppo mi sembra di essere in un vicolo cieco... ho fatto così..nella form ho la chart e per ogni punto del grafico, come mi ha suggerito mi trovo le coordinate dei rettangoli che voglio disegnare, le converto con ValuetoPixelPosition e le scrivo in un datatable (T_Punti) che dichiaro public shared, di modo da poter richiamare in punti dei rettangoli dalla class del controllo che mi hai consigliato per disegnare i rettangoli.

    Cosa ho ottenuto?...ora ho la chart nella form con i punti e nel datatable le corrette coordinate per i rettangoli...solo che non mi disegna i rettangoli...o meglio li disegna solo se scrollo la form e con lo stesso effetto di prima, cioè non li ridisegna sempre tutti quando scrollo lentamente la Form...help!

    Grazie 

    Il controllo l'ho scritto in questo modo:

    Public Class Dixegno
        Inherits Control

        Public Sub New()
            DoubleBuffered = True
        End Sub

        Protected Overrides Sub OnPaintBackground(ByVal pevent As PaintEventArgs)

        End Sub

        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)

            Dim Ipts, Npts As Double
            Dim GraphicsSez As System.Drawing.Graphics
            Dim semiTransBrush As New SolidBrush(Color.FromArgb(128, 101, 67, 33))

            Npts = Form1.T_Punti.Rows.Count - 1

            For Ipts = 0 To Npts
                GraphicsSez = Form1.Sezione.CreateGraphics
                GraphicsSez.FillRectangle(semiTransBrush, Form1.T_Punti.Rows(Ipts).Item(0), Form1.T_Punti.Rows(Ipts).Item(1), Form1.T_Punti.Rows(Ipts).Item(2), Form1.T_Punti.Rows(Ipts).Item(3))
            Next

        End Sub

    End Class
     
    venerdì 3 febbraio 2017 16:22
  • In OnPaint devi disegnare con il graphics dato da e.Graphics, non usando CreateGraphics.
    venerdì 3 febbraio 2017 21:32
  • Ok, grazie...ora sto utilizzando e.Graphics, ma l'aggiunta del controllo mi sta dando parecchi problemi..primo fra tutti il fatto che inserendolo nella forma, sopra la chart, la copre completamente e non non vedo più la chart..

    Sto provando invece la strada di evitare la creazione del controllo e inserire nella form una Public Sub mychart_paint (ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles mychart.Paint nella quale disegno con e.graphics.

    Ottengo esattamente quello che desidero, e anche quando scrollo il form i rettangoli stanno lì belli come li voglio. Ho un solo problema..quando carico per la prima volta la chart i rettagoli non li vedo, ma diventano visibili solo dopo aver ricaricato la chart. Come se non li disegnasse fino a quando la chart non è visibile e in qualche modo debba essere ridisegnata). 

    Non c'è un modo per richiamare la Sub mychart_paint non appena disegnata la chart? Dal debug noto che viene chiamata durante la creazione della chart, ma una volta che è visualizzata la chart non viene più richiamata...forse sta lì la soluzione.

    C'è qualche speranza in questa soluzione?

    Grazie

    lunedì 6 febbraio 2017 17:34
  • Il fatto è che non è chiaro quale sia il layout che vuoi ottenere e soprattutto quale sia la relazione tra il chart ed il tuo disegno. A che ti serve il chart se il disegno lo rifai a parte?
    lunedì 6 febbraio 2017 22:05
  • Ci sono riuscito!!!

    Prima di tutto grazie.

    Spiego: il layout che desideravo ottenere è quello di colorare delle aree (i rettangoli) di un grafico.

    Ora,nella chart ho utilizzato un grafico a dispersione. I punti sono le coordinate del rettangolo. 

     Disegnato il grafico della chart, ho inserito nell'evento OnPaint del grafico la chiamata alla procedura che calcola coordinate e dimensioni dei rettangoli da disegnare per ogni punto e le ho memorizzate in un datatable.

    A questo punto, sempre nell'evento OnPaint del grafico disegno per ogni punto i rettangoli.

    In questo modo ottengo il disegno dei rettangoli sulla chart e ogni volta che scrollo il form che contiene la chart vengono ridisegnati anche i rettangoli nella posizione corretta.

    Come mi hai suggerito tu, ora passo alla stampa...

    Per stampare il grafico, uso:

    Dim mygraph As System.Drawing.Rectangle
    mygraph= New System.Drawing.Rectangle(10, 280, 780, Form1.graph.Height *2) aumento altezza sulla stampa
    Form1.graph.Printing.PrintPaint(e.Graphics, myRecx_mygraph)
    ResizeRedraw = True

    Per i rettangoli userei lo stesso ciclo usato in Onpaint:

    Dim semiTransBrush As New SolidBrush(Color.FromArgb(128, 101, 67, 33))
                    Dim Ipts, Npts As Double
                    Npts = Form1.T_Punti.Rows.Count - 1

                    For Ipts = 0 To Npts
                        e.Graphics.FillRectangle(semiTransBrush, Form1.T_Punti.Rows(Ipts).Item(0), Form1.T_Punti.Rows(Ipts).Item(1), Form1.T_Punti.Rows(Ipts).Item(2), Form1.T_Punti.Rows(Ipts).Item(3))
                    Next

    Ottengo l'effetto desiderato, ovvero la stampa del grafico e dei rettangoli, ma ovviamente i rettangoli non sono delle dimensioni corrette e nel posto corretto...diciamo che ho verificato se la stampa dei rettangoli funzioni..ora devo riuscire a stampare correttamente i rettangoli al posto giusto e delle dimensioni giuste...

    ..e se pensassi di trattare per la stampa grafico e rettangoli come una bitmap in una picturebox?

    Tu hai sempre degli ottimi consigli...cosa ne pensi?

    Grazie mille

    martedì 7 febbraio 2017 12:04
  • Per stampare puoi usare PrintDialog e PrintDocument, quando ti verrà chiesto di stampare da PrintDocument chiamerai sullo stesso Graphics prima PrintPaint della chart e poi la funzione che disegna i rettangoli.

    Per mappare le coordinate, prendi la ChartArea, questa ha le proprietà AxisX e AxisY tramite le quali puoi usare il metodo ValueToPixelPosition.

    martedì 7 febbraio 2017 13:49
  • Ciao!

    Con la picturebox funziona...ma non è il massimo come qualità...

    come sempre mi piace il tuo consiglio e sto facendo come dici tu usando PrintDialog e Print Document..

    chiamo printpaint della chart...e funziona, poi chiamo la funzione che disegna i rettangoli ma qui sono in difficoltà..come faccio a mappare le coordinate della chartArea che ora sta nel nel rettangolo dove avviene il printpaint della chart? 

    Sbaglio qualcosa?

    Grazie

    martedì 7 febbraio 2017 14:36
  • Ma non eri già riuscito ad usare ValueToPixelPosition ?

    martedì 7 febbraio 2017 15:09
  • Ciao...sì ed era il consiglio giusto..

    stavo guardando il dito che indica la luna e non la luna...la soluzione era aggiungere alla posizione delle coordinate dei punti (calcolata con ValueToPixelPosition) la posizione del rettangolo che passo a printpaint!

    A questo punto ho ottenuto il risultato...e tu mi sei stato di gradissimo aiuto! Ottimi consigli!!!

    Giusto per fare il pignolo...i rettangoli che ho disegnato sono semitrasparenti per lasciar intravedere la griglia del grafico sottostante..a video è bellissimo..ma quando vado in stampa su pdf..la trasparenza diventa un reticolo di puntini...ma qui non credo dipenda da codice o impostazioni....rimarrò probabilmente con il dubbio se si possa fare meglio.

    Grazie ancora

    mercoledì 8 febbraio 2017 11:20
  • Ciao...sì ed era il consiglio giusto..

    stavo guardando il dito che indica la luna e non la luna...la soluzione era aggiungere alla posizione delle coordinate dei punti (calcolata con ValueToPixelPosition) la posizione del rettangolo che passo a printpaint!

    A questo punto ho ottenuto il risultato...e tu mi sei stato di gradissimo aiuto! Ottimi consigli!!!

    Giusto per fare il pignolo...i rettangoli che ho disegnato sono semitrasparenti per lasciar intravedere la griglia del grafico sottostante..a video è bellissimo..ma quando vado in stampa su pdf..la trasparenza diventa un reticolo di puntini...ma qui non credo dipenda da codice o impostazioni....rimarrò probabilmente con il dubbio se si possa fare meglio.

    Grazie ancora

    Per la trasparenza, invece di stampare direttamente, usa il graphics di una bitmap e poi stampa la bitmap.

    mercoledì 8 febbraio 2017 12:59