Problem z kodem komunikat non-static variable...

0

Witam!
Chciałbym prosić o pomoc. Dopiero zaczynam moją przygodę z javą, więc proszę o wyrozumiałość. Mój problem jest następujący, potrzebuję stworzyć dwa okienka, które będą otwierane przy starcie aplikacji. Męczę się nad tym już trzeci dzień, próbowałem przerabiać ten kod dziesiątki razy, a oprócz tego szukałem odpowiedzi w literaturze i na forum, jednak nic mi to nie pomogło... Obecnie doprowadziłem kod do takiej postaci:

import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JMenuBar;

import java.awt.event.*;
import java.awt.*;
import java.util.Random;

public class Problem
{
 private JFrame frame1;
 private JFrame frame2;
 private JButton button1;
 private JMenuItem menuItemExit;

 class Powitanie
 {
  public Powitanie()
  {
  JFrame frame1 = new JFrame();

   frame1.setSize(300, 200);
   frame1.setVisible(true);
   frame1.setTitle("Witaj!"); 
 
  frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame1.setLayout(null);

   JLabel label1 = new JLabel();
   label1.setText("Witam w programiku! :)");
   label1.setBounds(80, 50, 150, 20);

  frame1.add(label1);

   button1 = new JButton("Dalej");
   button1.setBounds(100, 80, 100, 20);

  frame1.add(button1);
 
  }
  }
  
  class Aplikacja
  {
  public Aplikacja()
  {
  JFrame frame2 = new JFrame();

  frame2.setSize(400, 300);
  frame2.setVisible(true);
  frame2.setTitle("Witaj!");

 frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 frame2.setLayout(null);

 JMenuBar mb = new JMenuBar();

  JMenu menu1 = new JMenu("Plik");
  JMenu menu2 = new JMenu("Opcje");
  JMenu menu3 = new JMenu("Dodatki");

  mb.add(menu1);
  mb.add(menu2);
  mb.add(menu3);

  menuItemExit = new JMenuItem("Zamknij");
  menu1.add(menuItemExit);

  JMenuItem menuItem1 = new JMenuItem("Pozycja 1");
  menu2.add(menuItem1);

  JMenuItem menuItem2 = new JMenuItem("Pozycja 2");
  menu2.add(menuItem2);

  JMenuItem menuItem3 = new JMenuItem("O programie");
  menu3.add(menuItem3);

  JMenuItem menuItem4 = new JMenuItem("Autor");
  menu3.add(menuItem4);

  frame2.setJMenuBar(mb);


}

}


public static void main(String args[])
{
  SwingUtilities.invokeLater(new Runnable() {
   public void run()
{
new Powitanie();
new Aplikacja();
}
});
}

}

Nie mam już pomysłów co z tym zrobić, proszę o pokazanie jak powinno to wyglądać lub wskazać mi błędy. Z góry dziękuję.

0

Zrobiłbyś to 10 razy szybciej gdybyś użył formatki czy to z eclipse czy netbeans, a przy okazji patrząc na wygenerowany kod widziałbyś jak to się robi. Lekko wyprostowałem Twój kod, tak że teraz działa, ale nadal nie jest on taki jaki powinien być. Po pierwsze używasz klas wewnętrznych, które jeżeli nie mają modyfikatora static, nie mogą samodzielnie istnieć bez obiektu klasy Problem.
Po drugie nie używasz żadnego układacza (layoutManager), tylko odpalasz setLayout(null) i próbujesz bawić się w zgadywanie pozycji i wymiarów. To tak naprawdę marnowanie czasu bo nic się przez to w tym czasie nie nauczysz. Po trzecie powinieneś sobie przemyśleć co powinno być "własnością" okienka, a co operacją na nim. Po czwarte nie mnóż zmiennych, których istnienie jest zbędne. Jeżeli zmienna jest wykorzystywana tylko w jednym miejscu, to najprawdopodobniej jest zupełnie zbędna i to co jest jej wartością można wrzucić bezpośrednio do miejsca jej użycia. Podobnie z polami klas - mają one sens tylko jeżeli będą używane przez kilka metod, w innym wypadku mogą być zmiennymi lokalnymi.
Zmiennym i metodom nadawaj sensowne nazwy zgodnie z tym co przechowują lub co robią. Mnóstwo ludzi nazywa zmienne byle jak lub zostawia nazwy wygenerowane automatycznie, a potem się dziwią szukając całe tygodnie w kodzie problemu, który wynika ze złego nazwania zmiennych.
To tyle na początek z tego co pamiętam.

import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JMenuBar;

public class Problem
{
	public Problem()
	{
		JFrame frame1 = new Powitanie();
		//zamknięcie tego okna nie powinno zamykać programu
		frame1.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		JFrame frame2 = new Aplikacja();
		frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		frame2.setVisible(true);
		frame1.setVisible(true);
	}

	class Powitanie extends JFrame
	{
		public Powitanie()
		{
			setSize(300, 200);
			setLayout(null);
			JLabel label1 = new JLabel();
			label1.setText("Witam w programiku! :)");
			label1.setBounds(80, 50, 150, 20);
			add(label1);
			JButton button1 = new JButton("Dalej");
			button1.setBounds(100, 80, 100, 20);
			add(button1);
			setTitle("Witaj!");
		}
	}

