Java - Problem med Thread (klocka)

Permalänk

Java - Problem med Thread (klocka)

Hej!
Tänkte bli bättre på att ta nytta på trådar i Java (Threads), därför bestämde jag mig för att göra en klocka.
Klockan är från början inställd på 18.46.2 men att den ska uppdateras varje sekund och när sekundvariabeln blir mer än 59, ska den nollställas och minutvariabeln ska höjas med en (samma med timmar). Alltså, som en klocka.
Problemet är bara att klockan inte vill uppdateras, utan den har stannat på 18.46.2.

Här kommer koden:

import java.awt.Graphics; import javax.swing.*; public class process extends JFrame implements Runnable { Thread t; int h,m,s; public process() { setTitle("Time"); h = 18; m = 46; s = 2; setSize(200,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public void start() { t = new Thread(this); t.start(); } public void run() { Thread tt = Thread.currentThread(); while(tt == t) { try { update(); Thread.sleep(1000); } catch(InterruptedException e) { e.printStackTrace(); } repaint(); } } public void stop() { t = null; } public void update() { s++; if(s > 59) { m++; s = 0; } if(m > 59) { h++; m = 0; } if(h > 23) { h = m = s = 0; } } public void paint(Graphics g) { g.drawString(h + "." + m + "." + s, 95, 95); } public static void main (String[] arg) { new process(); } }

Ser ni var problemet sitter?

Tacksam för svar.

Permalänk
Medlem

Du kör aldrig din start metod.

Permalänk
Skrivet av Racy:

Du kör aldrig din start metod.

public process() { setTitle("Time"); h = 18; m = 46; s = 2; start(); setSize(200,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); }

Tack!
Lade nu till start() i konstruktorn, så nu uppdateras den efter varje sekund som väntat :P. Problemet nu är dock att när nästa sträng ritas (i paint metoden) så ritas den över den/de andra strängen/strängarna. Jag vill att varje ny sträng ska ersätta den gamla så att det inte syns en massa kladd som man inte kan avläsa.
Borde det inte ersättas i och med repaint()?

Någon lösning?

Permalänk

Löste det nu

public void paint(Graphics g) { g.setColor(Color.BLACK); g.fillRect(0, 0, 200, 200); g.setColor(Color.WHITE); g.drawString(h + "." + m + "." + s, 80, 90); }

Permalänk
Medlem

Annars kan du köra med.

g.clearRect(0, 0, 200, 200);

Permalänk
Medlem

I en JFrame ska du överlagra paintComponent, inte paint

edit: korrigering: du bör överlagra paintComponent på den JComponent som används som contentPane i din JFrame. Dessutom bör du anropa super.paintComponent det första du gör. Det kan räcka för att komponenten ska rengöra sig mellan paints.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Skrivet av Teknocide:

I en JFrame ska du överlagra paintComponent, inte paint

edit: korrigering: du bör överlagra paintComponent på den JComponent som används som contentPane i din JFrame. Dessutom bör du anropa super.paintComponent det första du gör. Det kan räcka för att komponenten ska rengöra sig mellan paints.

Förstår inte riktigt hur du menar då det inte funkar när jag gör som du sa :\. Alltså, ändrar paint till paintComponent och skriver super.paintComponent() i denna metod.

Permalänk
Skrivet av Princeps:

Annars kan du köra med.

g.clearRect(0, 0, 200, 200);

Funkar det med

Permalänk
Medlem
Skrivet av 3liteSoldier:

Förstår inte riktigt hur du menar då det inte funkar när jag gör som du sa :\. Alltså, ändrar paint till paintComponent och skriver super.paintComponent() i denna metod.

Jag menar såhär:

import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import javax.swing.JFrame; import javax.swing.JPanel; public class TimePanel extends JPanel implements Runnable { private static final int WIDTH = 200; private static final int HEIGHT = 40; private int h = 18; private int m = 46; private int s = 2; public TimePanel() { this.setPreferredSize(new Dimension(WIDTH, HEIGHT)); this.setBackground(Color.BLACK); this.setForeground(Color.GREEN); // matrixy! new Thread(this).start(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // viktig String time = h + ":" + m + ":" + s; g.drawString(time, 20, 20); } @Override public void run() { while(true) { repaint(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } s++; m = m + s / 60; h = h + m / 60; s = s % 60; m = m % 60; h = h % 24; } } public static void main(String[] args) { JFrame window = new JFrame("Timer"); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.setContentPane(new TimePanel()); window.pack(); window.setVisible(true); } }

edit: förresten, klockan kommer att gå fel. Detta beror på att Thread.sleep(1000) sover i ungefär 1000 millisekunder (minst). Det handlar om millisekunder till en början men efter tusen sådana har klockan halkat en sekund efter jämfört med systemtiden..

edit 2: glömde naturligtvis att argumentera för min sak
Faktum är att det inte är nödvändigt att överlagra paintComponent. Man kan, mycket riktigt, köra över paint rätt och slätt, men det brukar inte rekommenderas.

Varför?
En Swing-komponent målas i tre omgångar: Först målas komponenten (paintComponent()), sedan komponentens bård (paintBorder()), och till sist dess barn (paintChildren()). Du kan läsa mer om detta här: http://java.sun.com/products/jfc/tsc/articles/painting/#swing

Varför vill vi anropa super.paintComponent() från vår överlagrade paintComponent?
JComponent, som är JPanels superklass, standardiserar vissa attribut mellan de olika komponenterna i Swing-ramverket. Genom att anropa super.paintComponent() först av allt låter vi vår komponent måla sig enligt den fördefinierade standarden; detta innebär att komponenten fylls med sin satta bakgrundsfärg (om inte setOpaque(false) har anropats på den). Kort och gott låter man sin nya komponent uppföra sig (eller åtminstone måla om sig) som en vanlig JComponent.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Skrivet av Teknocide:

Jag menar såhär:

import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import javax.swing.JFrame; import javax.swing.JPanel; public class TimePanel extends JPanel implements Runnable { private static final int WIDTH = 200; private static final int HEIGHT = 40; private int h = 18; private int m = 46; private int s = 2; public TimePanel() { this.setPreferredSize(new Dimension(WIDTH, HEIGHT)); this.setBackground(Color.BLACK); this.setForeground(Color.GREEN); // matrixy! new Thread(this).start(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // viktig String time = h + ":" + m + ":" + s; g.drawString(time, 20, 20); } @Override public void run() { while(true) { repaint(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } s++; m = m + s / 60; h = h + m / 60; s = s % 60; m = m % 60; h = h % 24; } } public static void main(String[] args) { JFrame window = new JFrame("Timer"); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.setContentPane(new TimePanel()); window.pack(); window.setVisible(true); } }

edit: förresten, klockan kommer att gå fel. Detta beror på att Thread.sleep(1000) sover i ungefär 1000 millisekunder (minst). Det handlar om millisekunder till en början men efter tusen sådana har klockan halkat en sekund efter jämfört med systemtiden..

edit 2: glömde naturligtvis att argumentera för min sak
Faktum är att det inte är nödvändigt att överlagra paintComponent. Man kan, mycket riktigt, köra över paint rätt och slätt, men det brukar inte rekommenderas.

Varför?
En Swing-komponent målas i tre omgångar: Först målas komponenten (paintComponent()), sedan komponentens bård (paintBorder()), och till sist dess barn (paintChildren()). Du kan läsa mer om detta här: http://java.sun.com/products/jfc/tsc/articles/painting/#swing

Varför vill vi anropa super.paintComponent() från vår överlagrade paintComponent?
JComponent, som är JPanels superklass, standardiserar vissa attribut mellan de olika komponenterna i Swing-ramverket. Genom att anropa super.paintComponent() först av allt låter vi vår komponent måla sig enligt den fördefinierade standarden; detta innebär att komponenten fylls med sin satta bakgrundsfärg (om inte setOpaque(false) har anropats på den). Kort och gott låter man sin nya komponent uppföra sig (eller åtminstone måla om sig) som en vanlig JComponent.

Tack!

Permalänk

Förstår bara inte riktigt hur modulus-operatorn hänger ihop med saken i run() - metoden.

Permalänk
Medlem
Skrivet av 3liteSoldier:

Förstår bara inte riktigt hur modulus-operatorn hänger ihop med saken i run() - metoden.

s är lika med resten av s genom 60.

0->59 / 60 = 0, rest 0->59
60 / 60 = 1, rest 0

... s += 1; // lägg till en sekund m += s / 60; // lägg till s / 60 minuter (1 om s == 60) h += m / 60; // samma som fallet ovan s %= 60; // s blir 0 om s är 60, annars ingen ändring m %= 60; // samma h %= 24; // samma fast 24

Visa signatur

Kom-pa-TI-bilitet

Permalänk

Jaha, nu förstår man klart och tydligt