Ä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 exempel 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 8 B,
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