Si a me non interessa che si crei ogni volta di nuovo anzi , l'importante è che me lo crei la prima volta, al dire il vero credevo che lo facesse già.per quello che dici tu come dovrei muovermi o meglio cosa dovrei cambiare?
Si a me non interessa che si crei ogni volta di nuovo anzi , l'importante è che me lo crei la prima volta, al dire il vero credevo che lo facesse già.per quello che dici tu come dovrei muovermi o meglio cosa dovrei cambiare?
No purtroppo non lo fa.Il metodo paintComponent non viene eseguito una sola volta e non sei tu a richiamarlo (sebbene tu ne possa forzare la chiamata applicando al componente il metodo repaint(), che internamente fa alcune cose e poi lo invoca).
Il metodo è richiamato in automatico tutte le volte che ce n'è bisogno, quindi non solo alla creazione del pannello, ma anche quando l'interfaccia "si accorge" che c'è stato un cambiamento, ad esempio se la ridimensioni o, come nel nostro caso, se ti muovi con le scrollbar nello scrollpane.
Per quello l'esecuzione è lenta: ogni movimento che fai richiama il metodo con tutte le milioni di operazioni da rieseguire ogni volta.
Se utilizzi un'immagine al posto di disegnare direttamente sul pannello, a questo punto puoi crearla una sola volta, all'inizio dell'esecuzione.per quello che dici tu come dovrei muovermi o meglio cosa dovrei cambiare?
Il codice non è da modificare in massa, perché basta fare quello che tu fai all'interno del paintComponent da un'altra parte.
Ecco un esempio:
Con questo codice stai creando una BufferedImage (che dichiari come variabile della classe perché sia visibile all'interno del paintComponent), "prendi la grafica" dell'immagine e disegni tutto al suo interno, al posto di farlo nel Graphics del paintComponent, che viene applicato al pannello.codice:public void createFractalImage() { image=new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB); Graphics g=image.getGraphics(); for(int i=-h;i<h;i++) { for(int y=-w;y<w;y++) { double a=(double)i/(h/2); double b=(double)y/(w/2); int c=funz(a,b); if(c==ite) { g.drawLine(i+h,y+w,i+h,y+w); g.setColor(Color.black); } else { g.setColor(colors[c%16]); g.drawLine(i+h,y+w,i+h,y+w); } } } }
Ora basta richiamare il metodo una volta sola, nel costruttore dopo aver definito i colori, mentre il metodo paintComponent diventa molto più snello: infatti deve solo disegnare l'immagine già creata, e tutte le volte che verrà richiamato (quando ti sposti con le scrollbar), non fa altro che visualizzare la porzione "giusta" dell'immagine:
Come detto a questo punto puoi sbizzarrirti su quante immagini creare e come sostituirle, hai un sacco di possibilità e l'esecuzione prende tempo solo alla creazione dell'immaginecodice:protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(image,0,0,null); }![]()
cosa sbaglio?'
mi disegna solo una parte
codice:import java.awt.Canvas; import java.awt.Color; import java.awt.Graphics; import java.util.Random; import java.awt.Color; import java.io.*; import java.util.*; import javax.swing.JFrame; import java.awt.Graphics; import java.awt.Graphics2D; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JComponent; import java.awt.Dimension; import java.awt.Image; import java.awt.image.BufferedImage; import javax.imageio.ImageIO; public class PixelCanvas extends JPanel { public static Color colore2(int c) { Color f; if (c < 64) { return f = new Color(c * 2, 0, 0); } else if (c < 128) { return f = new Color((((c - 64) * 128) / 126) + 128, 0, 0); /* 0x0080 to 0x00C0 */ } else if (c < 256) { return f = new Color((((c - 128) * 62) / 127) + 193, 0, 0); /* 0x00C1 to 0x00FF */ } else if (c < 512) { return f = new Color(255, (((c - 256) * 62) / 255) + 1, 0); /* 0x01FF to 0x3FFF */ } else if (c < 1024) { return f = new Color(255, (((c - 512) * 63) / 511) + 64, 0); /* 0x40FF to 0x7FFF */ } else if (c < 2048) { return f = new Color(255, (((c - 1024) * 63) / 1023) + 128, 0); /* 0x80FF to 0xBFFF */ } else if (c < 4096) { return f = new Color(255, (((c - 2048) * 63) / 2047) + 192, 0); /* 0xC0FF to 0xFFFF */ } return f = new Color(255, 255, 0); } public static double[] quad(double a, double b) { double z = Math.pow(a, 2) - Math.pow(b, 2); double z1 = 2 * a * b; double z2[] = {z, z1}; return z2; } public int funz(double a, double b) { double re = a, co = b; a = 0; b = 0; int c = 0; while (Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)) < 2 && c < ite) { double v[] = quad(a, b); double z1 = (v[0] + re); double z2 = (v[1] + co); a = z1; b = z2; c++; } return c; } Scanner in = new Scanner(System.in); public final int ite = Integer.parseInt(in.next()); public static final int WIDTH = 1000; public static final int HEIGHT = 1000; BufferedImage image; int w = WIDTH / 2; int h = HEIGHT / 2; public PixelCanvas() { setPreferredSize(new Dimension(WIDTH,HEIGHT)); createFractalImage(); } protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(image,0,0,null); } public void createFractalImage() { Color [] colore=new Color[16]; colore[0]=new Color(66, 30, 15); colore[1]=new Color(25, 7, 26); colore[2]=new Color(9, 1, 47); colore[3]=new Color(4, 4, 73); colore[4]=new Color(0, 7, 100); colore[5]=new Color(12, 44, 138); colore[6]=new Color(24, 82, 177); colore[7]=new Color(57, 125, 209); colore[8]=new Color(134, 181, 229); colore[9]=new Color(211, 236, 248); colore[10]=new Color(241, 233, 191); colore[11]=new Color(248, 201, 95); colore[12]=new Color(255, 170, 0); colore[13]=new Color(204, 128, 0); colore[14]=new Color(153, 87, 0); colore[15]=new Color(106, 52, 3); image=new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB); Graphics g=image.getGraphics(); for(int i=-h;i<h;i++) { for(int y=-w;y<w;y++) { double a=(double)i/(h/2); double b=(double)y/(w/2); int c=funz(a,b); if(c==ite) { g.drawLine(i+h,y+w,i+h,y+w); g.setColor(Color.black); } else { g.setColor(colore[c%16]); g.drawLine(i+h,y+w,i+h,y+w); } } } } public static void main(String[] args) { System.out.println("Inserire numero di iterzioni"); JPanel jp = new JPanel(); JScrollPane pane = new JScrollPane(new PixelCanvas(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); JFrame frame = new JFrame(); frame.setSize(1000,1000); frame.setContentPane(pane); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
ho risolto mettendo al posto di w,h width e height
codice:image=new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_ARGB); Graphics g=image.getGraphics();
Ma se creo un immagine settando l'altezza e la lunghezza sopra i 20000 mi da
codice:Exception in thread "main" java.lang.NegativeArraySizeException at java.awt.image.DataBufferInt.<init>(DataBufferInt.java:75) at java.awt.image.Raster.createPackedRaster(Raster.java:467) at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1032) at java.awt.image.BufferedImage.<init>(BufferedImage.java:333) at PixelCanvas.createFractalImage(PixelCanvas.java:121) at PixelCanvas.<init>(PixelCanvas.java:92) at PixelCanvas.main(PixelCanvas.java:158)
Questo non saprei, prova con una ricerca in internet,se ricopi la tua eccezione viene fuori qualcosa, ad esempio qui:
http://stackoverflow.com/questions/9...-bufferedimage
Ad ogni modo ho riscritto il tuo codice facendo un esempietto un po' più completo e correggendo qualcosa qua e là, non è ancora il massimo, si potrebbe fare molto di più, ma intanto posto il codice, se vuoi provalo :
codice:import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.LayoutManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; public class MandelbrotFractal { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable(){ public void run(){ new MainFrame().setVisible(true); } }); } } class MainFrame extends JFrame { private FractalFrame fractalFrame; private JTextField iterationsField,widthField,heightField; public MainFrame() { super("Mandelbrot Fractal Painter"); setDefaultCloseOperation(EXIT_ON_CLOSE); setResizable(false); JPanel contentPane=new JPanel(new BorderLayout()); contentPane.setBackground(Color.WHITE); contentPane.setBorder(new EmptyBorder(10,10,10,10)); JPanel topPanel=new WhitePanel(contentPane,BorderLayout.NORTH,new FlowLayout(FlowLayout.CENTER,0,0)); JPanel centerPanel=new WhitePanel(contentPane,BorderLayout.CENTER,new FlowLayout(FlowLayout.CENTER,5,10)); JPanel bottomPanel=new WhitePanel(contentPane,BorderLayout.SOUTH,new FlowLayout(FlowLayout.CENTER,0,0)); topPanel.add(new JLabel("Inserisci il numero di iterazioni e le dimensioni per l'immagine desiderati")); centerPanel.add(new JLabel("Iterazioni :")); centerPanel.add(iterationsField=new JTextField("200",5)); centerPanel.add(new JLabel("Lunghezza :")); centerPanel.add(widthField=new JTextField("500",5)); centerPanel.add(new JLabel("Altezza :")); centerPanel.add(heightField=new JTextField("500",5)); JButton button=new JButton("Ricrea pannello"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { int iterations=Integer.valueOf(iterationsField.getText()); int width=Integer.valueOf(widthField.getText()); int height=Integer.valueOf(heightField.getText()); if(iterations<0||width<0||height<0)throw new NumberFormatException(); if(fractalFrame!=null)fractalFrame.dispose(); (fractalFrame=new FractalFrame(iterations,width,height)).setVisible(true); } catch(NumberFormatException ex){ JOptionPane.showMessageDialog(MainFrame.this,"I parametri devono essere numeri interi non negativi!"); } } }); bottomPanel.add(button); setContentPane(contentPane); pack(); setLocationRelativeTo(null); } private class WhitePanel extends JPanel { public WhitePanel(JPanel parent,String position,LayoutManager layout) { super(layout); setBackground(Color.WHITE); parent.add(this,position); } } } class FractalFrame extends JFrame { public FractalFrame(int iterations,int width,int height) { super("Mandelbrot Fractal Frame"); setDefaultCloseOperation(DISPOSE_ON_CLOSE); setResizable(false); JScrollPane scroll=new JScrollPane(new FractalPanel(iterations,width,height)); scroll.setPreferredSize(new Dimension(Math.min(2*width,800),Math.min(2*height,800))); setContentPane(scroll); pack(); setLocationRelativeTo(null); } private class FractalPanel extends JPanel { private final int iter,w,h; private BufferedImage image; private Color[] colors; public FractalPanel(int iterations,int width,int height) { colors=new Color[]{ new Color(66,30,15),new Color(25,7,26),new Color(9,1,47),new Color(4,4,73),new Color(0,7,100),new Color(12,44,138),new Color(24,82,177),new Color(57,125,209), new Color(134,181,229),new Color(211,236,248),new Color(241,233,191),new Color(248,201,95),new Color(255,170,0),new Color(204,128,0),new Color(153,87,0),new Color(106,52,3) }; iter=iterations; w=width; h=height; createFractalImage(); setPreferredSize(new Dimension(2*w,2*h)); } public void createFractalImage() { image=new BufferedImage(2*w,2*h,BufferedImage.TYPE_INT_ARGB); Graphics g=image.getGraphics(); for(int i=-h;i<h;i++) { for(int y=-w;y<w;y++) { double a=(double)i/(h/2); double b=(double)y/(w/2); int c=funz(a,b); if(c==iter) { g.drawLine(i+h,y+w,i+h,y+w); g.setColor(Color.black); } else { g.setColor(colors[c%16]); g.drawLine(i+h,y+w,i+h,y+w); } } } } public double[] quad(double a,double b){ return new double[]{a*a-b*b,2*a*b}; } public int funz(double a,double b) { double re=a,co=b; a=0; b=0; int c=0; while(Math.sqrt(Math.pow(a,2)+Math.pow(b,2))<2 && c<iter) { double v[]=quad(a,b); double z1=(v[0]+re); double z2=(v[1]+co); a=z1; b=z2; c++; } return c; } protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(image,0,0,null); } } }
[EDIT]
Andrebbero rivisti un attimo w e h perché in realtà sono la semilunghezza e la semialtezza e anche lo scrollpane dovrebbe dimensionarsi un po' meglio...
Ultima modifica di Ansharja; 25-05-2016 a 15:46
Non so veramente come ringraziarti, magari potessi farlo anche io una roba del genere, starei a casa tutto il giorno a creare frattali.
da quello che ho capito l'errore che mi da è dato dal compilatore che data la troppa memoria occupata chiude il programma, in teoria si potrebbe evitare ,
Ok, cerca un po' se vuoi migliorare questo aspetto (io non ne so davvero nulla) ma hai davvero bisogno di una immagine di 20000*20000 ?
Prego, è stato un piacere
Riguardo al fatto di poterlo fare anche tu, beh io mi sono appassionato a swing poco più di un anno fa, perché volevo imparare a creare applicazioni per poter giocare a giochi come briscola,forza 4,campo minato,scacchi etc...
Ora vedo che mi piace creare qualsiasi tipo di applicazione, anche per gli scopi più stupidi (tipo calcolare i parziali intermedi dei tempi di quando vado a correre).
Se la cosa ti appassiona non c'è motivo di non riuscire a fare questo e molto di più, non sono mica un esperto![]()
si perchè, pur avendo scritto io il codice nn ho la minima idea di come creare una sola parte del piano cartesiano in quel modo a parità di grandezza avrei meno frattale ma più precisoOk, cerca un po' se vuoi migliorare questo aspetto (io non ne so davvero nulla) ma hai davvero bisogno di una immagine di 20000*20000 ?
Sarebbe interessante poter tramite il mouse cliccare sulla finestra e individuare un rettangolo e caricare nella finestra quel rettangolo ingrandito