JComboBox i ListCellRenderer

0

Hej,

Kończę właśnie pisać obsadzanie JComboBox'a JLabelami zawierającymi tworzone dynamicznie ikony i pobierany dynamicznie tekst i korzystam przy obsadzaniu z ListCellRenderer'a, ale nie wiem, czy to już przez zmęczenie, czy te upały, ale utknąłem... Mam napisanego ListCellRenderer'a i metodę w głównej klasie, która z niego korzysta. Problem, który próbuję teraz rozwiązać polega na tym, że chcę, by ListCellRenderer dodawał kolejne JLabele do JComboBoxa z uwzględnieniem już znajdujących się w boxie itemów (JLabeli właśnie). Jak na razie wywołanie metody ustawiającej renderer dla boxa po prostu nadpisuje już znajdujący się w nim JLabel, wiem dlaczego tak się dzieje, ale nie wiem jak zrobić, by itemy były dodawane do puli, a nie były nadpisywane.

Prezentuje to poniższy przykład:

Problem.jpg

  1. Naciskam :niebieską strzałkę w prawo: która zawiera metodę wykorzystującą renderer. JLabel pojawia się w boxie.
  2. Wpisuję nową wartość w textfieldzie (tym po lewej).
  3. Naciskam :niebieską strzałkę w prawo: i znowu wywołuję metodę z rendererem. JLabel pojawia się w boxie.
  4. Problem w tym, że nowy JLabel nadpisał wcześniejszy item.

Jak temu zaradzić? Poniżej kod Renderera i metody.

/*
 * Renderer
 */
import java.awt.Component;
import javax.swing.*;

public class ComboRenderer extends JLabel implements ListCellRenderer {
   
   // Deklaruję zmienne dla tekstu oraz ikony dla przyszłego JLabela
   String text;
   ColorSwatch icon; // ColorSwatch jest klasą implementującą 'Icon'. Tworzy ikonkę.
   
   public ComboRenderer (String text_d, ColorSwatch icon_d) {
      
      setOpaque(true);
      setHorizontalAlignment(CENTER);
      setVerticalAlignment(CENTER);
      
      text = text_d;
      icon = icon_d;
   }

   public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {

      setIcon(icon);
      setText(text);
      
      return this;
   }
}

/*
 * Metoda pobierająca tekst, tworząca ikonę oraz ustawiająca renderer dla JComboBox'a
 */
 public void setComboBox() {
      
   String value = field.getText().toString(); // Pobieram tekst z JTextField'a
      
   Color color = tcc.getColor();   // Pobieram kolor z innego JLabela
   ColorSwatch icon = new ColorSwatch(10, true);    // Tworzę nową ikonę
   icon.setColor(color);   // Ustawiam jej kolor

   ComboRenderer renderer = new ComboRenderer(value, icon); // Tworzę nowy renderer
      
   boxColor.setRenderer(renderer);      // Ustawiam renderer
   boxColor.setMaximumRowCount(5);    // Ustawiam wielkość wyświetlanego obszaru
}
 
 /*
 * Przycisk :niebieska strzałka w prawo:
 */
JButton copy = new JButton();
copy.addActionListener(new ActionListener() {
         
   public void actionPerformed(ActionEvent arg0) {
            
      try {
               
         String hex = field.getText();      // Pobieram wartość z JTextFielda
         boolean canI = CheckHexValue(hex);   // Sprawdzam szereg zależności w metodzie CheckHexValue()
               
         if (canI) {
                  
            setComboBox();   // Odpalam metodę setComboBox()
            boxColor.repaint();      // Odmalowuję JComboBox'a
         }    
      } catch (Exception e) {
               
         JOptionPane.showMessageDialog(null, e);      // W razie 'w' wyświetlam JOptionPane z treścią 'w'.
      }
   }
});

Chciałbym w jakiś sposób wysyłać do renderer'a dane o aktualnej zawartości JComboBoxa i jeżeli coś się wnim znajduje to, żeby do istniejących już w nim obiektów był dodawany następny JLabel o właściwościach określonych w konstruktorze, czyli "ComboRenderer(String text, ColorSwatch icon)".

Będę ogromnie wdzięczny za pomoc.

Pozdrawiam serdecznie!

0

Nie rozumiem Twojego podejścia, JComboBox ma model (dane), po kliknięciu w strzałkę powinieneś dodać element do modelu i to wszystko. (Ewentualnie wywołać repaint().)

0

Żeby dodawać JLabele z tekstem i ikoną muszę skorzystać z customowego renderera. Nie mogę od tak stworzyć modelu, dodać do niego elementu, ustawić tego modelu dla comboboxa i odpalić repainta. Gdy tak zrobię to element w comboboxie nie przyjmie formy JLabela, a jedynie ciąg znaków String. Chyba, że mówisz bym skorzystał z dodawania elementów do modelu w ciele renderer'a? Możesz rozwinąć swoją myśl? Będę wdzięczny.

Pozdrawiam serdecznie.

1
class Model extends AbstractListModel implements ComboBoxModel 
...
Model model = new Model();
JComboBox combo = new JComboBox(model);
combo.setRenderer(new MyRenderer());
...

A potem dodajesz do modelu kolejny element.
Elementy modelu powinny zawierać informacje o tekście, kolorze, ikonie,... Renderer jest jeden i korzysta z tych informacji.

0

Hej,

Dzisiaj to wydaje się oczywiste, ale wczoraj niestety jeszcze takie nie było :) Siadam właśnie do pisania. Tak naprawdę wystarczy, że do renderera dotrze informacja w hexach z JTextFielda, np. "#ffffff", a już renderer na jej podstawie stworzy JLabel'a z ikoną w kolorze o wartości "#ffffff" i ustawi tekst labela właśnie na #ffffff :D genialne :D Zobaczę tylko, czy takie rozwiązanie pozwoli dodawać elementy dynamiczne, ale na logikę wydaje się, że tak :)

Dzięki @bogdans za reset myśli :)

Pozdrawiam!

#EDIT#

Wszystko już działa jak należy :D
GGG.jpg

Tylko pojawił się teraz bardziej "dojrzały" problem - optymalizacja :< Dodawanie elementów do listy, czy późniejsze jej rozwijanie trwa 1-2 s. Znalazłem jednak linijki kodu, które za to odpowiadają.

package first_pack;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;

import javax.swing.*;

public class ComboRenderer extends JLabel implements ListCellRenderer {
     
     public ComboRenderer () {

     }

     public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
          
          setFont(new Font("Consolas", Font.PLAIN, 14));
          setOpaque(true);
          
          String hex; 
          
          if (value != null) {
               
               hex = value.toString();
               
               
               //ColorChooser rgb = new ColorChooser(); <---- ColorChooser to moja klasa główna...
               //Color rgbColor = rgb.HexToRgb(hex);      <---- ...w niej też znajduje się metoda HexToRgb
							                         i to owe dwie linijki kodu powodują takie zwiechy.
               
               ColorSwatch icon = new ColorSwatch(10, true);
               icon.setColor(Color.WHITE);
               
               setText(hex);
               setIcon(icon);
          }
          return this;
     }
}

Jak by można było to rozwiązać? Odseparować metodę HexToRgb do oddzielnej klasy?

Pozdrawiam.

EDIT#

Problem rozwiązany :D Odseparowałem metodę :>

Pozdrawiam po raz ostatni uf... :P

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