GUI Tutorial 2 - Colorado School of Mines

Download Report

Transcript GUI Tutorial 2 - Colorado School of Mines

GUI Tutorial 2
What did we do last time?

Basic flow



JFrame
Event-driven programming





action listener for buttons
Simple pop-up dialogs (JOptionPane)
Layout managers


instance variables, set up in ctor, close operation, size, visible
BorderLayout, FlowLayout, GridLayout
JPanel
JTextField, JLabel, Jbutton, JCheckBox, JComboBox,
JRadioButton, JRadioGroup
Borders and Fonts
What will we do this time?





Add actions to other controls
JMenu/JMenuItem
JTextArea
Panel Communication
Simple Drawing
Add a menu




Menus are added to the JFrame – not a JPanel
Menus are added via setJMenuBar – not add
The menu system consists of one JMenuBar and one or
more objects of type JMenu containing JMenuItem
In the JFrame constructor:
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
menuBar.add(createFileMenu());
The menu
private JMenu createFileMenu()
{
JMenu menu = new JMenu("File");
menu.add(createFileExitItem());
return menu;
}
private JMenuItem createFileExitItem()
{
JMenuItem item = new JMenuItem("Exit");
class MenuItemListener implements ActionListener {
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
}
item.addActionListener(new MenuItemListener());
return item;
}
Panel Communication – Remember this?
Main panel
Control Panel
Panel communication

Remember that communication between objects can be
thought of as message passing. For our program, we’ll
create a DisplayPanel to display a summary of the choices.
This panel should be updated every time a change is
made to one of the panels.
ToFromPanel
PreferencePanel
WillDrivePanel
Update the
status
DisplayPanel
Panel Communication - UML
First create a DisplayPanel
public class DisplayPanel extends JPanel {
// Variables for message
private String name, fromCity,toCity, willDrive, smoker;
// display – multiple lines allowed in JTextArea
private JTextArea display;
public DisplayPanel()
{ // set some default values
name = "Someone";
fromCity = "Somewhere";
toCity = "Somewhere";
willDrive = "needs a ride";
smoker = "no smoking";
display = new JTextArea(2, 20);
display.setLineWrap(true); // uses multiple lines
display.setWrapStyleWord(true); // breaks on word
boundaries
updateDisplay();
add(display);
}
Update method
private void updateDisplay()
{
display.setText(name + " " + willDrive + " from " + fromCity
+ " to " + toCity + " and prefers " + smoker);
}
} // end class
Panel communication

Other panels will need to be able to send values to set
the variables for this message. Use Eclipse to create
setters.
Where to send the message?


Other panels will need to have access to the DisplayPanel.
How to do this? Send a reference into the constructor.
In the PreferencePanel:
private DisplayPanel dp;
public PreferencePanel(DisplayPanel dp)
{
this.dp = dp;
notice use of this keyword
. . .

Update all the panels.
How to send?

Update the constructor of the JFrame (CarpoolGUI)
// Create DisplayPanel first
DisplayPanel dp = new DisplayPanel();
add(dp, BorderLayout.SOUTH);
// Send it into other 3 panels
PreferencePanel pPanel = new PreferencePanel(dp);
add(pPanel, BorderLayout.EAST);
ToFromPanel tfPanel = new ToFromPanel(dp);
add(tfPanel, BorderLayout.CENTER);
WillDrivePanel wdPanel = new WillDrivePanel(dp);
add(wdPanel, BorderLayout.NORTH);
All panels now display
Now we need to add some action
Add action – radio button

Need a radio listener
private class RadioListener implements ActionListener {
public void actionPerformed(ActionEvent e)
{
if (smokeButton.isSelected())
dp.setSmoker("smoking");
else
dp.setSmoker("no smoking");
}
}

Need to add listener to each button
RadioListener listener = new RadioListener();
smokeButton.addActionListener(listener);
noSmokeButton.addActionListener(listener);
Need to call updateDisplay

In DisplayPanel, the setters need to cause the display to
update, for example:
public void setSmoker(String smoker) {
this.smoker = smoker;
updateDisplay();
}
Add action - CheckBox
private class CheckboxListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (willDriveCB.isSelected())
dp.setWillDrive("will drive");
else
dp.setWillDrive("needs a ride");
}
}

Add the action listener to our check box:
willDriveCB.addActionListener(new CheckboxListener());
Add action – Focus Listener




The Java interpreter knows which component has the
“focus” – e.g., if the mouse is in the name field, it has
focus. If you click on some other field, the name field
“loses” focus.
FocusListener is an interface that can be used to respond
to focus events.
Two methods must be defined: focusGained and
focusLost. You must write both of these methods, even if
you’re only interested in one type of event. The other
method may have an empty body.
Be sure to include java.awt.event.*; (or specific classes)
Our focus listener
private class NameListener implements FocusListener
{
// We don’t care when we get focus
public void focusGained(FocusEvent e) {}
// When we lose focus, need to update the display
public void focusLost(FocusEvent e)
{
dp.setName(name.getText());
}
}

Add the focus listener to the name field. Since only one component
uses this listener, we don’t bother creating a local variable.
name.addFocusListener(new NameListener());
Add action - ComboBox


Fires both action events and item events. Item events
respond to any change of state, whether caused by the
program or the user. Action events are called when the
user interacts with the component.
For user actions, both events will be generated. You
should only listen for one type of event. Typically you’re
interested in the user’s actions, so use an action listener.
Add action - ComboBox

