Paint init i konkurencja

0

Cześć. Mam następujący problem który nie mogę rozwiązać. Mam aplet który z obrazka robi mi tło oraz 5 komponentów. 3 Radiobutton'y oraz 2 TextField. 2 TextField pojawiają się normalnie, 1 Radiobutton ten co jest domyślnie zaznaczony a pozostałe 2 Radiobuttony nie widać, dopiero po najechaniu w okolice gdzie się on znajduje to się pokazuje.

TextField mam w PAINT i jest OK, tak samo miałem Radiobuttony ale pokazywał się tylko ten zaznaczony, tak samo mam w init.

Co na to poradzić ?

0

Bardzo źle. W paint() nie trzymasz, nie tworzysz, nie zmieniasz żadnych komponentów. Zapisz to wężykiem. ;-)
Sytuacje w których w ogóle używasz paint są rzadkie. Zmiana tej procedury służy do bezpośredniego jakiejś grafiki. Najbardziej sensownym jej zastosowaniem jest wrzucenie do niej wywołań paintComponent() dla poszczególnych składników panela w jakiś niestandardowy sposób. Robiąc programy czy aplety w których są wyłącznie komponenty Swing, AWT lub SWT praktycznie nigdy nie używasz, ani nie zmieniasz procedur paint(). Ich domyślnym działaniem jest odrysowanie swojej zawartości składającej się z komponentów w nich zawartych i/lub swojej oryginalnej zawartości.

0

Ok, dzięki a mam pytanko jedno jeszcze.

Jak sprawdzić który RadioButton jest zaznaczony ?

0

Skorzystaj z metody isSelected() , która zwraca true, jeśli button jest zaznaczony

0

Ok, odczytywanie, który jest zaznaczony ok ale nadal nie wiem jak zrobić ten komponenty. Wywaliłem je z paint() do init() i teraz po uruchomieniu programu nie widać w ogóle komponentów ani jednego. Prawdopodobnie przez to że w paint() mam tlo i ono mi zamalowuje komponenty.

Jak miałem w paint() było je widać no ale dopiero po najechaniu.

Jak mam się z tym uporać jeśli ma nie być w paint i komponenty mają być widoczne ?

0

Najlepiej byłoby jakbyś wkleił to co zrobiłeś.
Gdzieś robisz podstawowy błąd.
Być może w innych miejscach przesłaniasz procedurę paint() - szczególnie w oknie lub panelu. Wtedy doprowadzisz właśnie do takiego efektu jaki opisujesz.

Poniższy kod powinien być wywoływany w invokeLater(...) (lub init o ile ten jest wywoływany przez invokeLater) i pozwala prawidłowo rozpocząć pracę okna.

JFrame r = new JakieśOknoTypuJFrame();
r.add(kolejny_element_okna);
//... dodajemy potrzebne elementy
r.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
r.setSize(szer, wys); //lub r.pack();
//tutaj ewentualne pozycjonowanie okna
if(zmaksymalizowane) //jakieś modyfikacje okna - np. maksymalizacja
	r.setExtendedState(JFrame.MAXIMIZED_BOTH);
r.setVisible(true);
0
public class rezystor extends JApplet{
     Image tlo;
     JButton przycisk;

     public void init() {
      tlo = getImage(getDocumentBase( ), "tlo.jpg");
      setVisible(true);
      setLayout(null);
      setSize(600,600);

      przycisk = new JButton("Tekst");
      przycisk.setBounds(50, 50, 100, 35);
      przycisk.setVisible(true);
      add(przycisk);
     }

     public void paint(Graphics g) {
          g.drawImage(tlo, 0, 0, this);
          
     }


}

Taki kod i przykrywa.

0

No to kilka błędów jakie robisz.

  1. Uruchamiasz setVisible jako pierwszą instrukcję. Nawet przed wywołaniem setLayout(), które powinno być jednym z pierwszych wywołań Swinga dla komponentu kontenerowego (takiego, który zawiera inne komponenty). SetVisible() zasadniczo powoduje tworzenie okna w systemie okien lub przeglądarki. Okno takie jest dość autonomiczne w stosunku do komponentów Swing, które nie są samymi oknami, a tylko ich logicznymi reprezentacjami w Javie/Swingu. Dużo trudniej jest manipulować już utworzonym obiektem systemu okien niż komponentem, który zostanie wyświetlony po tym jak wszystko zostanie w nim przygotowane.

