Våre tilpassede grafkomponenter krever manuell tegning, så vi må underklasse Lerret
, som er standardkomponenten som leveres for direkte grafikkmanipulering. Teknikken vi skal bruke vil være å overstyre maling
Metode av Lerret
med den tilpassede tegningen vi trenger. Vi vil bruke Grafikk
objekt, som automatisk overføres til maling
metode for alle komponenter, for å få tilgang til farger og tegningsmetoder.
Vi lager to tilpassede grafikkomponenter: et søylediagram og et linjediagram. Vi begynner med å bygge en generell rammeklasse for de to grafene, som deler noen grunnelementer.
Å bygge et generisk graframmeverk
Linjediagrammet og stolpediagrammet vi skal bygge er like nok til at vi kan lage et generisk
Kurve
klasse for å utføre noe av det kjedelige layoutarbeidet. Når det er gjort, kan vi utvide klassen til den spesifikke grafen vi trenger.
Det første du må gjøre når du designer tilpassede grafikkomponenter, er å sette penn på papir og tegne et bilde av det du trenger. Fordi vi teller piksler, er det lett å bli forvirret om plasseringen av elementene. Når du legger vekt på navn og plassering av elementer, vil det hjelpe deg å holde koden renere og lettere å lese senere.
Linjediagrammet og stolpediagrammet bruker samme oppsett for tittel og linjer, så vi begynner med å lage en generisk graf som inneholder disse to funksjonene. Oppsettet vi skal lage er vist i figuren nedenfor.
Å skape det generiske Kurve
klasse, vil vi underklasse Lerret
. Senterområdet er der faktiske grafdata vises; vi overlater dette til en utvidelse av Kurve
å implementere. Vi implementerer de andre elementene - en tittellinje, en vertikal linje til venstre, en horisontal linje nederst og verdier for området - i basisklassen. Vi kunne spesifisere en skrift og hardkode pixelmålingene i, men brukeren kunne ikke endre størrelsen på grafen. En bedre tilnærming er å måle elementene mot nåværende størrelsen på komponenten, slik at endring av applikasjonen vil resultere i en riktig størrelse på grafen.
Her er planen vår: Vi tar en String
tittel, en int
minimumsverdi, og en int
maksimal verdi i konstruktøren. Disse gir oss all informasjon vi trenger for å legge rammene. Vi beholder fire variabler for bruk i underklasser - topp
, bunn
, venstre
, og Ikke sant
verdier for grensene til graftegningsområdet. Vi bruker disse variablene til å beregne posisjonering av grafelementer senere. La oss begynne med en rask titt på Kurve
klassedeklarasjon.
importer java.awt. *; importer java.util. *; public class Graf utvider Canvas {// variabler som trengs public int top; offentlig int bunn; offentlig int venstre; offentlig rett; int tittelHøyde; int labelWidth; FontMetrics fm; int polstring = 4; Stringtittel; int min; int maks; Vektorgjenstander;
For å beregne riktig plassering av grafelementer, må vi først beregne regionene i vårt generiske grafoppsett som utgjør rammeverket. For å forbedre utseendet til komponenten, legger vi til en 4-piksel polstring i ytterkantene. Vi legger til tittelen sentrert øverst, med tanke på paddding-området. For å sikre at grafen ikke blir tegnet oppå teksten, må vi trekke høyden på teksten fra tittelområdet. Vi må gjøre det samme for min
og maks
verdiområdeetiketter. Bredden på denne teksten er lagret i variabelen labelWidth
. Vi må beholde en referanse til skriftmålingene for å gjøre målingene. De gjenstander
vektor brukes til å holde oversikt over alle de individuelle elementene som er lagt til Graf-komponenten. En klasse som brukes til å holde variabler relatert til grafelementer, er inkludert (og forklart) etter Kurve
klasse, som vises neste.
offentlig graf (strengtittel, int min, int maks) {this.title = title; this.min = min; this.max = maks; elementer = ny Vector (); } // sluttkonstruktør
Konstruktøren tar graftittelen og verdiområdet, og vi lager tomme vektorer for de enkelte grafelementene.
offentlig ugyldig omforming (int x, int y, int bredde, int høyde) {super.reshape (x, y, bredde, høyde); fm = getFontMetrics (getFont ()); titleHeight = fm.getHeight (); labelWidth = Math.max (fm.stringWidth (new Integer (min) .toString ()), fm.stringWidth (new Integer (max) .toString ())) + 2; topp = polstring + tittelHøyde; bunn = størrelse (). høyde - polstring; venstre = polstring + labelWidth; høyre = størrelse (). bredde - polstring; } // slutt omforming
Merk: I JDK 1.1 er omforme
metoden erstattes med public void setBounds (Rectangle r)
. Se API-dokumentasjonen for detaljer.
Vi overstyrer omforme
metoden, som arves nedover kjeden fra Komponent
klasse. De omforme
metoden kalles når komponenten endres og når den legges ut første gang. Vi bruker denne metoden til å samle inn målinger, slik at de alltid vil bli oppdatert hvis komponenten endres. Vi får skriftberegningene for gjeldende skrift og tildeler tittelHøyde
variabel den maksimale høyden på skriften. Vi får maksimal bredde på etikettene, tester for å se hvilken som er større og bruker deretter den. De topp
, bunn
, venstre
, og Ikke sant
variabler beregnes fra de andre variablene og representerer grensene til midtgraftegningsområdet. Vi bruker disse variablene i underklassene til Kurve
. Merk at alle målingene tar hensyn til a nåværende størrelsen på komponenten slik at tegning vil være riktig i alle størrelser eller aspekter. Hvis vi brukte hardkodede verdier, kunne ikke komponenten endres.
Deretter tegner vi rammeverket for grafen.
offentlig tom maling (Grafikk g) {// tegne tittelen fm = getFontMetrics (getFont ()); g.drawString (tittel, (størrelse (). bredde - fm.stringWidth (tittel)) / 2, øverst); // tegne maks- og minverdiene g.drawString (nytt heltal (min) .toString (), polstring, bunn); g.drawString (nytt heltal (maks) .toString (), polstring, topp + tittelHøyde); // tegne de vertikale og horisontale linjene g.drawLine (venstre, topp, venstre, bunn); g.drawLine (venstre, nederst, høyre, nederst); } // sluttmaling
Rammeverket er tegnet i maling
metode. Vi tegner tittelen og merkelappene på de aktuelle stedene. Vi tegner en vertikal linje ved venstre kant av graftegningsområdet, og en horisontal linje ved den nederste kanten.
I dette neste utdraget setter vi den foretrukne størrelsen for komponenten ved å overstyre foretrukket størrelse
metode. De foretrukket størrelse
metoden er også arvet fra Komponent
klasse. Komponenter kan spesifisere en ønsket størrelse og en minimumsstørrelse. Jeg har valgt en foretrukket bredde på 300 og en foretrukket høyde på 200. Layoutlederen vil kalle denne metoden når den legger ut komponenten.
offentlig dimensjon foretrukket størrelse () {retur (ny dimensjon (300, 200)); }} // slutt Graf
Merk: I JDK 1.1 er foretrukket størrelse
metoden erstattes med offentlig dimensjon getPreferredSize ()
.
Deretter trenger vi et anlegg for å legge til og fjerne elementene som skal tegnes.
public void addItem (String name, int value, Color col) {items.addElement (new GraphItem (name, value, col)); } // end addItem public void addItem (String name, int value) {items.addElement (new GraphItem (name, value, Color.black)); } // slutt addItem offentlig tomrom removeItem (strengnavn) {for (int i = 0; i <items.size (); i ++) {if (((GraphItem) items.elementAt (i)). title.equals (name )) items.removeElementAt (i); }} // slutt removeItem} // slutt Graf
Jeg har modellert addItem
og fjerne gjenstand
metoder etter lignende metoder i Valg
klasse, så koden vil ha et kjent preg. Legg merke til at vi bruker to addItem
metoder her; vi trenger en måte å legge til gjenstander med eller uten farge. Når et element er lagt til, et nytt Grafikk
objektet opprettes og legges til elementvektoren. Når et element fjernes, vil den første i vektoren med det navnet bli fjernet. De Grafikk
klassen er veldig enkel; her er koden:
importer java.awt. *; klasse GraphItem {Stringtittel; int verdi; Farge farge; public GraphItem (String title, int value, Color color) {this.title = title; this.value = verdi; denne. farge = farge; } // sluttkonstruktør} // slutt GraphItem
De Grafikk
klasse fungerer som en holder for variablene knyttet til grafelementer. Jeg har tatt med Farge
her i tilfelle den vil bli brukt i en underklasse av Kurve
.
Med dette rammeverket på plass kan vi lage utvidelser for å håndtere hver type graf. Denne strategien er ganske praktisk; vi trenger ikke å gjøre bryet med å måle piksler for rammeverket igjen, og vi kan lage underklasser for å fokusere på å fylle ut graftegningsområdet.
Bygg søylediagram
Nå som vi har et grafisk rammeverk, kan vi tilpasse det ved å utvide det
Kurve
og implementere tilpasset tegning. Vi begynner med et enkelt stolpediagram, som vi kan bruke akkurat som alle andre komponenter. Et typisk søylediagram er illustrert nedenfor. Vi fyller ut graftegningsområdet ved å overstyre
maling
metode for å kalle superklassen
maling
metode (for å tegne rammeverket), så utfører vi den tilpassede tegningen som er nødvendig for denne typen graf.
importer java.awt. *; offentlig klasse BarChart utvider Graph {int posisjon; int økning; public BarChart (String title, int min, int max) {super (title, min, max); } // sluttkonstruktør
For å plassere varene jevnt, beholder vi en økning
variabel for å indikere beløpet vi vil skifte til høyre for hver vare. Posisjonsvariabelen er den nåværende posisjonen, og økningsverdien legges til den hver gang. Konstruktøren tar ganske enkelt inn verdier for superkonstruktøren (Kurve
), som vi kaller eksplisitt.
Nå kan vi komme ned til noen faktiske tegninger.
offentlig tomrom (Grafikk g) {super.paint (g); inkrement = (høyre - venstre) / (items.size ()); posisjon = venstre; Fargetemp = g.getColor (); for (int i = 0; i <items.size (); i ++) {GraphItem item = (GraphItem) items.elementAt (i); int justert Verdi = bunn - (((var.verdi - min) * (nederst - øverst)) / (maks - min)); g.drawString (item.title, position + (increment - fm.stringWidth (item.title)) / 2, justertValue - 2); g.setColor (item.color); g.fillRect (posisjon, justert verdi, økning, bunn - justert verdi); posisjon + = inkrement; g.setColor (temp); }} // sluttmaling} // slutt BarChart
La oss se nærmere på hva som skjer her. I maling
metoden, kaller vi superklassen maling
metode for å tegne graframmen. Vi finner deretter økning
ved å trekke høyre kant fra venstre kant, og deretter dele resultatet med antall elementer. Denne verdien er avstanden mellom venstre kant av grafelementene. Fordi vi vil at grafen skal kunne endres, baserer vi disse verdiene på gjeldende verdi av venstre
og Ikke sant
variabler arvet fra Kurve
. Husk at venstre
, Ikke sant
, topp
, og bunn
verdiene er gjeldende faktiske pikselmålinger av graftegningsområdet tatt i omforme
Metode av Kurve
, og derfor tilgjengelig for vårt bruk. Hvis vi ikke baserte våre målinger på disse verdiene, ville ikke grafen kunne endres.
Vi tegner rektanglene i fargen spesifisert av Grafikk
. For å tillate oss å gå tilbake til den opprinnelige fargen, setter vi en midlertidig farge
variabel for å holde gjeldende verdi før vi endrer den. Vi sykler gjennom vektoren av grafelementer, beregner en justert vertikal verdi for hver, tegner tittelen på elementet og et fylt rektangel som representerer verdien. Inkrementet legges til x-posisjonsvariabelen hver gang gjennom sløyfen.
Den justerte vertikale verdien sørger for at hvis komponenten strekkes vertikalt, vil grafen fortsatt være tro mot de plottede verdiene. For å gjøre dette ordentlig må vi ta prosentandelen av området elementet representerer og multiplisere verdien med det faktiske pikselområdet til graftegningsområdet. Vi trekker deretter resultatet fra bunn
verdi for å plotte poenget riktig.
Som du kan se fra følgende diagram, er den totale horisontale pikselstørrelsen representert med høyre venstre og den totale vertikale størrelsen er representert med bunn topp.
Vi tar oss av den horisontale strekkingen ved å initialisere posisjon
variabel til venstre kant og øke den med økning
variabel for hvert element. Fordi det posisjon
og økning
variabler er avhengige av de faktiske nåværende pikselverdiene, komponenten blir alltid endret riktig i horisontal retning.
For å sikre at den vertikale tegningen alltid er riktig, må vi kartlegge grafelementverdiene med faktiske pikselplasseringer. Det er en komplikasjon: maks
og min
verdiene skal være meningsfylte for posisjonen til verdien på grafen. Med andre ord, hvis grafen starter på 150 og går til 200, skal et element med verdien 175 vises halvveis opp i den vertikale aksen. For å oppnå dette finner vi prosentandelen av grafområdet som varen representerer, og multipliserer den med det faktiske pikselområdet. Fordi grafen vår er opp ned fra grafikkontekstens koordinatsystem, trekker vi dette tallet fra bunn
for å finne riktig tomtpunkt. Husk at opprinnelsen (0,0) er i øvre venstre hjørne for koden, men nederst til venstre for grafstilen vi lager.