Toon posts:

[Java] repaint te langzaam ???

Pagina: 1
Acties:

Verwijderd

Topicstarter
Eerst een stukje code ...
code:
1
2
3
4
5
6
7
public void loop()
{
    System.out.println("1");
    andereClass.repaint();
    System.out.println("3");
    loop();
}

Andere klasse ...
code:
1
2
3
4
5
public void paint(Graphics G)
{
    System.out.println("2");
    TekenNogWatDingen();
}

Nu is de output die ik krijg niet 1,2,3 ... maar 1,3,2 :?. Stel dat die loop 5x herhaald wordt dan is de output zelfs zo 1,3,1,3,1,3,1,3,1,3,2 ?!

Heeft iemand een hier een verklaring voor ? En hoe kan ik het voor elkaar krijgen dat de output altijd 1,2,3 is ?

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 12-09 21:31

Janoz

Moderator Devschuur®

!litemod

Dat komt omdat repaint alleen opdracht geeft om het scherm opnieuw te tekenen.. Waneer dit gebeurt is niet aan het geprogrammeerde programma, maar aan de window manager. Als je er echt 1,2,3 uit wil hebben komen zul bij de aanroep een boolean op fals moeten zetten, en deze in je paint methode aan het eind weer op true zetten. Na de repaint opdracht laat je je programma dan wachten tot die boolean true is voor je verder gaat (niet met een actieve wacht lus natuurlijk, maar gewoon met Thread.sleep(10) ofzo).. Het is geen nette oplossing, dus mischien moet je nog maar ff kijken of je iets in je programma ontwerp kunt wijzigen waardoor je niet tegen dit probleem aanloopt.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • GarBaGe
  • Registratie: December 1999
  • Laatst online: 15-09 21:48
Dit is allemaal mogelijk dankzij "multi-threading".

"It's a feature, not a bug" :)

Je moet synchronizen :)

Ryzen9 5900X; 16GB DDR4-3200 ; RTX-4080S ; 7TB SSD


  • Left
  • Registratie: Augustus 2001
  • Laatst online: 09-02 20:43
De paint() functie van een klasse wordt aangeroepen vanuit een aparte thread. En dan alleen als er iets veranderd is in de UI van die klasse.

Met repaint() kun je ervoor zorgen dat de volgende keer dat de paint-thread aan de beurt is, jouw klasse gepaint wordt ongeacht of er iets in zijn UI veranderd is. Het gebeurt dus niet onmiddellijk, maar pas de volgende keer dat de paint-thread weer aan de beurt is.

In jouw code zou je i.p.v. repaint() gewoon paint() aan kunnen roepen, dat zou het juiste resultaat moeten geven.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Misschien is het goed om even te vertellen waarom (en uberhaupt of) je zo graag 1,2,3 wilt?

Begreep je de volgorde alleen niet of heb je ook echt een probleem met deze volgorde?

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


Verwijderd

Topicstarter
Op zaterdag 19 januari 2002 15:47 schreef mbravenboer het volgende:
Misschien is het goed om even te vertellen waarom (en uberhaupt of) je zo graag 1,2,3 wilt?

Begreep je de volgorde alleen niet of heb je ook echt een probleem met deze volgorde?
Nee, het is echt een "probleem" waar ik mee zit. Voor de oplossing maakt het niet zo veel uit, daarom heb ik het er niet bij gezet. Maar hier dan wat achtergrond : De loop veranderd steeds de coordinaten van een figuur op het scherm, maar om er voor te zorgen dat de figuur niet in 1x bv 50 coordinaten verder is, maar ze allemaal 1 voor 1 afloopt (dit moet ook op het scherm te zien zijn), moet de volgorde van uitvoeren 1,2,3 zijn. Anders krijg je dus het effect dat de coordinaten wel 50x veranderd zijn, maar dat je het maar 1x op het scherm ziet, namelijk bij het eindpunt.

Het is ook geen oplossing voor mij om het met een Thread.sleep(xx) in de loop op te lossen, maar dat heeft weer een andere oorzaak. Ik wil het dus echt zo krijgen dat de volgorde van uitvoeren 1,2,3 is (zonder een thread te gebruiken).

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 12-09 21:31

Janoz

Moderator Devschuur®

!litemod

Ik denk dat je weinig opties hebt.. Je zult wel gebruik moeten maken van threads...

Zoals al eerder vermeld loopt je GUI in een andere thread dan je programma zelf. Waneer jij een loopje hebt zonder daarin een andere thread aan de beurt te laten wordt de gui dus nooit geupdate...

uit je verhaal hierboven maak ik op dat je een soort animatie wilt maken.. Zelf heb ik laatst iets vergelijkbaars gemaakt. Ik gebruikte een apparte thread die de positie bepaalde. Hierin zat een loopje die de positie update, repaint aanriep, 20ms wachte en weer terug...

