Ändringar i det grafiska gränssnittet och dess komponenter ska göras av den särskilda Swing-tråden (även kallad event-dispatcher thread eller händelsetråden). Det är den tråden som alla actionPerformed normalt körs i, när man till exmepel trycker på knapapr.
Andra trådar får ändra i en grafisk komponent, men bara innan den ritats på skärmen första gången.
Programmet Client7.java
utgår från det gamla programmet
Client6.java från
föreläsning 9,
men vi har lagt till ett textfält av typen JTextField,
som visar den senaste raden som klienten fick från servern:
I Client7.java skapar vi ett JTextField
och placerar det i fönstret:
Gör så här i stället (ur programmet
Client8.java):
Programmet LAFTest.java):
Men vi kan lägga in objekt i stället för strängar i comboboxen.
Då är det objektets toString som visas i comboboxen,
men det är objektet som returneras av getSelectedItem.
Vi skapar en ny klass, LAFChoice,
och lägga in sådana objekt i comboboxen.
Klassen LAFChoice,
ur programmet LAFTest2.java):
I klassen ServerListener,
som är en tråd som läser rader från servern,
sätter vi texten i fältet:
outputField = new JTextField(30);
outputField.setEditable(false);
cp.add(outputField);
setText-anropet till utmatningsfältet kommer att
ske i ServerListener-tråden, inte i Swing-tråden.
private class ServerListener extends Thread {
public void run() {
String lineFromServer;
try {
while ((lineFromServer = in.readLine()) != null &&
!lineFromServer.equals("quit")) {
System.out.println("Från servern: " +
lineFromServer);
outputField.setText(lineFromServer);
}
}
catch (IOException e) {
System.out.println("Undantag fångat: " + e);
}
}
} // class ServerListener
private class ServerListener extends Thread {
private class OutputTextSetter implements Runnable {
private String textToSet;
public OutputTextSetter(String textToSet) {
this.textToSet = textToSet;
}
public void run() {
outputField.setText(textToSet);
}
}
public void run() {
String lineFromServer;
try {
while ((lineFromServer = in.readLine()) != null &&
!lineFromServer.equals("quit")) {
System.out.println("Från servern: " +
lineFromServer);
SwingUtilities.invokeLater(new OutputTextSetter(lineFromServer));
}
}
catch (IOException e) {
System.out.println("Undantag fångat: " + e);
}
}
} // class ServerListener
Look and feel-ändring
Hur man gör för att ändra look and feel medan man kör:
anropa bara SwingUtilities.updateComponentTreeUI().
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class LAFTest extends JFrame {
JComboBox c = new JComboBox();
JTextField t = new JTextField(30);
LAFTest outermostWindow = this;
public LAFTest() {
final UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels();
for (int i = 0; i < lafs.length; ++i) {
c.addItem(lafs[i].getName());
}
t.setEditable(false);
c.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
JComboBox box = (JComboBox)e.getSource();
for (int i = 0; i < lafs.length; ++i) {
if (lafs[i].getName() == box.getSelectedItem().toString())
try {
UIManager.setLookAndFeel(lafs[i].getClassName());
t.setText(lafs[i].getClassName());
}
catch (Exception exc) {
System.err.println("Error loading " + lafs[i].getClassName() + ": " + exc);
}
}
SwingUtilities.updateComponentTreeUI(outermostWindow);
}
});
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(t);
cp.add(c);
}
public static void main(String[] args) {
LAFTest frame = new LAFTest();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 80);
frame.setVisible(true);
}
} // class LAFTest
Använd objekt!
I exmplet med LAFTest ovan innehöll callback-metoden
actionPerformed en loop. Vi var tvungna att leta igenom listan lafs
med LookAndFeelInfo-objekt för att hitta det som har rätt getName,
dvs ett getName som stämmer med namnet som användaren valde i comboboxen.
Konstruktorn som gör ett LAFChoice-objekt,
fortfarande ur programmet LAFTest2.java):
private class LAFChoice {
UIManager.LookAndFeelInfo lafi;
public LAFChoice (UIManager.LookAndFeelInfo lafi) {
this.lafi = lafi;
}
public String toString() {
return lafi.getName();
}
public String getClassName() {
return lafi.getClassName();
}
} // class LAFChoice
public LAFTest2() { UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels(); for (int i = 0; i < lafs.length; ++i) { c.addItem(new LAFChoice(lafs[i])); } t.setEditable(false); c.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e){ JComboBox box = (JComboBox)e.getSource(); LAFChoice choice = (LAFChoice)box.getSelectedItem(); try { UIManager.setLookAndFeel(choice.getClassName()); t.setText(choice.getClassName()); } catch (Exception exc) { System.err.println("Error loading " + choice.getClassName() + ": " + exc); } SwingUtilities.updateComponentTreeUI(outermostWindow); } }); Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(t); cp.add(c); }
Programmet TextEdit.java):
import java.awt.*; import java.awt.event.*; import java.io.*; import javax.swing.*; public class TextEdit extends JFrame implements ActionListener { JPanel p = new JPanel(); JTextField namn = new JTextField(); JButton öppna = new JButton("Öppna"); JButton spara = new JButton("Spara"); JButton sluta = new JButton("Avsluta"); JTextArea area = new JTextArea(10,60); JScrollPane sp = new JScrollPane(area, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); public TextEdit() { Container c = getContentPane(); p.setFont(new Font("SansSerif", Font.PLAIN, 12)); area.setFont(new Font("Monospaced", Font.PLAIN, 12)); // placera ut komponenterna på panelen p p.setLayout(new GridLayout(1,5)); p.add(new JLabel("Filnamn: ", JLabel.RIGHT)); p.add(namn); p.add(öppna); p.add(spara); p.add(sluta); namn.addActionListener(this); öppna.addActionListener(this); spara.addActionListener(this); sluta.addActionListener(this); // placera ut panelen och textarean c.add(p, BorderLayout.NORTH); c.add(sp, BorderLayout.CENTER); pack(); setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE); } public void actionPerformed(ActionEvent e) { // undersök vilken knapp användaren har tryckt på if (e.getSource() == namn || e.getSource() == öppna) läsInFil(namn.getText()); else if (e.getSource() == spara) sparaFil(namn.getText()); else if (e.getSource() == sluta) System.exit(0); } private void läsInFil(String filnamn) { try { FileReader r = new FileReader(filnamn); area.read(r, null); } catch (IOException e) {} } private void sparaFil(String filnamn) { try { FileWriter w = new FileWriter(filnamn); area.write(w); } catch (IOException e) {} } public static void main (String[] arg) { TextEdit t = new TextEdit(); } }
Programmet Grafikdemo1.java):
import java.awt.*; import javax.swing.*; class DumFigur extends JPanel { public DumFigur() { setBackground(Color.blue); } public void paintComponent(Graphics g) { System.out.println("DumFigur.paintComponent..."); super.paintComponent(g); g.setColor(Color.black); g.drawRect(50, 100, 150, 200); g.drawRect(10, 20, 30, 40); g.fillRect(10, 20, 30, 40); g.setColor(Color.red); g.fillOval(20, 40, 60, 80); g.setColor(Color.pink); g.drawRoundRect(50, 100, 50, 100, 20, 20); g.draw3DRect(100, 150, 50, 100, true); g.draw3DRect(150, 200, 50, 100, false); } } // class DumFigur class Grafikfönster extends JFrame { public Grafikfönster(String titel) { super(titel); Container cp = getContentPane(); cp.setLayout(new GridLayout(1, 3)); cp.add(new DumFigur()); cp.add(new DumFigur()); cp.add(new DumFigur()); } } // class Grafikfönster public class Grafikdemo1 { public static void main(String[] args) { Grafikfönster g = new Grafikfönster("Grafikdemo1"); g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); g.setSize(800, 400); g.setVisible(true); } // main } // class Grafikdemo1
Programmet Grafikdemo2.java):
import java.awt.*; import javax.swing.*; import javax.swing.border.*; class Cirkeldiagram extends JPanel { private int värde; private int max; public Cirkeldiagram(int värde, int max) { if (max <= 0) throw new IllegalArgumentException("max = " + max + ", ska vara > 0"); if (värde < 0 || värde > max) throw new IllegalArgumentException("värde = " + värde + ", ska vara 0.." + max); this.värde = värde; this.max = max; setBackground(Color.white); } public Cirkeldiagram(int värde) { this(värde, 100); } public Cirkeldiagram() { this(0, 100); } public void setVärde(int värde) { if (värde < 0 || värde > max) throw new IllegalArgumentException("värde = " + värde + ", ska vara 0.." + max); this.värde = värde; repaint(); } public void paintComponent(Graphics g) { System.out.println("Cirkeldiagram.paintComponent..."); super.paintComponent(g); g.setColor(Color.blue); Insets i = getInsets(); System.out.println(" i = " + i); int bredd = getWidth() - i.left - i.right; int höjd = getHeight() - i.top - i.bottom; int diameter = Math.min(bredd, höjd); int x = i.left + (bredd - diameter) / 2; int y = i.top + (höjd - diameter) / 2; g.drawOval(x, y, diameter, diameter); double andel = (double)värde / max; int vinkelandel = (int)(andel * 360 + 0.5); g.fillArc(x, y, diameter, diameter, 90, -vinkelandel); } } // class Cirkeldiagram class Grafikfönster extends JFrame { public Grafikfönster(String titel) { super(titel); Container cp = getContentPane(); cp.setLayout(new GridLayout(1, 3)); Cirkeldiagram cd1 = new Cirkeldiagram(10, 100); Cirkeldiagram cd2 = new Cirkeldiagram(75, 100); Cirkeldiagram cd3 = new Cirkeldiagram(55, 100); cd2.setBorder(new EtchedBorder()); cd3.setBorder(new LineBorder(Color.green, 15)); cp.add(cd1); cp.add(cd2); cp.add(cd3); } } // class Grafikfönster public class Grafikdemo2 { public static void main(String[] args) { Grafikfönster g = new Grafikfönster("Grafikdemo2"); g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); g.setSize(800, 400); g.setVisible(true); } // main } // class Grafikdemo2
Ur programmet Grafikdemo3.java):
class Grafikfönster extends JFrame { private Cirkeldiagram cd = new Cirkeldiagram(0, 100); public Grafikfönster(String titel) { super(titel); Container cp = getContentPane(); cp.setLayout(new BorderLayout()); cd.setBorder(new EtchedBorder()); cp.add(cd, BorderLayout.CENTER); JSlider s = new JSlider(0, 100, 0); cp.add(s, BorderLayout.SOUTH); s.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { cd.sättVärde(((JSlider)e.getSource()).getValue()); } }); } } // class Grafikfönster
Placera reglaget och knappen på en JPanel.
Ur programmet Grafikdemo4.java):
class Grafikfönster extends JFrame { private Cirkeldiagram cd = new Cirkeldiagram(0, 100); JSlider s = new JSlider(0, 100, 0); public Grafikfönster(String titel) { super(titel); Container cp = getContentPane(); cp.setLayout(new BorderLayout()); cd.setBorder(new EtchedBorder()); cp.add(cd, BorderLayout.CENTER); JPanel p = new JPanel(); p.setLayout(new FlowLayout()); s.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { cd.setVärde(((JSlider)e.getSource()).getValue()); } }); p.add(s); JButton b = new JButton("Nollställ"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { s.setValue(0); cd.setVärde(0); } }); p.add(b); cp.add(p, BorderLayout.SOUTH); } } // class Grafikfönster