Jak odebrać komunikat zmiany rozdzielczości od systemu?

0

Witam.
Malutki problem, ale nie wiem którędy go w Javie popchnąć.
Wytworzyłem sobie klasę dziedziczącą po JComponent, która aktywnie renderuje i animuje klatki filmu/animacji
Dorzuciłem do niej reakcję na zmianę wielkości komponentu w ten sposób, że po zmianie rozmiaru rozdzielczość animowanego materiału jest skalowana do nowej wielkości. Do animacji używam wewnętrznie obiektu BufferedImage służącego do renderowania w tle, który jest tworzony przy pierwszym wyświetleniu oraz po każdej zmianie rozmiarów za pomocą

bufor = new BufferedImage(GUI.getDefGraph().createCompatibleImage(szer, wys, Transparency.TRANSLUCENT));

I wszystko jest ok. Tylko, że nie do końca. Jeżeli w trakcie działania animacji po prostu zmienię sobie tryb graficzny (rozdzielczość i/lub głębię kolorów), to oczywiście wszystkie kontrolki odpowiednio się przemalują. Tyle, że bufor, który stworzyłem nie musi już mieć odpowiednich parametrów zgodnych z właściwościami ekranu i co za tym idzie może przestać być akcelerowany sprzętowo (lub w ogóle może się wykrzaczyć). A chodzi mi o to, żeby po szybkiej zmianie bufora na znowu pasujący, komponent dostosował się do ekranu. Czyli krótko mówiąc potrzebny mi sposób na odebranie komunikatu, który np. w Windows ma nazwę WM_DISPLAY_CHANGE.
Moją spekulacją jest to, że prawdopodobnie chodzi o zarejestrowanie "listenera" na komunikaty typu AWTEvent, albo PropertyChangeEvent. Ale niewiele mi to daje bo nigdzie nie mogę znaleźć żadnej informacji o odbieraniu tego typu komunikatów (i jakich) od systemu.

0

może stwórz oddzielny wątek, który będzie sprawdzał co jakiś czas rozdzielczość ekranu i informował Cię przy pomocy swojego Eventu o zmianie rozdzielczośći?

0

To jest rozwiązanie nad którym myślałem, ale piekielnie nieeleganckie. Już pominę kwestię, że potrzebna mi każda mikrosekunda, więc tworzenie rzadko potrzebnych bytów na cały czas działania programu, to słaby pomysł. Tym bardziej, że doskonale wiem, że taki komunikat po systemie biega i co więcej JVM musi go sama odbierać bo inaczej wykrzaczyłby się cały system okienkowy w momencie zmiany na ekranie np. ilości kolorów na piksel.

0

na forum Suna nie ma innych pomysłów na to, ale jak byś znalazł ładniejsze rozwiązanie daj znać :)

0

Właśnie znalazłem bardziej eleganckie rozwiązanie. Co prawda nie jest ono docelowe bo używa prywatnych klas Suna obecnych w JRE, ale działa i w przyszłości będzie mogło być niezależne od tego co sobie Sun wymyśli. Wymagać to będzie podstawienia tylko jednego pliku class w nowszej wersji. A oto kod:

RejestratorZmianyGrafiki.java:

/**
 * Rejestruje zmiany trybu graficznego
 * Powiela sun.awt.DisplayChangedListener dla niewrażliwości
 * od wpływu zmian przyszłych implementacji sun.awt.*
 * @author Olamagato
 * @version 1.0
 */
public interface RejestratorZmianyGrafiki
{
	void zmienionoPaletę();
	void zmienionoRozdzielczość();
}

RejestracjaZmianyGrafiki.java

import java.awt.GraphicsEnvironment;
/**
 * Obsługuje rejestratora zdarzeń zmiany trybu graficznego
 * Rejestruje i wyrejestrowuje wywołania
 * @author Olamagato
 */
public class  RejestracjaZmianyGrafiki
{
	/**
	 * Ustawia warunki do informowania obserwatora o zmianach trybu
	 * graficznego
	 * @param obserwator klasa implementująca RejestratorZmianyGrafiki
	 */
	public RejestracjaZmianyGrafiki(RejestratorZmianyGrafiki obserwator)
	{
		GraphicsEnvironment ge =
			GraphicsEnvironment.getLocalGraphicsEnvironment();
		if(ge instanceof sun.java2d.SunGraphicsEnvironment)
		{
			sge = (sun.java2d.SunGraphicsEnvironment)ge;
			this.obserwator = obserwator;
		}
	}
	/**
	 * Rejestruje obserwatora dla zmian trybu graficznego
	 * Nadmiarowe rejestracje są ignorowane.
	 */
	public synchronized void włącz()
	{
		if(obserwator == null) return;
		if(!zarejestrowano)
		{	//sge i powiadamiacz zawsze istnieje
			sge.addDisplayChangedListener(powiadamiacz);
			zarejestrowano = true;
		}
	}
	/**
	 * Wyrejestrowuje obserwatora zmian trybu graficznego
	 * Nadmiarowe wyrejestrowania są ignorowane.
	 */
	public synchronized void wyłącz()
	{
		if(obserwator == null) return;
		if(zarejestrowano)
		{	//sge i powiadamiacz zawsze istnieje
			sge.removeDisplayChangedListener(powiadamiacz);
			zarejestrowano = false;
		}
	}

	//Zachowuje stan środowiska gdyby cudem nie był już dostępny w czasie wyrejestrowywania
	private sun.java2d.SunGraphicsEnvironment sge;

	//odnośnik do klasy powiadamianej o zmianach
	private RejestratorZmianyGrafiki obserwator; 

	//pozwala na wielokrotne rejestracje bez ryzyka wykrzaczenia
	private boolean zarejestrowano;

	private sun.awt.DisplayChangedListener powiadamiacz =
		new sun.awt.DisplayChangedListener() //nikt się nie dobierze z zewnątrz
	{
		/** Wywoływana tylko przez sun.awt.DisplayChangedListener */
		public void displayChanged() { obserwator.zmienionoRozdzielczość(); }

		/** Wywoływana tylko przez sun.awt.DisplayChangedListener */
		public void paletteChanged() { obserwator.zmienionoPaletę(); }
	};
}

Całość wymagać będzie tylko stworzenia obiektu RejestracjaZmianyGrafiki i podaniu jej klasy, która będzie obserwować zmiany grafiki w momencie gdy się pojawią. Rozwiązanie po prostu podkleja się do tego co robi Swing ponieważ i ta biblioteka potrzebuje uaktualnić bufory ekranowe po zmianie rozdzielczości/kolorów.
Można tę klasę jeszcze zabezpieczyć jako tako przed nagłym zniknięciem pakietu sun.* na innych JVM niż Sunowskich, aby przynajmniej nie wysypywała reszty programu oraz ewentualnie dodać obsługę finalize dla przypadku gdy ktoś zapomni wyłączyć rejestrację, a klasa pójdzie do śmieci (pewnie tylko po to, żeby wyrzucić błąd).

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