Multidesk.be » Forums » Java » vertraging in tekenapplicatie

  • Pagina
  • 1 van 1
0 gasten lezen dit onderwerp.
^ Onderwerp geschreven door Simon op vrijdag 16 oktober 2009 om 17:09:09.
Simon's avatar
Multiviteit: 3742
Voor het vak beginselen van programmeren moesten we in de oefenzitting een applicatie schrijven waarin vierkanten getekend worden. Aan de uitvoerder wordt de zijde en de schaalfactor van het vierkant gevraagd. Er worden een reeks vierkanten getekend waarbij het volgende telkens zijn vier hoekpunten op de zijde van het vorige vierkant heeft (daarvoor is de schaalfactor gebruikt).
Nu heb ik dit allemaal kunnen verwezenlijken, maar ik krijg toch niets te zien. Volgens de assistent komt dit doordat er een soort vertraging (hij noemde het delay) ingebouwd moest worden omdat er vlugger getekend wordt dan dat het venster gegenereerd wordt. Met als gevolg dat ik dus niets zie. Met de berekeningen zelf is niets mis, alleen weet ik niet hoe ik die delay moet inbouwen. Die zou moeten komen voor regel 38 in de klasse main dacht ik.

Klasse Main:
CODE
  1.  
  2. import javax.swing.*;
  3. import java.awt.*;
  4.  
  5. public class Main
  6. {       
  7.         public static void main(String[] args)
  8.         {
  9.                 //we vragen aan de gebruiker wat de zijde en de schaalfactor is
  10.                 String zijde = JOptionPane.showInputDialog("Geef de zijde van het eerste vierkant op");
  11.                 int zijde_parsed = Integer.parseInt( zijde );
  12.                
  13.                 String schaalfactor = JOptionPane.showInputDialog("met welke factor moeten de vierkanten geschaald worden?");
  14.                 int schaalfactor_parsed = Integer.parseInt( schaalfactor );
  15.                
  16.                 //nieuwe drihoek met hoogte 5
  17.                 Fractal fractal = new Fractal( schaalfactor_parsed, zijde_parsed );
  18.                
  19.                 //als de zijde kleiner is dan 5 geven we een foutmelding
  20.                 if( fractal.getZijde() <= 5 )
  21.                 {
  22.                         JOptionPane.showMessageDialog( null, "De zijde van het vierkant moet groter zijn dan 5!" );
  23.                 }
  24.                 else
  25.                 {
  26.                         //hoogte en breedte is de zijde van het vierkant
  27.                         int zijde_venster = (int)fractal.getZijde();
  28.                        
  29.                         //nieuw venster creŽren met de vierkanten
  30.                         JFrame venster = new JFrame( "mini-fractal" );
  31.                         venster.setSize( zijde_venster, zijde_venster );
  32.                         venster.setLocation( 300, 300 );
  33.                         venster.setVisible( true );
  34.                        
  35.                         Container contentPane = venster.getContentPane();
  36.                         contentPane.setBackground( Color.white );
  37.                        
  38.                         //we roepen de functie aan die de fractals tekent
  39.                         fractal.tekenFractal( contentPane.getGraphics() );
  40.                 }
  41.         }
  42. }
  43.  


