Toon posts:

[Java/AWT] Blokkerende hoofdthread lijkt thread te blokkeren

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig met een applicatie waarmee de gebruiker door verschillende pagina's kan bladeren. Het laden van zo'n pagina kan wel even duren, daarom wil ik dus een progressbar onderaan voorzien, zodat er wat visuele feedback is naar de gebruiker.
Als ik echter de (blokkerende) zware functie op de pagina-component oproep, blokkeert schijnbaar de tekenthread van de progressbar.

Ik heb even een skelet voorbeeld gemaakt waarin het probleem ook voorkomt.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.awt.Container;
import java.awt.Dimension;

public class WorkingComponent extends Container {

    public WorkingComponent(Dimension dimension){
        setBounds(0,0,dimension.width, dimension.height);
    }
    //blokkeert twee seconden, simuleert werk
    public void work(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {}
    }
}


De progressbar is iets langer. Deze heeft z'n eigen thread, kwestie van de rest gerust te laten, dacht ik?

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Vector;

public class LoadScreenRenderControl extends Component implements Runnable{

    private final static int DOT_HEIGTH = 8;
    private final static int DOT_WIDTH = 2;
    private final static int DOT_COUNT = 11;
    private final static int DOT_VISIBLE = 10;
    private final static int DOT_BORDER = 2;
    
    private final static int TIME = 100;
    
    private final static Color kleur = Color.red;
    private Vector kleuren;
    
    private int progress;
    
    private int xcoord, ycoord;
    private int totalwidth;
    
    private volatile Thread thread;
    
    public LoadScreenRenderControl(Dimension dim){
        setBounds(0,0,dim.width, dim.height);
        totalwidth = DOT_WIDTH + DOT_BORDER;
        
        ycoord = (getHeight() - DOT_HEIGTH)/2;
        xcoord = (getWidth() - (DOT_COUNT*DOT_WIDTH + (DOT_COUNT - 1)*DOT_BORDER))/2;
        
        int reddiff = kleur.getRed()/DOT_VISIBLE;
        int greendiff = kleur.getGreen()/DOT_VISIBLE;
        int bluediff = kleur.getBlue()/DOT_VISIBLE;
        
        kleuren = new Vector(DOT_VISIBLE);
        for(int i = DOT_VISIBLE; i > 0; i--){
            kleuren.addElement(new Color(kleur.getRed() - i*reddiff, kleur.getGreen() - i*greendiff, kleur.getBlue() - i*bluediff));
        }
    }
    
    public void start() {
        progress = 0;
        thread = new Thread(this);
        thread.start();
    }
    
    public void stop() {
        thread = null;
    }
        
    public void run() {
        
        Thread thisThread = Thread.currentThread();
        while (thread == thisThread) {
        //hier gebeurt dus het tekenen
            progress++;
                progress%=DOT_COUNT;
            repaint();
                
            try {
                Thread.sleep(TIME);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    public void paint(Graphics g) {
        if(g != null){
            int x = xcoord + progress*totalwidth;
            g.clearRect(0,0,getWidth(),getHeight());
            for(int i = 0; i < DOT_VISIBLE; i++){
                g.setColor((Color)kleuren.elementAt(i));
                g.fillRect(x, ycoord, DOT_WIDTH, DOT_HEIGTH);
                x = xcoord + ((i + progress)%DOT_COUNT)*totalwidth;
            }
        }
        else{
            System.out.println("[loadscreen] g == null");
        }
    }

}


En dan nog ProgressTest. De klasse die alles bij elkaar gooit.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;

public class ProgressTest extends Container implements KeyListener {
    
    private final static Dimension DIM = new Dimension(100, 100);
    private final static Dimension PROGRESS_DIM = new Dimension(50, 20);
    
    private LoadScreenRenderControl progressbar;
    private WorkingComponent working;
    
    public ProgressTest(){
        setBounds(0,0,DIM.width, DIM.height);
        
        progressbar = new LoadScreenRenderControl(PROGRESS_DIM);
        working = new WorkingComponent(DIM);
    }
    
    public void start(){
            
        addKeyListener(this);
        requestFocus();
        add(progressbar);
        progressbar.start();
    }
    
    public static void main(String[] args){
        ProgressTest test = new ProgressTest();
        
        JFrame frame = new JFrame("Progress Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBackground(Color.black);
        frame.setContentPane(test);
        frame.setBounds(0,0,DIM.width + 9, DIM.height + 35);
        frame.setVisible(true);
        
        test.start();
    }
    
//zet werk in gang, blokkeer...
    public void keyPressed(KeyEvent arg0) {
        working.work();
    }
    
    public void keyReleased(KeyEvent arg0) {}
    
    public void keyTyped(KeyEvent arg0) {}
}


Wanneer je op een toets duwt, wordt de WorkingComponent in gang gezet, en blokkeert de progressbar (of de tekenthread?) twee seconden.

Ik heb al vanalles geprobeerd, in de "originele" versie wordt dubbele buffering gebruikt, en zijn er heel wat meer niveaus Containers, maar het probleem is hier evengoed geïllustreerd.

Op voorhand bedankt.

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 13:40
Was het niet zo dat paint operaties in java altijd in de event-dispatching thread uitgevoerd worden? Daar start je je WorkingComponent nu ook in, en "hangt" je gui dus. Wat ik meestal doe is juist de langlopende taak in een nieuwe thread te starten, en die af en toe een eventje laten gooien hoever hij is als dat nodig is.

Roomba E5 te koop


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

er is vast in Java ook een DoEvents() functie :) die moet je dan regelmatig (in een loop) aanroepen tijdens je "zware" functie... of je kan inderdaad multithreaden, maar dan moet je goed opletten of je applicatie wel threadsafe gebouwd is :)

-niks-


  • grhmpf
  • Registratie: December 2000
  • Laatst online: 29-05-2022

grhmpf

Android <3

*kuch* SwingWorker *kuch*

Nou oke, swing basics dus:

http://java.sun.com/docs/...uiswing/misc/threads.html

[ Voor 67% gewijzigd door grhmpf op 12-04-2006 19:51 ]


  • Robtimus
  • Registratie: November 2002
  • Laatst online: 22-02 17:25

Robtimus

me Robtimus no like you

MLM schreef op woensdag 12 april 2006 @ 19:23:
er is vast in Java ook een DoEvents() functie :) die moet je dan regelmatig (in een loop) aanroepen tijdens je "zware" functie...
Eh, nee, helaas niet.

Zoals al gezegd is er 1 enkele thread voor ALLE GUI operaties - het afhandelen van events, maar ook repainten. Zware operaties dienen dan ook altijd in een andere thread te worden uitgevoerd als je niet wilt dat je GUI hangt.

Let er wel op dat je vanuit zo'n andere thread niet je GUI kan aanpassen, daarvoor moet je de link van grhmpf maar eens lezen.

More than meets the eye
There is no I in TEAM... but there is ME
system specs


Verwijderd

Topicstarter
Bedankt voor de link. Had over het feit gekeken dat die vanuit de eventthread opgestart wordt |:( Ben ik dus wel een hele dag mee bezig geweest, zelfs mijn collega heeft erover gekeken.
Swingworker is echter geen optie. Het moet op het MHP-platform(gestripte java 1.1.8 ) draaien, heb dus alleen beschikkinging over beperkte AWT-mogelijkheden om m'n gui te maken.
Bedankt allen.
Pagina: 1