Programmering

Kartlegg deg til tilpassede grafkomponenter

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.

$config[zx-auto] not found$config[zx-overlay] not found