We’ll use the same listener for both boxes. We’ll use the
ActionEvent getSource method to determine which one changed.
private class ComboListener implements ActionListener {
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == toCity)
dp.setToCity(toCity.getSelectedItem().toString());
else
dp.setFromCity(fromCity.getSelectedItem().toString());
}
}

Add the listener to both combo boses.
ComboListener listener = new ComboListener();
fromCity.addActionListener(listener);
toCity.addActionListener(listener);
That’s all, folks!
Eclipse Hint:



Edit > Select All (Ctrl-A)
Source > Correct Indentation (Ctrl-I)
All programs that are turned in for grading should be
neatly formatted!
Drawing
The Graphics class –Get the concept!
From the Sun documentation:
The Graphics class is the abstract base class for all graphics contexts that
allow an application to draw onto components that are realized on various
devices, as well as onto off-screen images.
A Graphics object encapsulates state information needed for the basic
rendering operations that Java supports. This state information includes the
following properties:

The Component object on which to draw.

A translation origin for rendering and clipping coordinates.

The current clip.

The current color.

The current font.

The current logical pixel operation function (XOR or Paint).

The current XOR alternation color (see setXORMode(java.awt.Color)).
Graphics class continued

Sample methods:







drawImage
drawLine/fillLine
drawOval/fillOval
drawRect/fillRect
drawString
setColor
setFont
x: 0 ..
y
0
.
.
Example line from ~10 10 to ~20 20
Graphics class, continued


Graphics is abstract, can’t call constructor directly
Can be obtained by calling getGraphics on a component
usually don’t need to!


Automatically created for the paintComponent method of
any class that extends JComponent (either directly or
indirectly)
paintComponent is called automatically when the component
needs to be redrawn




initial load
when repaint() method called
when screen is resized etc.
BEST STRATEGY: write the paintComponent method, call
repaint() when you need to update the drawing
Drawing – Basic Strategy
1.
2.
3.
4.
5.
6.
7.
8.
As always, create a JFrame
Create a class that extends JComponent or JPanel to contain your
drawing
Add that JPanel to your JFrame (often to the CENTER)
In that class, override paintComponent(Graphics g) method.
Inside the method, use draw commands as needed to create your image
(e.g., g.drawLine(…))
paintComponent will be called automatically when the screen needs to be
redrawn (e.g., when first displayed, if minimized then maximized, etc).
Inside paintComponent, call super.paintComponent for required
housekeeping – IMPORTANT!
If you need to update the drawing, do not call paintComponent directly.
Instead, call repaint().
Example: change player’s position in Clue, call repaint() on your board (either board.repaint(); or repaint();
depending on what method is updating the player’s location).
Create a JPanel
import javax.swing.*;
import java.awt.*;
public class DrawPanel extends JPanel {
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Remember this for housekeeping (e.g., background)
g.setColor(Color.BLUE);
g.drawRect(10, 15, 20, 20);
}
}
Create a frame, add the component
public class DrawFrame extends JFrame {
private DrawPanel drawPanel;
public DrawFrame()
{
drawPanel = new DrawPanel();
// paintComponent will automatically be
// called 1 time
add(drawPanel, BorderLayout.CENTER);
setSize(300, 300);
}
public static void main(String[] args) {
DrawFrame frame = new DrawFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Let’s make some changes
public class DrawPanel extends JPanel
public void translate(int dx, int dy)
{
{
private int x, y;
x += dx;
public DrawPanel()
y += dy;
{
// Must include this to see changes
repaint();
x = 10;
y = 15;
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawRect(x, y, 20, 20);
}
}
And call it from main…
public void updateDrawing(int dx, int dy)
{
drawPanel.translate(dx, dy);
}
public static void main(String[] args) {
DrawFrame frame = new DrawFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
// This will cause rectangle to display in new location
frame.updateDrawing(100, 100);
}
Let’s put in a delay
public void updateDrawing(int dx, int dy)
{
this.dx = dx; // need to add instance variables
this.dy = dy;
// 1000 millisecond delay
Timer t = new Timer(1000, new TimerListener());
t.start();
Be sure to get javax.swing.Timer
}
private class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
drawPanel.translate(dx, dy);
}
}
Complete Program
public class DrawFrame extends JFrame {
public class DrawPanel extends JPanel {
private DrawPanel drawPanel;
private int x, y;
private int dx, dy;
public DrawPanel(int x, int y) {
this.x = x;
public DrawFrame() {
this.y = y;
drawPanel = new DrawPanel(10, 15);
add(drawPanel, BorderLayout.CENTER);
}
setSize(300, 300);
public void paintComponent(Graphics g) {
}
super.paintComponent(g);
public void updateDrawing(int dx, int dy) {
this.dx = dx;
g.setColor(Color.BLUE);
this.dy = dy;
g.drawRect(x, y, 20, 20);
Timer t = new Timer(1000, new TimerListener());
System.out.println("Called paint component");
t.start();
}
private class TimerListener implements ActionListener
{
}
public void translate(int dx, int dy) {
x += dx;
public void actionPerformed(ActionEvent e) {
y += dy;
drawPanel.translate(dx, dy); } }
// Must include this to see changes
public static void main(String[] args) {
DrawFrame frame = new DrawFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.updateDrawing(5, 10);
}
}
repaint();
}
}