Tablica JLabel

0

W klasie Game deklaruję tablicę JLabeli, mam też tam metodę tworzącą JLabele:

    public static JLabel[] answers = new JLabel[Files.dbSize];

    void initLabel(JLabel jlabel, int coordX, int coordY, int width, int height, String a)
    {
        remove(jlabel);
        jlabel.setOpaque(true);
        jlabel.setFont(taskFont);
        jlabel.setForeground(myFontColor);
        jlabel.setBackground(myBackground);
        jlabel.setLocation(coordX,coordY);
        jlabel.setSize(width, height);
        jlabel.setText(a);
        add(jlabel);
        repaint();
    }//koniec initLabel

W klasie Mouse próbuję utworzyć nowy JLabel:

Window.game.initLabel(Game.answers[0],5,200,100,100,"test");

Niestety program nie współpracuje:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
	at java.desktop/java.awt.Container.remove(Container.java:1282)
	at TheRoom1.Game.initLabel(Game.java:66)
	at TheRoom1.Mouse.click(Mouse.java:99)
	at TheRoom1.Mouse.mouseClicked(Mouse.java:16)
	at java.desktop/java.awt.Component.processMouseEvent(Component.java:6581)
	at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3343)
	at java.desktop/java.awt.Component.processEvent(Component.java:6343)
	at java.desktop/java.awt.Container.processEvent(Container.java:2259)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4961)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2317)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4793)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4548)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4480)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2303)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2758)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4793)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:766)
	at java.desktop/java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:717)
	at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:711)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:89)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:99)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:739)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:737)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:89)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:736)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:199)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Problem tkwi gdzieś w powiązaniu z tablicą, bo jak sprawdzam na pojedynczej zmiennej JLabel to śmiga bez zarzutu. Co robię nie tak?

0

pokaż metode remove()

1