	class Aplikacja extends JFrame
	{
		public Aplikacja()
		{
			setSize(400, 300);
			setLayout(null);
			JMenuBar mb = new JMenuBar();
			JMenu menu1 = new JMenu("Plik");
			JMenu menu2 = new JMenu("Opcje");
			JMenu menu3 = new JMenu("Dodatki");
			menu1.add(new JMenuItem("Zamknij"));
			menu2.add(new JMenuItem("Pozycja 1"));
			menu2.add(new JMenuItem("Pozycja 2"));
			menu3.add(new JMenuItem("O programie"));
			menu3.add(new JMenuItem("Autor"));
			mb.add(menu1);
			mb.add(menu2);
			mb.add(menu3);
			setJMenuBar(mb);
			setTitle("Witaj!");
		}
	}

	public static void main(String args[])
	{
		SwingUtilities.invokeLater( new Runnable()
			{ @Override public void run() { new Problem(); } } );
	}
}
0

Witam.
Przeszperałem swoje notatki z SCJP i oto co znalazłem:

new Problem().new Powitanie();
new Problem().new Aplikacja();

Ponieważ są to klasy "zwykłe" wewnętrzne do to ich utworzenia potrzebujesz obiektu, który je opakowuje.

Dużo lepiej byłoby, jakbyś podzielił sobie program na 3 pliki - główny program, i dwie klasy okienek.
poza tym nie używaj invokelater - jest to wywarzanie otwartych drzwi (to moje prywatne zdanie)
Zamiast tego można spokojnie użyć JFrme.setVisible(true). InvokeLater warto używać do operacji które mają się dziać równolegle do działania gui, np jakiś zapis na dysku przy jednoczesnym wyświetleniu paska postępu.

Pozdrawiam.

0
  1. Naucz się po pierwsze pisać czytelny kod.
  2. Okienka opisanego w klasie Powitanie nie widać, bo wyświetlasz oba okna w jednym miejscu, a okno Powitanie jest mniejsze. Jak użytkownik odsłoni sobie okno Powitanie i kliknie w krzyżyk zamykający, to program się zakończy. Taka była twoja intencja ?
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JMenuBar;

import java.awt.event.*;
import java.awt.*;
import java.util.Random;

public class Problem
{
  public static void main(String args[])
  {
    SwingUtilities.invokeLater(new Runnable() 
    {
      public void run()
      {
        new Powitanie();
        new Aplikacja();
      }
    });
  }
}

//----------------------------

class Powitanie
{
  private JButton button1;
  public Powitanie()
  {
    JFrame frame1 = new JFrame();

    frame1.setSize(300, 200);
    frame1.setVisible(true);
    frame1.setTitle("Witaj!");

    frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame1.setLayout(null);

    JLabel label1 = new JLabel();
    label1.setText("Witam w programiku! :)");
    label1.setBounds(80, 50, 150, 20);

    frame1.add(label1);

    button1 = new JButton("Dalej");
    button1.setBounds(100, 80, 100, 20);

    frame1.add(button1);

  }
}

//----------------------------

class Aplikacja
{
  private JMenuItem menuItemExit;
  public Aplikacja()
  {
    JFrame frame2 = new JFrame();

    frame2.setSize(400, 300);
    frame2.setVisible(true);
    frame2.setTitle("Witaj!");

    frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame2.setLayout(null);

    JMenuBar mb = new JMenuBar();

    JMenu menu1 = new JMenu("Plik");
    JMenu menu2 = new JMenu("Opcje");
    JMenu menu3 = new JMenu("Dodatki");

    mb.add(menu1);
    mb.add(menu2);
    mb.add(menu3);

    menuItemExit = new JMenuItem("Zamknij");
    menu1.add(menuItemExit);

    JMenuItem menuItem1 = new JMenuItem("Pozycja 1");
    menu2.add(menuItem1);

    JMenuItem menuItem2 = new JMenuItem("Pozycja 2");
    menu2.add(menuItem2);

    JMenuItem menuItem3 = new JMenuItem("O programie");
    menu3.add(menuItem3);

    JMenuItem menuItem4 = new JMenuItem("Autor");
    menu3.add(menuItem4);

    frame2.setJMenuBar(mb);

  }
}
0
Black007 napisał(a)

poza tym nie używaj invokelater - jest to wywarzanie otwartych drzwi (to moje prywatne zdanie)

Dobrze byłoby gdybyś nie wprowadzał kolegi w błąd. invokeLater() jest niezbędne ponieważ biblioteki Swinga nie są wielowątkowe. Trzeba tylko zrozumieć co to oznacza. Polecam doczytać o wielowątkowości.
To, że przy niewielkim i prostym programie użycie paru metod wprost z wątku metody main() nie wysypie programu, nie znaczy że jest to zbędne. W każdej poprawnej aplikacji Swinga potrzebne jest przynajmniej jedno (i tyle wystarczy) wywołanie invokeLater() lub invokeAndWait() dla apletu.

