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.
De progressbar is iets langer. Deze heeft z'n eigen thread, kwestie van de rest gerust te laten, dacht ik?
En dan nog ProgressTest. De klasse die alles bij elkaar gooit.
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.
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.