Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 16

Discussione: Paint e virgola mobile

  1. #1
    Utente di HTML.it
    Registrato dal
    Mar 2009
    Messaggi
    174

    Paint e virgola mobile

    Ciao a tutti. In Java sto creando un mio controllo grafica estendendo la classe JComponent; in particolare sto realizzando una chunkbar (quella che mostra l'avanzamento di un download come ad esempio in uTorrent e fratelli), ma ho un problema qnd faccio il resize del frame.

    codice:
    @Override
        public void paint(Graphics graphics) {
            Graphics2D graphics2d = (Graphics2D) graphics;
            graphics2d.drawRect(0, 0, width - 1, height - 1);
            graphics2d.setColor(new Color(0, 0, 255));
    
            for (int i = 0; i < numOfchunks; i++) {
                if (chunks[i]) {
                    graphics2d.fillRect(i * chunkWidth + 1, 1, chunkWidth + 2, height - 2);
                }
            }
        }
    fillRect accetta come parametri (chunkWidth) degli interi, ma qst mi causa il seguente problema solo con multipli interi mi vengono disegnati/dimensionati correttamente i quadratini dei chunk altrimenti la barra contiene degli spazi vuoti. Forse un'immagine vale più di mille parole: sopra come dovrebbe visualizzarla, sotto cosa succede in realtà. Il problema è dovuto all'arrotondamento, sapete come posso risolvere il problema?
    Immagini allegate Immagini allegate

  2. #2
    Moderatrice di Grafica, Cerco e offro lavoro L'avatar di Myaku
    Registrato dal
    Nov 2006
    Messaggi
    10,349
    sposto


  3. #3
    Utente di HTML.it
    Registrato dal
    Mar 2009
    Messaggi
    174
    Grazie Myaku, scusate se ho postato nel punto sbagliato e anche se si trattava di programmazione in Java visto che c'era di mezzo la grafica... la prossima volta saprò cosa fare

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284

    Re: Paint e virgola mobile

    Originariamente inviato da Hermiod
    In Java sto creando un mio controllo grafica estendendo la classe JComponent
    Allora innanzitutto dovresti fare l'override di paintComponent(), non di paint().
    In Swing le cose sono un po' diverse, lo spiega anche il tutorial: A Closer Look at the Paint Mechanism

    Originariamente inviato da Hermiod
    in particolare sto realizzando una chunkbar (quella che mostra l'avanzamento di un download come ad esempio in uTorrent e fratelli), ma ho un problema qnd faccio il resize del frame.

    fillRect accetta come parametri (chunkWidth) degli interi, ma qst mi causa il seguente problema solo con multipli interi mi vengono disegnati/dimensionati correttamente i quadratini dei chunk altrimenti la barra contiene degli spazi vuoti.
    Nel paintComponent() dovresti usare getWidth()/getHeight() per ottenere la dimensione corrente del componente e basarti su queste dimensioni per calcolare le posizioni/dimensioni dei chunk (sapendo ovviamente a priori quanti sono!).

    E se vuoi fare le cose in modo accurato, usa la classe Rectangle2D.Float per definire in modo preciso il rettangolo e attiva anche l'anti-aliasing, così se ti viene fuori, per esempio, un rettangolo con x=10, y=10, w=10.5, h=20, allora il bordo destro lo ottieni "sfumato" come se fosse di "mezzo" pixel, appunto.

    E infine, ti conviene gestire la indicazione di on/off dei chunk in modo "furbo", ad esempio con java.util.BitSet e usare i suoi metodi per andare a cercare le sequenze di "on" contigui da disegnare come unità singola.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Utente di HTML.it
    Registrato dal
    Mar 2009
    Messaggi
    174
    Grazie mille andbin era proprio la dritta che cercavo, non appena mi rimetto al progetto (fra una mezz'oretta metto in pratica ciò che mi hai suggerito, magari se ho qualche altro problemino so dove andare Grazie mille ragazzi!!! Siete una forza

  6. #6
    Utente di HTML.it
    Registrato dal
    Mar 2009
    Messaggi
    174
    Ciao andbin, scusa se ti disturbo! Tu dici di usare la classe Rectangle2D.Float, ma non ne vengo a capo nonostante sono d'accordo con te per avere una maggiore precisione. Io faccio così, dove sbaglio?

    codice:
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.drawRect(0, 0, width-1, height-1);
        g2d.setColor(new Color(0, 0, 255));
        Rectangle2D.Float chunk = new Rectangle2D.Float(x, y, width, height);
        for (int i = 0; i < chunks.size(); i++) {
            if (chunks.get(i))
                g2d.fillRect(chunk.x, y, width, height);
        }
    }
    e giustamente la fillRect accetta solo int mentre chunk.x è un float
    PS: il codice che ho postato è a titolo di esempio, sistemo dopo...

  7. #7
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Hermiod
    Io faccio così, dove sbaglio?
    No, proprio sbagliato.

    Innanzitutto non vedo i calcoli necessari a determinare il rettangolo per ognuno dei "chunk". Ossia: dato il "width" complessivo a disposizione per i chunk e dato il numero totale di chunk, per il chunk i-esimo, devi calcolarne la sua posizione x (y/height sono fissi dato che la barra è orizzontale, mentre il width del chunk è calcolato dai 2 dati iniziali che ho detto).

    Inoltre, se guardi, Rectangle2D.Float è-un Shape (implementa appunto la interfaccia Shape) ...... e Graphics2D ha un metodo fill(Shape). Quindi cosa ne deduci?

    Tralasciamo per il momento ottimizzazioni varie tipo l'uso di BitSet e il disegno "in blocco" di chunk "on" contigui .....
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  8. #8
    Utente di HTML.it
    Registrato dal
    Mar 2009
    Messaggi
    174
    andbin te l'avevo detto che era un codice orientativo, forse non mi ero espresso bene: qll che intendevo era quale metodo mi permetteva di disegnare un rettangolo che avesse come vertici dei float Cmq adesso ho risolto e il tutto si comporta bene secondo le mie aspettative anzi posto il codice così se magari serve a qualcun'altro...

    codice:
    package chunkbar;
    
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Rectangle;
    import java.awt.RenderingHints;
    import java.awt.geom.Rectangle2D;
    import java.util.BitSet;
    import javax.swing.JComponent;
    
    public class ChunkBar extends JComponent {
    
        private int numOfChunks;
        private BitSet chunks;
        private int x;
        private int y;
        private int width;
        private int height;
    
        public ChunkBar() {
            numOfChunks = 0;
            chunks = new BitSet(numOfChunks);
            x = 0;
            y = 0;
            width = 100;
            height = 20;
        }
    
        public void setup(int numOfChunks) {
            this.numOfChunks = numOfChunks;
            chunks = new BitSet(numOfChunks);
        }
    
        public void setChunk(int index) {
            chunks.set(index);
        }
    
        public double getRatio() {
            int availableChunks = 0;
            for (int i = 0; i < chunks.size(); i++) {
                if (chunks.get(i)) {
                    availableChunks++;
                }
            }
            double ratio = availableChunks / (double) numOfChunks * 100;
            return ratio;
        }
    
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.drawRect(0, 0, width - 1, height - 1);
            g2d.setColor(new Color(0, 0, 255));
            float chunkWidth = getWidth() / (float) numOfChunks;
            for (int i = 0; i < chunks.size(); i++) {
                if (chunks.get(i)) {
                    Rectangle2D.Float chunk =
                            new Rectangle2D.Float(i*chunkWidth, 1, chunkWidth+1, height-2);
                    g2d.fill(chunk);
                }
            }
        }
    
        @Override
        public int getX() {
            return x;
        }
    
        @Override
        public int getY() {
            return y;
        }
    
        @Override
        public int getWidth() {
            return width;
        }
    
        @Override
        public int getHeight() {
            return height;
        }
    
        @Override
        public Rectangle getBounds() {
            return new Rectangle(x, y, width, height);
        }
    
        @Override
        public void setBounds(int x, int y, int width, int height) {
            this.x = x;
            this.y = y;
            this.width = width;
            repaint();
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(width, height);
        }
    
        @Override
        public void setPreferredSize(Dimension size) {
            this.width = size.width;
            this.height = size.height;
            repaint();
        }
    
        @Override
        public float getAlignmentX() {
            return x;
        }
    
        @Override
        public void setAlignmentX(float x) {
            this.x = (int) x;
            repaint();
        }
    
        @Override
        public float getAlignmentY() {
            return y;
        }
    
        @Override
        public void setAlignmentY(float y) {
            repaint();
            this.y = (int) y;
        }
    }
    Ah ovviamente tutti i ichunk sono della stessa dimensione a parte l'ultimo che può essere più piccolo: non ne tengo conto e approssimo considerandolo di dimensione pari agli altri! Grazie per l'aiuto se avete qualche altro suggerimento è ben accetto...

  9. #9
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Hermiod
    anzi posto il codice così se magari serve a qualcun'altro...
    Uhm .... vedendo il tuo codice mi sta venendo la sensazione che non hai compreso molto bene come si gestisce il painting e in generale i componenti.

    1) Tutti quei override di getX(), getWidth(), getBounds() ecc... in realtà non servirebbero affatto!!! E tantomeno i getAlignmentX() e getAlignmentY() ecc... (nota che questo "alignment" x/y NON è la posizione x/y del componente!!!)

    2) Se vuoi che il tuo componente abbia un certo preferred size di default (es. 100x20), basta che nel costruttore chiami setPreferredSize(new Dimension(100,20)). Lo "stato" ovvero i campi di istanza per gestire le dimensioni, li ha già java.awt.Component. Non hai bisogno di tenere tu dei campi di "rifare" quello che praticamente fa già il componente.

    3) I metodi che modificano i dati che rappresentano lo "stato" del tuo componente (es. il tuo setChunk() ), dovrebbero richiedere il repaint() alla fine ..... altrimenti come pensi che si possa aggiornare visivamente il componente?

    4) La 'x' del rettangolo dovrebbe essere i*chunkWidth+1, altrimenti vai sopra il bordo e la width dovrebbe essere solo chunkWidth, senza il +1.
    Come ottimizzazione, potresti istanziare nel paintComponent() solo 1 Rectangle2D.Float e cambiargli solo la 'x' ogni volta (che è appunto l'unica variabile), piuttosto di istanziare N Rectangle2D.Float.

    5) Se vuoi sapere quanti bit "true" ci sono nel BitSet, basta usare cardinality()


    Ultima cosa: nel paintComponent() imponi tu un bordo e il colore blu della barra. Questo non è sbagliato di per sé .... è solo molto limitato. Se questo componente lo usi solo tu e per un preciso scopo .... ok. Giusto per tua conoscenza, se volessi fare un qualcosa di più generico, potresti sfruttare la proprietà di "foreground" già presente nei componenti e anche la proprietà "border". Nel paintComponent dovresti quindi usare getForeground() per il colore e usare getInsets() per sapere di quanto "rientrare" per non toccare il bordo che poi verrà disegnato in base al Border del componente. Questo è molto più flessibile, ovviamente.
    Ma la flessibilità dipende da cosa devi fare e vuoi offrire tu ....
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  10. #10
    Utente di HTML.it
    Registrato dal
    Mar 2009
    Messaggi
    174
    Beh
    1) ho aggiunto tutti quei set/get per poter integrare il componente in NetBeans, altrimenti non riuscivo a gestirlo nel form editor... Mi ero scordato di scriverlo.
    2) anche qui gestisco il resizing da NetBeans...
    3) il componente essendo inserito in un container (JPanel) una volta invalidato il frame principale viene effettuato il repaint di tutti gli altri componenti, cmq faccio anche un repaint qnd setto un nuovo chunk: non capisco come mai se metto il repaint nel metodo setChunk mi viene ignorato invece se lo metto dopo la sua invocazione funziona correttamente... non mi voglio scervellare per qst sto facendo un progetto i cui scopi sono ben altri VVoVe:
    4) ok infatti, non mi ero accorto per lo stesso motivo del punto di prima: altri scopi
    5) non ho mai usato questa classe e non mi andava di spulciare nelle API cmq grazie...
    Per il resto terrò conto dei tuoi suggerimenti, ma come migliorie da apportare...
    Immagini allegate Immagini allegate

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.