Klasse Fractal:
CODE
  1.  
  2. import java.awt.*;
  3.  
  4. //klasse die een mini fractal met vierkanten maakt
  5. public class Fractal
  6. {
  7.         //aantal getallen
  8.         int schaalfactor;
  9.         double zijde;
  10.         int[][] punt = new int[4][2];
  11.                
  12.         //constructor
  13.         public Fractal( int schaalfactor, int zijde )
  14.         {
  15.                 this.schaalfactor = schaalfactor;
  16.                 this.zijde = zijde;
  17.                
  18.                 //we geven een initiŽle waarde aan de punten aan de hand van de gegeven zijde
  19.                 //x1, y1
  20.                 punt[0][0] = 0;
  21.                 punt[0][1] = zijde;
  22.                 //x2, y2
  23.                 punt[1][0] = zijde;
  24.                 punt[1][1] = zijde;
  25.                 //x3, y3
  26.                 punt[2][0] = zijde;
  27.                 punt[2][1] = 0;
  28.                 //x4, y4
  29.                 punt[3][0] = 0;
  30.                 punt[3][1] = 0;
  31.         }
  32.        
  33.         //methoden
  34.        
  35.         //geeft de zijde van het vierkant terug
  36.         public double getZijde()
  37.         {
  38.                 return zijde;
  39.         }
  40.        
  41.         //genereert de nieuwe coordinaat van een punt
  42.         private void nieuweCoordinaat( int indexpunt )
  43.         {
  44.                 //de index geeft mee welk punt aangepast moet worden
  45.                 //daarvoor berekenen we dan de nieuwe x en y
  46.                 int oude_x = punt[indexpunt][0];
  47.                 int oude_y = punt[indexpunt][1];
  48.                
  49.               //we bepalen het naburige punt
  50.               int x2 = punt[(indexpunt+1)%4][0];
  51.               int y2 = punt[(indexpunt+1)%4][1];   
  52.              
  53.               //nieuwe x en y bepale
  54.                 punt[indexpunt][0] = oude_x + (x2 - oude_x)/schaalfactor;
  55.                 punt[indexpunt][1] = oude_y + (y2 - oude_y)/schaalfactor;
  56.         }
  57.        
  58.         //de zijde wordt herberekend
  59.         private void berekenZijde()
  60.         {
  61.                 //de zijde is wortel( (x2-x1)≤ + (y2-y1)≤ )
  62.                 double x1 = punt[0][0];
  63.                 double x2 = punt[1][0];
  64.                 double y1 = punt[0][1];
  65.                 double y2 = punt[1][1];
  66.                
  67.                 zijde = Math.sqrt( Math.pow( (x2-x1), 2 ) + Math.pow( (y2-y1), 2 ) );
  68.         }
  69.        
  70.         //tekent de fractal
  71.         public void tekenFractal( Graphics lijnen )
  72.         {
  73.                 //we maken een lus die stopt wanneer de zijde kleiner wordt dan 5
  74.                 //daarbinnen worden telkens de zijden van het vierkant getekend
  75.                 //en daarna worden de nieuwe punten bepaald
  76.                 for( int i = 0; zijde > 5; i ++)
  77.                 {
  78.                         //we tekenen de lijnen tussen de punten
  79.                         //x1, y1
  80.                         int x1 = punt[0][0];
  81.                         int y1 = punt[0][1];
  82.                         //x2, y2
  83.                         int x2 = punt[1][0];
  84.                         int y2 = punt[1][1];
  85.                         //x3, y3
  86.                         int x3 = punt[2][0];
  87.                         int y3 = punt[2][1];
  88.                         //x4, y4
  89.                         int x4 = punt[3][0];
  90.                         int y4 = punt[3][1];
  91.                        
  92.                         //lijn tussen x1 en x2
  93.                         lijnen.drawLine(x1, y1, x2, y2);
  94.                        
  95.                         //lijn tussen x2 en x3
  96.                         lijnen.drawLine(x2, y2, x3, y3);
  97.                        
  98.                         //lijn tussen x3 en x4
  99.                         lijnen.drawLine(x3, y3, x4, y4);
  100.                        
  101.                         //lijn tussen x4 en x1
  102.                         lijnen.drawLine(x1, y1, x4, y4);
  103.                        
  104.                         //daarna bepalen we de nieuwe punten
  105.                         nieuweCoordinaat( 0 ); //voor 1
  106.                         nieuweCoordinaat( 1 ); //voor 2
  107.                         nieuweCoordinaat( 2 ); //voor 3
  108.                         nieuweCoordinaat( 3 ); //voor 4
  109.                        
  110.                         //en we zorgen dat de zijde van het VOLGENDE vierkant berekend wordt
  111.                         //dit is zo omdat de punten al gewijzigd zijn
  112.                         berekenZijde();
  113.                 }
  114.         }
  115. }
  116.  
^ Reactie #1 geschreven door SMG op vrijdag 16 oktober 2009 om 22:39:20.
SMG's avatar
Multiviteit: 12000
Moderator
Om een code gewoon te laten wachten heb je sleep, maar ik vrees ervoor dat dit je zal helpen. Hiermee gaat er echt niets meer gebeuren (en zal je code dus gewoon wachten totdat de tijd verlopen is).
CODE
  1. try {
  2.             Thread.currentThread().sleep(1000);
  3.         } catch (InterruptedException ex) {
  4.             Logger.getLogger(Driver.class.getName()).log(Level.SEVERE, null, ex);
  5.         }

Dit zal de huidige thread gewoon laten slapen voor 1000 milliseconden. Je kan dit eender waar in je code zetten.
Op de try en catch blokken moet je niet echt letten, dit moet gewoon in zulke blokken want dit wordt aangezien als risicovolle code :p