Trouwens... Waarom roep je je loop in bovenstaand voorbeeld trouwens recursief aan? Er zijn nettere manieren dan een stackoverflow om programma's te laten stoppen :)

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Op zaterdag 19 januari 2002 15:36 schreef Zpeedy het volgende:
Eerst een stukje code ...
code:
1
2
3
4
5
6
7
public void loop()
{
    System.out.println("1");
    andereClass.repaint();
    System.out.println("3");
    loop();
}
dit is wel heel erg fout, zo heb je binnen de kortste keren een stack overflow (of juist een gigantische hoeveelheid geheugenverbruik)

Je roept de functie hier namelijk recursief aan. Veel beter kun je gewoon een oneindig lusje maken met
code:
1
2
3
4
while (true)
{
   ...
}

.edit: wat janoz al zei dus :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • tomato
  • Registratie: November 1999
  • Niet online
Janoz: Er zijn nettere manieren dan een stackoverflow om programma's te laten stoppen :)
LOL :D

Verwijderd

Topicstarter
Op zaterdag 19 januari 2002 17:43 schreef Janoz het volgende:
Trouwens... Waarom roep je je loop in bovenstaand voorbeeld trouwens recursief aan? Er zijn nettere manieren dan een stackoverflow om programma's te laten stoppen :)
I know ... dit was alleen maar een voorbeeld (heeft ook voor de rest niets met het probleem te maken).

BTW, zoals iemand hier voorstelde om paint() ipv repaint() aan te roepen, zal in mijn geval niet werken omdat je bij een paint een Graphics object moet meegeven en die is in mijn geval niet bekend bij de klasse die de repaint aanroept.

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 03-09 16:40
En nu de vraag waarom die maar 1x door die paint gaat.

Wat is het nut van een oude paint opdracht uitvoeren als de volgende al klaar staat, en de volgende en de volgende en de volgende ...

De VM weet dit en reageert dus alleen op de laatste paint. Zeer waarschijnlijk wil de VM net de paint gaan uitvoeren en dan krijgt de VM alweer de volgende paint.

Wat jij ziet als een bug is in feite een hele goede optimalisatie van java. Why bother met tekenen als je al weet wat je erna moet tekenen? Je weet dat IO een dure operatie is mag ik aannemen.

Je mag ook NOOIT zaken uitvoeren in je paint methode die je gegarandeerd zovaak uitgevoerd wil hebben als dat je repaint.

Nu de laatste vraag, hoe zorg je dat wel alle stappen gepaint worden? Simpel... Kijk in de java API maar is bij repaint, welke methode wordt zo snel als mogelijk aangeroepen? Yup, "update" it is. Probleem is alleen dat je dan een meer klassieke render loop krijgt.
Render, update, render, update.

Dit renderen is dus het updaten van je componenten. Daarnaast moet je repaint van het betreffende component overerven met een lege implementatie, (je panel waar je op tekent bijvoorbeeld) anders wordt repaint toch nog aangeroepen bij bijvoorbeeld een size wijziging en dergelijke. (De momenten dat normaliter je zaakjes opnieuw getekend moeten worden.)

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:47
Meerdere threads gebruiken en die onderling gaan synchroniseren lijkt me wat te veel van het goede en is hier ook helemaal niet nodig.

Doe in plaats van repaint() gewoon update(getGraphics()) of eventueel paint(getGraphics), als de achtergrond van het betreffende component niet gewist hoeft te worden.

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 03-09 16:40
Zie mijn vorige post.

Beste oplossing is om voor dit panel een specifieke render thread te maken die het tekenen op het geval beheerd. De states kunnen door het ding gewijzigd worden. En als je daar invloed op wil, dan zul je moeten synchonizen op de variabelen die je wilt kunnen wijzigen, met zeer snel zichtbare schokken tot gevolg. Daarnaast kun je beter time based renderen en niet frame based renderen. (Dat het verschil tussen frames wordt bepaald door een delta per tijdseenheid en niet door een vaste delta per frame.)

Verwijderd

Topicstarter
Op zaterdag 19 januari 2002 18:09 schreef Soultaker het volgende:
Doe in plaats van repaint() gewoon update(getGraphics()) of eventueel paint(getGraphics), als de achtergrond van het betreffende component niet gewist hoeft te worden.
Jaja, dit werkt dus perfect :Y) ! Niets meer en niets minder dan dat ik nodig had !
Ik kon alleen niet direct update of paint aan roepen vanwege het probleem met het Graphics object. Dus ff in de teken klasse een extra methode aangemaakt die paint(getGraphics) aanroept en die methode dan aanroepen vanuit de lus.

Voorlopig ben ik er weer uit ! Bedankt voor de reacties ! -Een hele blije /me :)-
Pagina: 1