Czy istnieje sposób na utworzenie JButton
własnej grafiki przycisku, a nie tylko z obrazem wewnątrz przycisku?
Jeśli nie, czy istnieje inny sposób tworzenia niestandardowego JButton
w java?
Odpowiedzi:
Kiedy po raz pierwszy uczyłem się Javy, musieliśmy stworzyć Yahtzee i pomyślałem, że fajnie byłoby tworzyć własne komponenty i kontenery Swinga zamiast rysować wszystko na jednym JPanel
. Zaletą rozszerzenia Swing
komponentów jest oczywiście możliwość dodania obsługi skrótów klawiaturowych i innych funkcji ułatwień dostępu, których nie można zrobić po prostu posiadającpaint()
wydrukowanie ładnego obrazka metody. Może nie być to jednak najlepsze rozwiązanie, ale może to być dla Ciebie dobry punkt wyjścia.
Edytuj 8/6 - Jeśli nie widać tego na zdjęciach, każda kostka jest przyciskiem, na który możesz kliknąć. Spowoduje to przeniesienie go DiceContainer
poniżej. Patrząc na kod źródłowy, możesz zobaczyć, że każdy przycisk Die jest rysowany dynamicznie, na podstawie jego wartości.
Oto podstawowe kroki:
JComponent
super()
w swoich konstruktorachMouseListener
Umieść to w konstruktorze:
enableInputMethods(true);
addMouseListener(this);
Zastąp te metody:
public Dimension getPreferredSize()
public Dimension getMinimumSize()
public Dimension getMaximumSize()
Zastąp tę metodę:
public void paintComponent(Graphics g)
Ilość miejsca, z którym musisz pracować podczas rysowania przycisku, jest definiowana przez getPreferredSize()
, przyjmowanie getMinimumSize()
i getMaximumSize()
zwracanie tej samej wartości. Nie eksperymentowałem zbyt wiele z tym, ale w zależności od układu używanego w GUI, twój przycisk może wyglądać zupełnie inaczej.
I na koniec kod źródłowy . Na wypadek, gdybym coś przeoczył.
Tak, jest to możliwe. Jedną z głównych zalet używania Swinga jest łatwość, z jaką można tworzyć abstrakcyjne kontrolki i manipulować nimi.
Oto szybki i brudny sposób na rozszerzenie istniejącej klasy JButton, aby narysować okrąg po prawej stronie tekstu.
package test;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
public class MyButton extends JButton {
private static final long serialVersionUID = 1L;
private Color circleColor = Color.BLACK;
public MyButton(String label) {
super(label);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension originalSize = super.getPreferredSize();
int gap = (int) (originalSize.height * 0.2);
int x = originalSize.width + gap;
int y = gap;
int diameter = originalSize.height - (gap * 2);
g.setColor(circleColor);
g.fillOval(x, y, diameter, diameter);
}
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
size.width += size.height;
return size;
}
/*Test the button*/
public static void main(String[] args) {
MyButton button = new MyButton("Hello, World!");
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
Container contentPane = frame.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(button);
frame.setVisible(true);
}
}
Zwróć uwagę, że nadpisując paintComponent można zmienić zawartość przycisku, ale obramowanie jest malowane metodą paintBorder . Należy również zarządzać metodą getPreferredSize , aby dynamicznie obsługiwać zmiany zawartości. Należy zachować ostrożność podczas pomiaru wskaźników czcionek i wymiarów obrazu.
Powyższy kod nie jest właściwym podejściem do tworzenia kontrolki, na której można polegać. Wymiary i kolory w Swing są dynamiczne i zależą od wyglądu i stylu użytkowania. Nawet domyślny wygląd Metal zmienił się w wersjach JRE. Byłoby lepiej zaimplementować AbstractButton i przestrzegać wytycznych określonych przez Swing API. Dobrym punktem wyjścia jest przyjrzenie się plikom javax.swing.LookAndFeel i javax.swing.UIManager klasom .
http://docs.oracle.com/javase/8/docs/api/javax/swing/LookAndFeel.html
http://docs.oracle.com/javase/8/docs/api/javax/swing/UIManager.html
Zrozumienie anatomii LookAndFeel jest przydatne do pisania kontrolek: Tworzenie niestandardowego wyglądu i stylu
Zawsze możesz wypróbować wygląd i styl Syntezatora. Dostarczasz plik xml, który działa jak rodzaj arkusza stylów, wraz z dowolnymi obrazami, których chcesz użyć. Kod może wyglądać następująco:
try {
SynthLookAndFeel synth = new SynthLookAndFeel();
Class aClass = MainFrame.class;
InputStream stream = aClass.getResourceAsStream("\\default.xml");
if (stream == null) {
System.err.println("Missing configuration file");
System.exit(-1);
}
synth.load(stream, aClass);
UIManager.setLookAndFeel(synth);
} catch (ParseException pe) {
System.err.println("Bad configuration file");
pe.printStackTrace();
System.exit(-2);
} catch (UnsupportedLookAndFeelException ulfe) {
System.err.println("Old JRE in use. Get a new one");
System.exit(-3);
}
Następnie kontynuuj i dodaj swój JButton tak, jak zwykle. Jedyną zmianą jest to, że używasz metody setName (string), aby określić, do czego powinien mapować przycisk w pliku xml.
Plik xml może wyglądać następująco:
<synth>
<style id="button">
<font name="DIALOG" size="12" style="BOLD"/>
<state value="MOUSE_OVER">
<imagePainter method="buttonBackground" path="dirt.png" sourceInsets="2 2 2 2"/>
<insets top="2" botton="2" right="2" left="2"/>
</state>
<state value="ENABLED">
<imagePainter method="buttonBackground" path="dirt.png" sourceInsets="2 2 2 2"/>
<insets top="2" botton="2" right="2" left="2"/>
</state>
</style>
<bind style="button" type="name" key="dirt"/>
</synth>
Znajdujący się tam element bind określa, na co należy odwzorować (w tym przykładzie zastosuje on ten styl do wszystkich przycisków, których właściwość name została ustawiona na „dirt”).
I kilka przydatnych linków:
http://javadesktop.org/articles/synth/
http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/synth.html
Pewnie jadę milion mil w złym kierunku (ale jestem dopiero młody: P). ale nie mógłbyś dodać grafiki do panelu, a następnie wskaźnika myszy do obiektu graficznego, tak aby gdy użytkownik znajdował się na grafice, Twoja akcja była wykonywana.
Nie tworzyłem SWINGa od moich wczesnych zajęć z CS, ale gdyby nie był wbudowany, mógłbyś po prostu dziedziczyć javax.swing.AbstractButton
i tworzyć własne. Powinno być całkiem proste, aby połączyć coś razem z istniejącymi szkieletami.