Ik heb het wel even rap getest in je code en in regel 38 moet het alvast niet (als het er al in moet :D).
Deze tekst werd het laatst bewerkt voor 10.93 % door SMG op vrijdag 16 oktober 2009 om 22:45:03.
^ Reactie #2 geschreven door NightCreature op zaterdag 17 oktober 2009 om 00:45:55.
NightCreature's avatar
Multiviteit: 1196
MSc.
Wat je wil is een double buffer systeem gebruiken. Ale je teken instructies gaan naar de buffer die niet op het beeld getoont wordt. Wanneer je klaar bent met teken dan wissel je de buffers en wordt je plaatje weergegeven, terwijl je je volgende afbeelding in de buffer tekent die eerst op het scherm werd getoont.

Alle render applicaties werken op een dergelijken manier en meeste UI van programmas zijn ook double buffered om flikkering te voorkomen.

Die laatste for lus zou trouwens netter zijn als een while loop omdat je niet weet hoe vaak die lus uitgevoerd wordt.
for loops zijn voor iteraties waarbij je weet hoeveel keer je die wil doen, while is een lus om te itereren tot een bepaalde conditie vervuld is.

Roep deze functie van je contentPane eens aan public void paint(Graphics g)
Deze tekst werd het laatst bewerkt voor 5.18 % door NightCreature op zaterdag 17 oktober 2009 om 00:55:03.
I need thought completion.
Shaders, een beetje vreemd maar wel lekker (voor de ogen dan he)
2.83Ghz Q9550 HD4850 512MiB 4GiB 1333Mhz DDR3 RAM
http://paulintheuk.blogspot.com
FE Programmer @ Codemasters (Front End)
^ Reactie #3 geschreven door Simon op woensdag 21 oktober 2009 om 19:23:14.
Simon's avatar
Multiviteit: 3742
Ik denk dat die buffer systemen nog een beetje te ver gaan voor mij. Ik ben slechts een beginneling.

Nu, in school werkte het programma niet. Hier thuis wel, ook zonder de sleep enz. (dus met de code hierboven). Maar er klopt iets niet met mijn fractalen. Met beginzijde 500 en schaalfactor 4 krijg ik dit resultaat.
Bijlage:
http://www.multidesk.be/bijlage/9c4751e6545979943bc820c9908b1d11.png

Zoals je kan zien ontbreken er enkele lijnen en er loopt iets mis met het tekenen, want op geen enkel moment wordt ook maar 1 vierkant getekend (enkel vierhoeken). Komt dit nu door het feit dat er toch een probleem is met die tijd enzo? Of is mijn code verkeerd?

**EDIT**
Probleem zit waarschijnlijk in het feit dat de punten berekend worden als int en na enkele delingen zullen de precieze punten geen integers meer zijn natuurlijk maar decimale getallen. Maarja, ik kan niet anders dan integers gebruiken aangezien drawLine integers als argumenten vraagt.
Deze tekst werd het laatst bewerkt voor 17.81 % door Simon op woensdag 21 oktober 2009 om 19:36:58.
^ Reactie #4 geschreven door NightCreature op woensdag 21 oktober 2009 om 23:34:48.
NightCreature's avatar
Multiviteit: 1196
MSc.
Ten eerste gooi int[][] punt = new int[4][2]; eens weg en gebuik Point[] punt = new Point[4]; Dit maakt je code een stuk makkelijker om te lezen. Dan weet je meteen dat dat array een punten array is.

Hoogst waarschijnlijk wordt je lijn niet getekend omdat deze buiten het panel valt waarop je aan het tekenen bent.

En waarom je vierkant verminkt wordt is omdat je eerst punt 1 berekent en wegschrijft in het array. Als we dan het nieuwe punt voor 4 gaan berekenen gebruik je de nieuwe waarde voor punt 1 en niet de oude waarde die je zou moeten gebruiken. Ik had dat eerder moeten zien maar vandaag moest ik je programma zelf implementeren om te debuggen en het dan te zien lol.