InvokeLater warto używać do operacji które mają się dziać równolegle do działania gui, np jakiś zapis na dysku przy jednoczesnym wyświetleniu paska postępu.

Tak się robi wysypujące się programy. Coś chyba wiemy, resztę zgadniemy... :d

0
Olamagato napisał(a)
Black007 napisał(a)

poza tym nie używaj invokelater - jest to wywarzanie otwartych drzwi (to moje prywatne zdanie)

Dobrze byłoby gdybyś nie wprowadzał kolegi w błąd. invokeLater() jest niezbędne ponieważ biblioteki Swinga nie są wielowątkowe. Trzeba tylko zrozumieć co to oznacza. Polecam doczytać o wielowątkowości.
To, że przy niewielkim i prostym programie użycie paru metod wprost z wątku metody main() nie wysypie programu, nie znaczy że jest to zbędne. W każdej poprawnej aplikacji Swinga potrzebne jest przynajmniej jedno (i tyle wystarczy) wywołanie invokeLater() lub invokeAndWait() dla apletu.

InvokeLater warto używać do operacji które mają się dziać równolegle do działania gui, np jakiś zapis na dysku przy jednoczesnym wyświetleniu paska postępu.

Tak się robi wysypujące się programy. Coś chyba wiemy, resztę zgadniemy... :d

Przyznam, że spotkałem się z taką opinią, ale od 3 lat programuję zawodowo w J2SE i jakoś moje programy nie sypią się przez niewykorzystanie invokeLater(), raz nawet zdarzyło się, że właśnie wywołanie tej metody spowodowało nieprawidłowe działanie GUI.

Mógłbyś wskazać źródło, gdzie wyczytałeś, że wykorzystanie invokeLater() jest konieczne?

0

W każdym nowszym podręczniku do Javy, w każdym tutorialu Suna. I wystarczy sobie też podglądnąć źródła klas Swinga, żeby się o tym przekonać. Dostęp do pól klas Swinga nie jest synchronizowany, więc odpalanie jego metod z wielu wątków oznacza zakleszczenia, albo uszkodzenia danych. W małych programach może Ci się uda, w większych nie ma mowy. Jeżeli lubisz latać do klientów ratując dane w wyniku niewytłumaczalnych błędów jakie mogą robić Twoje aplikacje, to nie musisz się przejmować wielowątkowością. ;-)

0

Dziękuję za pomoc. Przyznam, ze w moim podręczniku jest również wykorzystywane na przykładach aplikacji jedynie invokeLater. Mam tylko jeszcze jedno pytanie, przeczytałem, że ten sposób wykonania tej aplikacji jest nieco zbyt zawiły ja na to co powinien dawać, czy mógłby ktoś napisać w jaki sposób mógłbym to przerobić lub pokazać na kodzie?

0

Tak naprawdę, to nie jest to jeszcze aplikacja, a co najwyżej formatka lub szkielet.
Kiedyś dojście do tego poziomu zajmowało mnóstwo kodu i było wyzwaniem samym w sobie, ale dzisiaj z powodu całkiem niezłych narzędzi i współczesnych bibliotek nie jest to nic trudnego.
Przede wszystkim poczytaj sobie źródła przykładów dostępnych na tutorialu Suna i zobacz co one robią w działaniu. Są wystarczająco małe, żeby wielkość kodu nie zaciemniała tego co robią.
Od razu nie zrobisz żadnego dobrze działającego programu. Jak kilka razy nie zrobisz błędów, to się niczego nie nauczysz. Ważne, żeby nauczyć się wyszukiwania przyczyn błędów. Czyli dużo czytać i robić na początek dużo prostych programików.
Co do tego kodu, to przykłady jak można go zmienić masz i ode mnie i od bogdansa. ZA jakiś czas załapiesz, że okienko powitalne powinno dziedziczyć od JDialog, co pozwoli mu wyskakiwać zawsze "z przodu" i w tym czasie bez swojego zamknięcie nie pozwoli na zrobienie czegokolwiek we właściwym programie.

Co do struktury programów w Javie i Swingu, to typowo w main() zleca się wątkowi obsługi Swinga skonstruowanie pierwszego okna aplikacji (po to jest invokeLater()). Po jego skonstruowaniu okienko jest poruszane przez zdarzenia docierające do Javy, które możesz obsłużyć lub nie. Poszczególne akcje takie jak wywołanie czegoś z menu lub reakcja na działanie myszki powinny zostać obsłużone w metodach implementowanych dla "listenerów". Jeżeli nie będą one robiły nic czasochłonnego, a tylko zmieniały stan lub wygląd aplikacji, to cały kod może być zamknięty w tych metodach. Jeżeli byłoby to jednak coś czasochłonnego (np. więcej niż 1/3 sekundy), to w takiej metodzie obsługi powinno utworzyć się nowy wątek wykonujący to czasochłonne zadanie, a po jego zakończeniu informujący z powrotem wątek obsługi Swing o jego zakończeniu (wtedy znowu przez invokeLater).

0

Dziękuję ;-)

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