@Berylo: remove() to pewnie metoda java.awt.Container, po której OP pewnie dziedziczy w klasie Game (patrząc na to, że ma dostęp do metod add i repaint

@Jarek Szulc
Zgodnie z dokumentacją, metoda java.awt.Container#remove rzuca NullPointerException, gdy Component, który przekazujesz w parametrze jest nullem.
Czyli twój trop jest dobry: masz gdzieś błąd w trakcie inicjalizacji tablicy Game#answers, bo Game.anwsers[0] to null i dlatego remove(jLabel) w initLabel rzuca ci wyjątkiem.
Sprawdź sobie dlaczego tam jest null, albo pokaż kod inicjalizacyjny tej tablicy

PS1
W jakim celu w ramach inicjalizacji labela dodajesz go i usuwasz?

PS2
To-to jest brzydkie: Window.game.initLabel(Game.answers[0],5,200,100,100,"test");. Używaj getterów, jeśli musisz - a najlepiej zrób tak, żeby w ogóle ich nie było (jeśli się da)

0

@Tyvrel
Z metodą remove() jest jak piszesz i fakt, że jest tam niepotrzebna. Prawdę mówiąc już nawet sam nie wiem co miałem na myśli ją tam dopisując. W każdym razie po usunięciu tej linijki błąd jest ten sam, z tą różnicą że wskazuje na linię kolejną w metodzie initLabel

Kod inicjalizacyjny tablicy? Mógłbyś rozwinąć, bo nie wiem co masz na myśli.

W moim rozumowaniu, deklarując tablicę w ten sposób:

public static JLabel[] answers = new JLabel[Files.dbSize];

tworzę tablicę zawierającą tyle elementów (z których każdy jest nowym JLabel), ile wynosi wartość zmiennej dbSize z klasy File. Ogólnie chcę osiągnąć identyczny efekt jak poniżej, zastępując szereg zmiennych tablicą.

public static JLabel a1 = new JLabel();
public static JLabel a2 = new JLabel();
public static JLabel a3 = new JLabel();
public static JLabel a4 = new JLabel();
public static JLabel a5 = new JLabel();

No i następnie ustawić parametry każdego z Labeli przy pomocy metody initLabel.

Ad. PS2
Tutaj też bym prosił o rozwinięcie co konkretnie jest 'brzydkie' i w jaki sposób miałbym tutaj gettery zastosować?

1

Widzę, że się nie do końca zrozumieliśmy. jLabel w metodzie initLabel jest nullem.
Dlaczego?
initLabel wywołujesz za pomocą: Window.game.initLabel(Game.answers[0],5,200,100,100,"test");
Twój jLabel to Game.answers[0].
Czyli Game.answers[0] to null.

Pytanie do ciebie, czemu w Game.answers[0] masz nulla? (Jeśli dalej nie rozumiesz, wydrukuj sobie w terminalu Game.answers w Mouse tuż przed wywołaniem Window.game.initLabel(Game.answers[0],5,200,100,100,"test");)

Stąd moje pytanie: skoro w tablicy Game.answers masz nulla sprawdź w jaki sposób i kiedy dodajesz do tej tablicy rekordy.


Jeśli zaś chodzi o brzydkość tego: Window.game.initLabel(Game.answers[0],5,200,100,100,"test");

  1. game jest singletonem, a to antywzorzec projektowy, Jeśli chcesz zgłębić temat, poczytaj o nietestowalności singletonów i dependency injection
  2. Twoja myszka wie o tym, że jest coś takiego jak gra, a ponadto wie coś o JLabelach w środku. Jest to złamanie zasady jednej odpowiedzialności (S w SOLID). Mówiąc obrazowo: trudno, żeby producenci myszek umieszczali w każdej sterownik do obsługi każdej jednej gry. Nie popełniaj podobnego błędu, tylko dlatego, że pracujesz w dużo mniejszej skali.
  3. Udostępniasz pole game publicznie. To jest fe-fe i konwencją w świecie programistów jest, żeby zamiast tego stosować gettery, bo to wprowadza enkapsulację (czy tak jest w rzeczywistości zapraszam do uczestnictwa w świętej wojnie)
1

W moim rozumowaniu, deklarując tablicę w ten sposób:
public static JLabel[] answers = new JLabel[Files.dbSize];
tworzę tablicę zawierającą tyle elementów (z których każdy jest nowym JLabel), ile wynosi wartość zmiennej dbSize z klasy File.

W ten sposób tworzysz tablicę o rozmiarze takim jak wartość zmiennej dbSize, a nie liczbę elementów. Innymi słowy dopiero deklarujesz jak duża ma być tablica, rezerwujesz miejsce w pamięci na tyle obiektów. Nie mniej jednak tablica pozostaje pusta i w każdym elemencie tablicy jest null dopóki jej nie wypełnisz ręcznie.
Dodać możesz tak:

answers[0] = jLabel;
answers[1] = otherJLabel;
itd

W twoim wypadku być może lepiej będzie użyć ArrayList gdzie nie musisz podawać indexu tylko robisz answers.add(jLabel);

Być może to wiesz, ale nie widzę tego w kodzie.

0
Tyvrel napisał(a):

Jeśli zaś chodzi o brzydkość tego: Window.game.initLabel(Game.answers[0],5,200,100,100,"test");

  1. game jest singletonem, a to antywzorzec projektowy, Jeśli chcesz zgłębić temat, poczytaj o nietestowalności singletonów i dependency injection

To co robię to projekt na zaliczenie przedmiotu. Pominę to na ten moment, bo wydaje mi się że oceniający projekt mi się do tego raczej nie przyczepi, ale dzięki za wyjaśnienie :)

  1. Twoja myszka wie o tym, że jest coś takiego jak gra, a ponadto wie coś o JLabelach w środku. Jest to złamanie zasady jednej odpowiedzialności (S w SOLID). Mówiąc obrazowo: trudno, żeby producenci myszek umieszczali w każdej sterownik do obsługi każdej jednej gry. Nie popełniaj podobnego błędu, tylko dlatego, że pracujesz w dużo mniejszej skali.

W klasie Mouse mam tylko obsługę kliknięć w oknie, czyli prosta metoda pobierająca współrzędne kliknięcia i kolejna (już nieco bardziej obszerna) wykonująca akcje w zależności od pobranych współrzędnych. Naprawdę to może przestać działać w przypadku podłączenia innej myszy?

  1. Udostępniasz pole game publicznie. To jest fe-fe i konwencją w świecie programistów jest, żeby zamiast tego stosować gettery, bo to wprowadza enkapsulację (czy tak jest w rzeczywistości zapraszam do uczestnictwa w świętej wojnie)

Żebym z wnętrza klasy Mouse mógł się odwołać do metody initLabel, znajdującej się w klasie Game, muszę ją zrobić public static. Jak ją zrobię static, to mi wyskakuje, że nie mogę wewnątrz niej wywołać metod add(), remove() i repaint(), które są mi tam potrzebne.

Żeby działało, wywołuję więc initLabel na obiekcie klasy Game, zadeklarowanym w klasie Window:

public static Game game = new Game(); //Panel gry

Pewnie da się to zrobić jakoś ładniej, ale moja skromna wiedza niestety nie pozwoliła mi wpaść na inny pomysł. No i póki co mnie interesuje przede wszystkim to, żeby całość działała (deadline i te sprawy).

Edit:
Dobra, działa. Nie wiem czemu ja na to sam nie wpadłem wcześniej ^^
Pierw

public static JLabel[] answersTab = new JLabel[Files.dbSize];

Potem

for (int i = 0; i < Files.dbSize; i++)
{
     answersTab[i] = new JLabel();
}

I śmiga :)

Dzięki panowie

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