C# oplossing
CODE
  1.  
  2. class RectangleFractal
  3. {
  4.     public RectangleFractal(float scaleFactor, int sideSize)
  5.     {
  6.         m_scaleFactor = scaleFactor;
  7.         m_sideSize = sideSize;
  8.         m_corners = new PointF[4];
  9.         m_corners[0] = new PointF(0.0f, 0.0f);
  10.         m_corners[1] = new PointF((float)sideSize, 0.0f);
  11.         m_corners[2] = new PointF((float)sideSize, (float)sideSize);
  12.         m_corners[3] = new PointF(0.0f, (float)sideSize);
  13.     }
  14.  
  15.     private void GenerateNewCoordinates()
  16.     {
  17.         PointF[] oldValues = new PointF[4];
  18.         for(int counter = 0; counter < m_corners.Length; ++counter)
  19.         {
  20.             oldValues[counter] = new PointF(m_corners[counter].X, m_corners[counter].Y);
  21.          }
  22.  
  23.          for (int counter = 0; counter < m_corners.Length; ++counter)
  24.         {
  25.             m_corners[counter].X = oldValues[counter].X + (oldValues[(counter + 1) % 4].X - oldValues[counter].X) / m_scaleFactor;
  26.             m_corners[counter].Y = oldValues[counter].Y + (oldValues[(counter + 1) % 4].Y - oldValues[counter].Y) / m_scaleFactor;
  27.         }
  28.     }
  29.  
  30.     private void RecalculateSideSize()
  31.     {
  32.         m_sideSize = (m_corners[1].X - m_corners[0].X) * (m_corners[1].X - m_corners[0].X) + (m_corners[1].Y - m_corners[0].Y) * (m_corners[1].Y - m_corners[0].Y);
  33.     }
  34.  
  35.     public void DrawFractal(Graphics g)
  36.     {
  37.         while (m_sideSize > 5)
  38.         {
  39.             Pen pen = new Pen(Color.Black, 1.0f);
  40.             g.DrawLine(pen, m_corners[0], m_corners[1]);
  41.             g.DrawLine(pen, m_corners[1], m_corners[2]);
  42.             g.DrawLine(pen, m_corners[2], m_corners[3]);
  43.             g.DrawLine(pen, m_corners[3], m_corners[0]);
  44.  
  45.             Console.WriteLine("Rectangle Data");
  46.              foreach (PointF p in m_corners)
  47.             {
  48.                 Console.WriteLine(p);
  49.             }
  50.             Console.WriteLine("---------------------------");
  51.  
  52.             GenerateNewCoordinates();
  53.  
  54.             RecalculateSideSize();
  55.         }
  56.     }
  57.  
  58.     private float m_scaleFactor;
  59.     private float m_sideSize;
  60.     private PointF[] m_corners;
  61. }
  62.  


De foreach lus staat er enkel in zodat ik kan zien hoe de waardes veranderen iedere iteration van de while lus. Daardoor zag ik dus ook dat de berekening voor punt 4 na de eerste lus fout was.
Deze tekst werd het laatst bewerkt voor 3.21 % door NightCreature op woensdag 21 oktober 2009 om 23:59:12.
I need thought completion.
Shaders, een beetje vreemd maar wel lekker (voor de ogen dan he)
2.83Ghz Q9550 HD4850 512MiB 4GiB 1333Mhz DDR3 RAM
http://paulintheuk.blogspot.com
FE Programmer @ Codemasters (Front End)
^ Reactie #5 geschreven door Simon op zondag 25 oktober 2009 om 14:50:10.
Simon's avatar
Multiviteit: 3742
Bedankt, mijn fout zat inderdaad in de berekening.
Ik heb het met succes kunnen aanpassen :).

Ik heb het nog eens gevraagd en blijkbaar moest het toch met een soort van vertraging gebeuren.
Met deze code op regel 38 in de main werkt alles goed:
CODE
  1.  
  2. try
  3.                         {
  4.                                 Thread.sleep(1000);
  5.                         }
  6.                         catch(Exception e)
  7.                         {
  8.                         }
  9.  
^ Reactie #6 geschreven door NightCreature op zondag 25 oktober 2009 om 17:08:37.
NightCreature's avatar
Multiviteit: 1196
MSc.
Thread.Sleep hoef je niet tussen een try catch te zetten als een thread niet kan slapen is er iets mis in je applicatie.
I need thought completion.
Shaders, een beetje vreemd maar wel lekker (voor de ogen dan he)
2.83Ghz Q9550 HD4850 512MiB 4GiB 1333Mhz DDR3 RAM
http://paulintheuk.blogspot.com
FE Programmer @ Codemasters (Front End)
  • Pagina
  • 1 van 1

Snel-antwoordformulier
Toon uitgebreid antwoordformulier Bericht nalezen Bericht plaatsen