Wie zeichne ich das am geschicktesten?

Thallius

Top Contributor
Hi,

ich muss in eine Tabelle hunderte von Einträgen selber zeichnen. Im Moment sieht die Routine folgendermassen aus:

Code:
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;

        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        int w = getWidth() - shadowLeft;
        int h = getHeight() - shadowTop;

        GradientPaint gp = new GradientPaint(0, 0, data.topColor, 0, h, data.bottomColor);
        g2d.setPaint(gp);
        g2d.fillRoundRect(0, 0, w, h, 10, 10);
    
        inttoTravel = ((int)toTravelMinutes * pixelPerHour) / 60;

        if(toTravel > 1)
        {
            gp = new GradientPaint(0, 0, travelData.topColor, 0, h, travelData.bottomColor);
            g2d.setPaint(gp);
            g2d.fillRoundRect(0, 0, toTravel, h, 10, 10);
        }

        g2d.setColor(GlobalSettings.jobViewBorderColor);
        g2d.drawRoundRect(0, 0, w - 1, h - 1, 10, 10);
    }

Das Ergebnis habe ich in einem Bild angehängt. Es handelt sich hierbei um einen Techniker-Auftrag. In diesem soll nun die eigentlich Arbeitszeit und die An- und Abfahrszeit farblich gertrennt gezeichnet werden. Der einfachheit halber habe ich jetzt nur mal die Anfahrtszeit mit eingebaut.
Wie ihr seht ist das Ergebnis natürlich suboptimal, da der Übergang von Traveltime zu Worktime nicht abgerundet sein sollte. Da die Traveltime aber von 1 Pixel bis zu 50% des ganzen Balken einnehmen kann, kann ich auch nicht einfach die Worktime als FillRect machen, da es dann, wenn die Traveltime nur 1-2 Pixel breit ist die abgerundeten Ecken zernageln würde. Fusch wäre jetzt das so zu machen wie ich es habe und ab einer TravelTime von 5 Pixeln nochmal ein Rectfill mit Travelfarbe ab xPos 5 zu zeichnen z.B. Andere Fuschereien gibts natürlich auch ohne Ende.

Schöner wäre es hier eine performante und saubere Lösung zu finden. Kann man da eventuell mit Maskierung arbeiten. Oder ist das dann viel zu langsam?

Wer hat Ideen?

Gruß

Claus
 

Anhänge

  • image.png
    image.png
    4,7 KB · Aufrufe: 44

dzim

Top Contributor
Hm. ich muss zugeben, dass ich das Problem noch nicht ganz verstehe. Was ist an dem Bild genau Sub-Optimal?

Ich weiss nur, das Dirk Lemmermann mal mit so etwas konfrontiert war: Er hat CallendarFX - eine (Überraschung!) Kalenderübersicht - geschrieben, die (wenn ich es richtig verstehe) sich viel auf Canvas verlässt.
Vielleicht findest du da eine Idee:
http://dlsc.com/javafx-tip-20-a-lot-to-show-use-canvas/

(Wie gesagt, ich habe dein Problem noch nicht ganz verstanden...)
 

Thallius

Top Contributor
Zoome einfach mal weit in das Bild herein. Dann siehst du, dass der Übergang von TravelTime (grau) zu WorkTime (grün) hält abgerundete Kanten hat. Das ist unschön. Wenn ich ein Rectfill hätte bei dem ich angeben kann das z.B. Nur die Linken beiden Kanten abgerundet werden sollen, dann wäre mein Problem gelöst.

Gruß

Claus
 

dzim

Top Contributor
Ah ja. Hab ich auf Originalgrösse nicht erkannt :D

Kannst du so etwas wie einen "Clipping-Node" darüberlegen? Was genau ist das Canvas? Doch nur der "Fortschritt"-Balken, oder?

Du könntest dem Layout, dass das Canvas enthält, einen (Rectangle) Clipping-Node überstülpen, das die abgerundeten Ecken erzeugt, während dein Canvas einfach nur die beiden Rectangles (mit "eckigen" Ecken), entsprechend ihrer Grösse, enthält.
Hast du schon mal Clipping ausprobiert? Ich hab es vor einiger Zeit mal, als hier im Forum die Frage, für die das ebenfalls prädestiniert war, aufgekommen ist.
 

Thallius

Top Contributor
Bis jetzt wußte ich noch gar nicht, dass es ein Clipping gibt. Habe es gerade mal überflogen und ich denke wenn das performant genug ist sollte das mein Problem lösen.

Gruß

Claus
 

Thallius

Top Contributor
So,

es hat also super funktioniert mit dem Clipping. Wer das auch mal braucht:

Code:
        Shape roundRectangle = new RoundRectangle2D.Float(0, 0, w, h, 10, 10);
        g.setClip(roundRectangle);

        GradientPaint gp = new GradientPaint(0, 0, data.topColor, 0, h, data.bottomColor);
        g2d.setPaint(gp);
        g2d.fillRect(0, 0, w, h);

        gp = new GradientPaint(0, 0, travelData.topColor, 0, h, travelData.bottomColor);
        g2d.setPaint(gp);
        if(toTravel > 0)
            g2d.fillRect(0, 0, toTravel, h);
        if(fromTravel > 0)
            g2d.fillRect(w - 1 - fromTravel, 0, fromTravel, h);

        g.setClip(null);
        g2d.setColor(GlobalSettings.jobViewBorderColor);
        g2d.drawRoundRect(0, 0, w - 1, h - 1, 10, 10);

Gruß

Claus
 

Thallius

Top Contributor
Ich habe gerade aber noch eine Kleinigkeit herausgefunden die wahrscheinlich auch für andere Interessant ist.

Ich zeichne in den ViewPort eine JScrollPane, welche ColumnHaeder- und RowHeaderViews hat. In meinem Beispiel zeichne ich dann über diese Views hinaus. Man muss also explizit alle Clippings setzen und auch wieder löschen.

Code:
        Rectangle rect = g.getClipBounds();
        Shape roundRectangle = new RoundRectangle2D.Float(0, 0, w, h, 10, 10);
        g2d.setClip(roundRectangle);
        g2d.clip(rect);

---- hier zeichnen

       g2d.setClip(rect);

Gruß

Claus
 

Ähnliche Java Themen

Neue Themen


Oben