Odświeżanie elementów GUI

0

Witam. Mam problem, a zarazem pytanie. Czy istnieje jakaś metoda, która odświeża elementy okna (GUI)?

Dla tych, którzy nie zrozumieli:

Tworzę klasę rozszerzającą JFrame i w konstruktorze ustawiam rozmiar, tytuł, itp.
Następnie w metodzie paint() (metoda rysująca) tworzę nowy obraz zapisany w pamięci procesu, rysuję na nim obiekty i na końcu wyświetlam go w okienku.
Jednakże jest problem, a mianowicie gdy w konstruktorze dodam np. JLabel to nie jest on widoczny, ponieważ obraz jest rysowany na samym wierzchu.
Powtórzę może pytanie: "Czy istnieje jakaś metoda, która odświeża elementy okna (GUI)?"

0

repaint() powoduje odmalowanie okna, ale jeśli malujesz elementy w takiej kolejności że się zakrywają to tak też to będzie odmalowane.

0
  1. invalidate() kiedy stan obiektów Swing zmienił się tak, że nie odpowiada mu stan obiektów GUI, które są (mogą być) widoczne na ekranie (np. dodałeś JLabel, przesunąłeś położenie JButton itp.).
  2. validate (lub validateTree) kiedy chcesz jawnie zaktualizować stan obiektów GUI na podstawie zmienionego stanu obiektów Swing (np. zakończyłeś grzebać w kontrolkach).
  3. repaint() kiedy chcesz odrysować zaktualizowany obiekt GUI (validate nie wymusza odrysowania, czyli aktualizacji pamięci obrazu). Ta metoda może zostać opuszczona jeżeli odmalowanie zostanie wywołane przez system - na przykład zmieniane kontrolki dostaną/utracą focusa, zostaną przeniesione na wierzch innych okien itp.

I dla jasności: Obiekty GUI są kontrolowane głównie przez system operacyjny. Obiekty Swing są kontrolowane przez Javę/JVM. A te ostatnie są kontrolowane przez Twoją aplikację za pomocą wywołań invokeLater, invokeAndWait lub z metod obsługi zdarzeń poruszanych przez wątek Swing - twoja aplikacja dostarcza Swingowi obiekty funkcyjne (instancje implementujące np. actionListenera) za pomocą metod rejestrujących procedury obsługi zdarzeń.

0
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Frame extends JFrame {
	//Wysokosc i szerokosc
	public static final int WIDTH = 600;
	public static final int HEIGHT = 400;
	
	//Obrazki
	private ImageIcon someone;
	
	//Podwojne buforowanie
	private Image dbImage;
	private Graphics dbg;

	//Elementy gui
	private JLabel lbl;

	
	public Frame() {
		setSize(WIDTH, HEIGHT + 29);
		setTitle("Okno");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setResizable(false);
		setVisible(true);
		setLayout(null);
		
		lbl = new JLabel("Hartkor");
		lbl.setBounds(100, 100, 150, 30);
		add(lbl);
	}
	
	public void paint(Graphics g) {
		if (dbImage == null) {
			dbImage = createImage(WIDTH, HEIGHT);
			dbg = dbImage.getGraphics();
		}
		
		draw(dbg);
		
		g.drawImage(dbImage, 0, 29, null);
		
		
	}
	
	public void draw(Graphics g) {
		g.setColor(Color.white);
		g.fillRect(0, 0, WIDTH, HEIGHT + 29);
		g.setColor(Color.black);
		
		try { Thread.sleep(30); }
		catch (Exception e) {}
		
		repaint();
		
		
	}

}

Po odpaleniu jak widzimy ukazuje nam się okno z białym tłem.
Jak zrobić, aby JLabel był narysowany na tym tle, a nie pod.

Z góry dzięki.

0

Jak to jak? Normalnie, w paint() twojego JFrame daj lbl.paint(). Zmieniłeś sposób rysowania swojej ramki więc rysuje się tylko to co kazałeś!

0

Dzięki, oto mi chodziło, jednakże pojawia się drugi problem, a mianowicie:

Po ustawieniu pozycji i rozmiaru JLabel jest w jakiś domyślnych koordynatach.
Teraz pojawia się pytanie: Jak przesunąć label i ustawić jego koordynaty?
Poprzez ustawienie za pomocą metody setBounds rozmiaru i położenia podane rzeczy nie zmieniają się, jakby w ogóle nie wywołano tej metody.

0

Lekcja na dziś: layout manager.
Tak w ogóle to może po prostu ściągniesz wtyczkę Google Window Builder do Eclipse i ułatwisz sobie życie?

0

Druga lekcja na dziś: nie wywołuj repaint() z paint().

0

@Shalom

Dzięki, przydatny plugin.

@bogdans

Podaj mi stosowne argumenty, dlaczego w metodzie draw nie mam wywolywać repaint co 30 milisekund.

0

U Ciebie draw() wywołuje repaint(), repaint() standardowo wywołuje paint(), u Ciebie paint() wywołuje draw(), draw() wywołuje repaint(),....

0

Tak, wiem. W czym widzisz problem ;> ?

0

@Shalom już napisał w czym problem. Ale skompiluj i uruchom ten program, to się dowiesz czemu nie należy robić cyklicznych wywołań.

public class Overflow
{
    public static void main(String[] args)
    {
        a();        
    }
    private static void a()
    {
        b();
    }
    private static void b()
    {
        c();
    }
    private static void c()
    {
        a();
    }
}
0

Powtarzaj jak mantrę: "setVisible(true) zawsze na końcu". I tak jakieś 100 razy. :)

Metoda ta powoduje (co jest dość słabo opisane w javadoc) pojawienie się okna GUI (typu top-level), wszystkich podokien i wszystkich kontrolek jakie do tego momentu mu zdefiniowano (głównie za pomocą metod add). Dlatego kiedy już ją wywołasz kolejne wywołania metod Swinga wydają się nie działać (kolejne add, setSize, setPreferredSize, setLayout itd.) - choć są w istocie realizowane - aż do momentu wywołania validate lub validateTree (a oprócz tego czasem jeszcze repaint). Metody takie jak add, remove powodują automatyczne wywołanie invalidate dla obiektu, który jest modyfikowany - dlatego nie trzeba tej metody dodatkowo wywoływać. Metody Swinga mają natychmiastowe działanie wyłącznie na obiektach określanych jako "lightweight" - są one kontrolowane bezpośrednio przez Javę, a konkretniej przez bibliotekę Swing.

1 użytkowników online, w tym zalogowanych: 0, gości: 1