2.setSize uruchamiasz po setVisible. Błąd podobny jak powyżej. Dodatkowo dla apletu setSize ma niewiele sensu ponieważ jego ułożenie i wielkość powinna być zasadniczo kontrolowana przez stronę html, a nie przez samego siebie - choć jest to możliwe, nie jest zbyt dobrą praktyką.

  1. Tworzysz komponent przycisku i dodajesz go do komponentu rezystor - tyle, że to wcale nie oznacza, że dodajesz element graficzny przycisku do elementu graficznego apletu związanego z obiektem rezystor. Żeby tak się stało musiałbyś wykonać metodę revalidate(), albo invalidate() i validate() po sobie. Te wywołania aktualizują elementy graficzne związane z komponentami Swinga.

  2. Podmieniając całą metodę paint() i wrzucając jako jedyne działanie tej procedury drukowanie obrazka likwidujesz możliwość odrysowania się elementów graficznych jakie są związane z komponentami dodanymi w tym aplecie - a to dlatego, że procedura ta domyślnie powoduje odrysowanie siebie, ramki i wszystkich zawartych w sobie komponentów*. Twoja wersja paint() tego nie robi. Dlatego widzisz tylko sam obrazek, a przycisk rysuje się z wielkim bólem dopiero jak wyślesz do niego komunikat najechania myszą (najeżdżając myszą:).
    Powinieneś w celu zmiany tła przedefiniować procedurę paintComponent(), a nie paint().

*public void paint(Graphics g)
[...] This method actually delegates the work of painting to three protected methods: paintComponent, paintBorder, and paintChildren. They're called in the order listed to ensure that children appear on top of component itself.

  1. Wywołujesz metody Swing z wątku metody init() apletu, co nie oznacza wcale wątku Swing. Wszelkie wywołania metod komponentów Swing powinny byc zawarte w wywołaniu klasy implementującej interfejs Runnable() i przekazanej do wywołania metody invokeAndWait(). Normalnie dla Swing powinna to być invokeLater() - ale ponieważ wiele przeglądarek wysypuje się kiedy wątek procedury init() zakończy się przed pierwszym wywołaniem pętli zdarzeń Swing - dlatego nie wolno do tego dopuścić. Stąd wywołanie procedur inicjujących aplet musi być wywołaniem synchronicznym (powrócić ze sterowaniem do init() dopiero po wykonaniu żądanego do uruchomienia kodu).
    Jest nawet gorzej niż wielu sądzi. Każda z 4 procedur: init, start, stop i destroy może być wywoływana w zupełnie innym wątku (choć nie musi) dlatego trzeba to uwzględniać. Aplet w naturalny sposób jest programem wielowątkowym. Aplet używający Swinga może mieć conajmniej 5 wątków. Aplikacja conajmniej 2 z czego jeżeli main() szybko się zakończy - staje się potencjalnie jednowątkowa.

Tak więc można powiedzieć, że niemal wszystko w tym krótkim kawałku kodu jest źle. Musiałbyś to poprawić. Możesz wyszukać na tym forum tematy ze słowem Swing i co nieco się dowiedzieć. Albo skorzystać z jakiegoś lepszego podręcznika do Javy (lub wreszcie go przeczytać:).

0

WIELKIE DZIĘKI CHŁOPIE.

Jedynie to nie wiem jak zrobić to wywołanie elementów graficznych oraz wywołanie tworzenia przycisku tak aby nie była w metodzie SWING.

Jeśli możesz podaj jakiś przykładowy kod do tego problemu.

0
public class rezystor extends JApplet{

  DrawingPanel panel;
  Image image;

  public void init () {
    setLayout(null);
    Container content_pane = getContentPane ();
    panel = new DrawingPanel(this);
    content_pane.add(panel);

    image = getImage (getCodeBase (), "tlo.jpg" );
    setVisible(true);
  }
}




class DrawingPanel extends JPanel {
  rezystor fParent = null;

  DrawingPanel (rezystor parent) {
    fParent = parent;
  }

  public void paintComponent (Graphics g) {
    super.paintComponent (g);
    g.drawImage (fParent.image,10,10,this);
  }
}

Próbuje innych sposób i zrobiłem powyższy lecz nie maluje mi wcale Image.

0

Zrób tak. Utwórz osobną klasę tła wywodzącą się z JPanel. Dla niej przedefiniuj paintComponent() tak aby odrysowywała obrazek na swojej powierzchni. Oprócz tego zrób osobny panel na którym będą elementy interfejsu użytkownika zrobione w Swingu. Następnie stwórz obiekt JLayeredPane i dodaj do niego oba panele zrobione wcześniej, z tym że dodawaj je metodą add(JPanel panel, Integer priorytetWarstwy). Panel z obrazkiem dodaj z mniejszą wartością priorytetu, a panel z interfejsem z wyższą. W ten sposób będziesz miał panel warstwowy, w którym nic nie będzie ze sobą kolidowało. Ten obiekt typu JLayeredPane dodaj w metodzie run() klasy będącej argumentem w wywołaniu invokeAndWait(), która musi znaleźć się w init() apletu. W tej metodzie run() oprócz dodania JLayeredPane musi się jeszcze znaleźć wszystko co jest potrzebne do utworzenia okna Swing czyli:

  • Ustalenie rozmiaru, ewentualnie pobranie go z danych apletu (to najlepiej bo jest już skonstruowane kiedy przeglądarka wywołuje init() - a tym samym rozmiary apletu są ściągnięte z okna apletu w obszarze przeglądarki). Do ustawienie rozmiaru najlepiej użyć setPrefferedSize().
  • Zaktualizowanie okna przez SwingUtilities.updateComponentTreeUI() lub validate lub revalidate() (zamiast setVisible() - a to dlatego, że okno apletu już istnieje od samego początku odpalenia metody init()).

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