Text under Shape in java - java

I want to create a draggable component contains a shape (circle) and a text (JLabel) under it. But i dont get the shape and text in the jpanel. I attached the code below.
SubMapViewer Class
package test;
import com.businesslense.topology.client.config.Condition;
import com.businesslense.topology.client.config.ConfigReader;
import com.businesslense.topology.client.config.NodeConfig;
import com.businesslense.topology.client.config.Parameter;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class SubMapViewer extends JLayeredPane {
#Override
public void paint(Graphics grphcs) {
super.paint(grphcs); //To change body of generated methods, choose Tools | Templates.
System.out.println("Paint called");
}
public void showMap() {
Runnable gui = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame f = new JFrame("Draggable Components");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 300);
f.setLocationRelativeTo(null);
JLayeredPane panel = new SubMapViewer();
panel.setLayout(null);
NodeComponent nodeComponent = new NodeComponent(50);
JPanel jPanel = new JPanel();
jPanel.setSize(100, 100);
jPanel.setBorder(javax.swing.BorderFactory.createLineBorder(Color.BLACK, 2));
jPanel.add(nodeComponent);
jPanel.setVisible(true);
Draggable d2 = new Draggable(jPanel, 200, 150);
panel.add(d2);
f.add(panel);
f.setVisible(true);
}
};
//GUI must start on EventDispatchThread:
SwingUtilities.invokeLater(gui);
}
Properties getDisplayProperties(Properties properties) {
//List<String> menuList = new ArrayList<>();
List<com.businesslense.topology.client.config.NodeConfig> nodeConfigs = ConfigReader.getData().getNodeConfig();
outer:
for (Iterator<NodeConfig> it = nodeConfigs.iterator(); it.hasNext();) {
NodeConfig nodeConfig = it.next();
List<Condition> conditions = nodeConfig.getCondtion();
boolean match = false;
for (Iterator<Condition> it1 = conditions.iterator(); it1.hasNext();) {
Condition condition = it1.next();
if (condition.getValue().equalsIgnoreCase("" + properties.get(condition.getName()))) {
match = true;
} else {
continue outer;
}
}
if (match) {
Properties displayProperties = new Properties();
for (Iterator<Parameter> it1 = nodeConfig.getParameter().iterator(); it1.hasNext();) {
Parameter parameter = it1.next();
displayProperties.put(parameter.getName(), parameter.getValue());
}
return displayProperties;
}
}
return null;
}
public static void main(String[] arv) {
SubMapViewer subMapViewer = new SubMapViewer();
subMapViewer.showMap();
}
}
NodeComponent Class
package test;
import com.businesslense.topology.client.marker.DefaultNodeComponent;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.apache.log4j.Logger;
public class NodeComponent extends JPanel {
private String name;
private Integer size;
static Logger logger = Logger.getLogger(DefaultNodeComponent.class.getName());
public NodeComponent(Integer size) {
setLayout(null);
setSize(size , size * 2);
this.size = size;
this.name = "ICON NAME";
JLabel textLabel = new JLabel(name);
textLabel.setLocation(size, 10);
add(textLabel);
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
int shapePaddingVal = (size * 5) / 100;
int shapeRadius = (size * 90) / 100;
Color shapeColor = Color.BLACK;
g2d.setColor(shapeColor);
g2d.setStroke(new BasicStroke(2));
g2d.drawOval(shapePaddingVal, shapePaddingVal, shapeRadius/2, shapeRadius/2);
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(0, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
}
}
Draggable Class
package test;
/*
* Draggable.java
*/
import java.awt.*;
import javax.swing.*;
import java.awt.event.MouseEvent;
import javax.swing.border.Border;
import javax.swing.event.MouseInputAdapter;
public class Draggable extends JComponent {
private Point pointPressed;
private JComponent draggable;
public Draggable(final JComponent component, final int x, final int y) {
draggable = component;
// draggable.setCursor(draggable.getCursor());
setCursor(new Cursor(Cursor.HAND_CURSOR));
setLocation(x, y);
setSize(component.getPreferredSize());
setLayout(new BorderLayout());
add(component);
MouseInputAdapter mouseAdapter = new MouseHandler();
addMouseMotionListener(mouseAdapter);
addMouseListener(mouseAdapter);
}
#Override
public void setBorder(final Border border) {
super.setBorder(border);
if (border != null) {
Dimension size = draggable.getPreferredSize();
Insets insets = border.getBorderInsets(this);
size.width += (insets.left + insets.right + 5);
size.height += (insets.top + insets.bottom);
setSize(size);
}
}
private class MouseHandler extends MouseInputAdapter {
#Override
public void mouseDragged(final MouseEvent e) {
Point pointDragged = e.getPoint();
Point loc = getLocation();
loc.translate(pointDragged.x - pointPressed.x,
pointDragged.y - pointPressed.y);
setLocation(loc);
}
#Override
public void mousePressed(final MouseEvent e) {
pointPressed = e.getPoint();
}
}
}

I want to create a draggable component contains a shape (circle) and a text (JLabel) under it
Why don't you use use a JLabel with an Icon and text?
NodeComponent nodeComponent = new NodeComponent(50);
JPanel jPanel = new JPanel();
jPanel.setSize(100, 100);
jPanel.add(nodeComponent);
By default a JPanel uses a FlowLayout, which respects the components "preferred size". Your NodeComponent class should override the getPreferredSize() method to return a realistic value. Another reason for just using a JLabel since it will determine the preferred size for you based on the Icon and text.
JLabel textLabel = new JLabel(name);
textLabel.setLocation(size, 10);
add(textLabel);
You are adding the label to the component which uses a null layout. Since the size is zero, the text will not display.

Related

Mouse listener not working with JPanel

The paintcomponent works fine, the image shows up, no problems on that end or with the JFrame. I want to implement zooming and panning but not getting any luck as the added mouse listener isn't responding.
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import javax.swing.JPanel;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
public class map extends JPanel {
public int moz = 100;
public void map()
{
addMouseListener(
new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
moz = moz +100;
repaint();
}
}
);
}
public void paintComponent(Graphics g){
.....
g.drawLine( 0, moz, 100, 0 );
}
}
Your class doesn't have a real constructor but rather has a "pseudo" constructor since it has a return type -- yes void counts. So get rid of the void return type by changing:
// this is not a constructor
public void map()
to:
// this is a real constructor
public map()
Also as a side recommendation, change your variable and class names to conform with Java naming conventions: class names all start with an upper-case letter and method/variable names with a lower-case letter.
So in your case you'd name your class Map, and in playing with the code could have something like:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class Map extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Color DRAW_RECT_COLOR = new Color(200, 200, 255);
public static final Stroke IMAGE_STROKE = new BasicStroke(3f);
public static final Color IMAGE_COLOR = Color.RED;
private BufferedImage image = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
private Rectangle drawRectangle = null;
private List<Color> colors = new ArrayList<>();
private Random random = new Random();
public Map() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
for (int r = 0; r < 4; r++) {
int r1 = (r * 255) / 3;
for (int g = 0; g < 4; g++) {
int g1 = (g * 255) / 3;
for (int b = 0; b < 4; b++) {
int b1 = (b * 255) / 3;
colors.add(new Color(r1, g1, b1));
}
}
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
Graphics2D g2 = (Graphics2D) g;
if (drawRectangle != null) {
g.setColor(DRAW_RECT_COLOR);
g2.draw(drawRectangle);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
Point p1 = null;
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
if (p1 == null) {
return;
}
Point p2 = e.getPoint();
drawRectangle = createDrawRect(p2);
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
Rectangle rectangle = createDrawRect(e.getPoint());
Graphics2D g2 = image.createGraphics();
g2.setStroke(IMAGE_STROKE);
Color c = colors.get(random.nextInt(colors.size()));
g2.setColor(c);
g2.draw(rectangle);
g2.dispose();
p1 = null;
drawRectangle = null;
repaint();
}
private Rectangle createDrawRect(Point p2) {
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int w = Math.abs(p1.x - p2.x);
int h = Math.abs(p1.y - p2.y);
return new Rectangle(x, y, w, h);
}
}
private static void createAndShowGui() {
Map mainPanel = new Map();
JFrame frame = new JFrame("Map");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

GUI button placement

I am trying to design a GUI with triangle shaped buttons. I have create the triangle button class correctly in so far as creating a JButton with my class constructor results in a triangle button on the page, but I fall short when it comes to placement of the button.
Could any direct me or have an example for creating a hexagonal shape from triangle buttons?
Here is my TriangleButton class for reference:
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
class TriangleButton extends JButton {
final static double side_len = 52; //Change for variable triangle size
final static double y_offset = (Math.sqrt(3) * side_len / 2);
private Shape triangle;
public TriangleButton(int spot){
triangle = createTriangle(spot);
}
public void paintBorder( Graphics g ) {
((Graphics2D)g).draw(triangle);
}
public void paintComponent( Graphics g ) {
((Graphics2D)g).fill(triangle);
}
public Dimension getPreferredSize() {
return new Dimension((int)side_len, (int)y_offset);
}
public boolean contains(int x, int y) {
return triangle.contains(x, y);
}
private Shape createTriangle(int spot) {
Polygon p = new Polygon();
p.addPoint( 0 , 0 );
p.addPoint( (int)side_len , 0 );
p.addPoint( (int)side_len/2, (int)(y_offset) );
return p;
}
}
The look I had in mind would be something like..
With space between the buttons.. basically just up-pointing and down-pointing triangles lined up.
But anything to put me in the right direction would be appreciated!
As an alternative, due to the complexities of generating a suitable layout to allow components to overlap, you could simply create a single button which housed all the triangles and which provided centralised control, for example
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Path2D;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractButton;
import javax.swing.DefaultButtonModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
HexagonButton btn = new HexagonButton();
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(Arrays.toString(btn.getSelectedObjects()));
System.out.println(e.getActionCommand());
}
});
add(btn);
}
}
public class HexagonButton extends AbstractButton {
public static final String TOP_RIGHT_QUAD = "Top.right";
public static final String TOP_QUAD = "Top";
public static final String TOP_LEFT_QUAD = "Top.left";
public static final String BOTTOM_LEFT_QUAD = "Bottom.left";
public static final String BOTTOM_QUAD = "Bottom";
public static final String BOTTOM_RIGHT_QUAD = "Bottom.right";
private Shape top;
private Shape topRight;
private Shape topLeft;
private Shape bottomLeft;
private Shape bottomRight;
private Shape bottom;
private Map<String, Shape> paths;
private String selectedQuad;
public HexagonButton() {
setModel(new DefaultButtonModel());
createPaths();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
String previousQuad = selectedQuad;
selectedQuad = null;
for (String quad : paths.keySet()) {
Shape shape = paths.get(quad);
if (shape.contains(e.getPoint())) {
getModel().setPressed(true);
getModel().setArmed(true);
selectedQuad = quad;
if (!selectedQuad.equals(previousQuad)) {
fireActionPerformed(new ActionEvent(HexagonButton.this, ActionEvent.ACTION_PERFORMED, selectedQuad));
}
break;
}
}
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
getModel().setArmed(false);
getModel().setPressed(false);
}
});
}
#Override
public Object[] getSelectedObjects() {
return new Object[]{selectedQuad};
}
#Override
public void invalidate() {
super.invalidate();
createPaths();
}
protected void createPaths() {
topRight = create(0d, -60d);
top = create(-60d, -120d);
topLeft = create(-120d, -180d);
bottomLeft = create(-180d, -240d);
bottom = create(-240d, -300d);
bottomRight = create(-300d, -360d);
paths = new HashMap<>(6);
paths.put(TOP_RIGHT_QUAD, topRight);
paths.put(TOP_QUAD, top);
paths.put(TOP_LEFT_QUAD, topLeft);
paths.put(BOTTOM_LEFT_QUAD, bottomLeft);
paths.put(BOTTOM_QUAD, bottom);
paths.put(BOTTOM_RIGHT_QUAD, bottomRight);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(104, 104);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
Graphics2D g2d = (Graphics2D) g.create();
if (selectedQuad != null) {
Shape path = paths.get(selectedQuad);
g2d.setColor(UIManager.getColor("List.selectionBackground"));
g2d.fill(path);
}
g2d.setColor(getForeground());
g2d.draw(topRight);
g2d.draw(top);
g2d.draw(topLeft);
g2d.draw(bottomLeft);
g2d.draw(bottom);
g2d.draw(bottomRight);
g2d.dispose();
}
public Shape create(double startAngle, double endAngle) {
double width = getWidth();
double height = getHeight();
double radius = Math.min(width, height) / 2;
double xOffset = width - radius;
double yOffset = height - radius;
double startX = xOffset + radius * (Math.cos(Math.toRadians(startAngle)));
double startY = yOffset + radius * (Math.sin(Math.toRadians(startAngle)));
double endX = xOffset + radius * (Math.cos(Math.toRadians(endAngle)));
double endY = yOffset + radius * (Math.sin(Math.toRadians(endAngle)));
Path2D path = new Path2D.Double();
path.moveTo(xOffset, yOffset);
path.lineTo(startX, startY);
path.lineTo(endX, endY);
path.closePath();
return path;
}
}
public static class TriangleButton extends JButton {
final static double side_len = 52; //Change for variable triangle size
final static double y_offset = (Math.sqrt(3) * side_len / 2);
private Shape triangle;
public TriangleButton(int spot) {
triangle = createTriangle(spot);
}
#Override
public void paintBorder(Graphics g) {
super.paintBorder(g);
((Graphics2D) g).draw(triangle);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
((Graphics2D) g).fill(triangle);
}
#Override
public Dimension getPreferredSize() {
return new Dimension((int) side_len, (int) y_offset);
}
#Override
public boolean contains(int x, int y) {
return triangle.contains(x, y);
}
private Shape createTriangle(int spot) {
Polygon p = new Polygon();
p.addPoint(0, 0);
p.addPoint((int) side_len, 0);
p.addPoint((int) side_len / 2, (int) (y_offset));
return p;
}
}
}
Using your class I made some changes and came up with the following:
import java.awt.*;
import java.awt.Shape;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.*;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class TriangleButton2 extends JButton {
final static double side_len = 52; //Change for variable triangle size
final static double y_offset = (Math.sqrt(3) * side_len / 2);
private Shape triangle;
public TriangleButton2(int degrees){
triangle = createTriangle(degrees);
setRolloverEnabled( false );
setContentAreaFilled( false );
setBorderPainted( false );
}
public void paintBorder( Graphics g ) {
((Graphics2D)g).draw(triangle);
}
public void paintComponent( Graphics g ) {
super.paintComponent(g);
((Graphics2D)g).fill(triangle);
}
public Dimension getPreferredSize() {
return new Dimension((int)side_len, (int)y_offset);
}
public boolean contains(int x, int y) {
return triangle.contains(x, y);
}
private Shape createTriangle(int degrees) {
Polygon p = new Polygon();
p.addPoint( 0 , 0 );
p.addPoint( (int)side_len , 0 );
p.addPoint( (int)side_len/2, (int)(y_offset) );
return ShapeUtils.rotate(p, degrees);
// return p;
}
private static void createAndShowGUI()
{
JPanel panelNorth = new JPanel( new FlowLayout(FlowLayout.CENTER, -22, 2) );
panelNorth.add( new TriangleButton2(180) );
panelNorth.add( new TriangleButton2(0) );
panelNorth.add( new TriangleButton2(180) );
JPanel panelSouth = new JPanel( new FlowLayout(FlowLayout.CENTER, -22, 1) );
panelSouth.add( new TriangleButton2(0) );
panelSouth.add( new TriangleButton2(180) );
panelSouth.add( new TriangleButton2(0) );
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panelNorth, BorderLayout.NORTH);
frame.add(panelSouth, BorderLayout.SOUTH);
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
The above code uses the ShapeUtils class found in Playing With Shapes.
Not sure of the exact functionality you want from the button. Your current implantation doesn't have any visual effects when you click on the button or mouse over the button.
In this case you might want to consider just creating an Icon to represent your triangle. you can use the ShapeIcon class found in Playing With Shapes to create your triangle icons. Then you can use the ShapeComponent class also found in Playing With Shapes to create an actual component that you add to the panel.
The FlowLayout shows how you can overlap the buttons to get your desired layout effect.
Check out this page for some relatable information:
Creating custom JButton from images containing transparent pixels
It just might be easier creating JButtons from triangle images.

custom java Swing component Model, UIDelegate, component format

I was given the task to create a custom swing component. I have my component functioning properly in a test application which includes JSlider that is used to zoom in and out on an Image. However I am required to present my custom component in a Model, UIDelegate, and Component class format and I am totally lost on how to convert my code so that it follows this format. Here is the code for my test application.
package test;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.*;
import java.io.File;
import java.net.URL;
import javax.imageio.ImageIO;
public class ZoomDemo extends JComponent implements ChangeListener {
JPanel gui;
/**
* Displays the image.
*/
JLabel imageCanvas;
Dimension size;
double scale = 1.0;
private BufferedImage image;
public ZoomDemo() {
size = new Dimension(10, 10);
setBackground(Color.black);
try {
image = ImageIO.read(new File("car.jpg"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void setImage(Image image) {
imageCanvas.setIcon(new ImageIcon(image));
}
public void initComponents() {
if (gui == null) {
gui = new JPanel(new BorderLayout());
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
imageCanvas = new JLabel();
JPanel imageCenter = new JPanel(new GridBagLayout());
imageCenter.add(imageCanvas);
JScrollPane imageScroll = new JScrollPane(imageCenter);
imageScroll.setPreferredSize(new Dimension(300, 100));
gui.add(imageScroll, BorderLayout.CENTER);
}
}
public Container getGui() {
initComponents();
return gui;
}
public void stateChanged(ChangeEvent e) {
int value = ((JSlider) e.getSource()).getValue();
scale = value / 100.0;
paintImage();
}
protected void paintImage() {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
BufferedImage bi = new BufferedImage(
(int)(imageWidth*scale),
(int)(imageHeight*scale),
image.getType());
Graphics2D g2 = bi.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform at = AffineTransform.getTranslateInstance(0, 0);
at.scale(scale, scale);
g2.drawRenderedImage(image, at);
setImage(bi);
}
public Dimension getPreferredSize() {
int w = (int) (scale * size.width);
int h = (int) (scale * size.height);
return new Dimension(w, h);
}
private JSlider getControl() {
JSlider slider = new JSlider(JSlider.HORIZONTAL, 1, 500, 50);
slider.setMajorTickSpacing(50);
slider.setMinorTickSpacing(25);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(this);
return slider;
}
public static void main(String[] args) {
ZoomDemo app = new ZoomDemo();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(app.getGui());
app.setImage(app.image);
// frame.getContentPane().add(new JScrollPane(app));
frame.getContentPane().add(app.getControl(), "Last");
frame.setSize(700, 500);
frame.setLocation(200, 200);
frame.setVisible(true);
}
}
The following code is the class format i need to follow
Component Class
package component;
import javax.swing.JComponent;
import javax.swing.JSlider;
import javax.swing.plaf.ComponentUI;
public class ProgressBar extends JComponent {
public static ComponentUI createUI(JComponent c) {
return new ZoomUI();
}
public void installUI(JComponent c){
}
public void uninstallUI (JComponent c){
}
}
Model CLass
public class ZoomModel extends JSLider {
}
UIDelegate Class
public class ZoomUI extends ComponentUI implements ChangeListener{
}
Any help on how I can implement my custom component in this format would be greatly appreciated. I am very new to Swing and documentation I have found on custom components has been very confusing and of little help.
test application
package test;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.*;
import java.io.File;
import java.net.URL;
import javax.imageio.ImageIO;
import component.ZoomComponent;
public class ZoomDemo extends JPanel implements PropertyChangeListener, ActionListener {
ZoomComponent zoomer;
JPanel board;
private BufferedImage image;
public ZoomDemo( ) {
super(true);
setLayout(new BorderLayout( ));
board = new JPanel(true);
board.setPreferredSize(new Dimension(300, 300));
board.setBorder(new LineBorder(Color.black, 5));
zoomer = new ZoomComponent();
add(board, BorderLayout.NORTH);
add(zoomer, BorderLayout.SOUTH);
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void propertyChange(PropertyChangeEvent arg0) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
UIManager.getDefaults().put("ZoomComponentUI", "component.BasicZoomUI");
ZoomDemo s= new ZoomDemo();
JFrame frame = new JFrame("Sample Sketch Application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(s);
frame.pack( );
frame.setVisible(true);
}
}
Okay, so that was a fun adventure into parts of the API I don't use :), start by having a read through How to Write a Custom Swing Component and it's associated links, this will give you the ground work to understand what is about to happen...
Model
The Interface
Personally, I always start with an interface, life is better with interfaces and it gives you more flexibility. Now, which model should you extend from (based on your requirements)...?
Well, the best choice I could find was the BoundedRangeModel, which is also used by the JSlider...this actually means that I can not only pass this model to the view, but to a JSlider and without any extra work, have the slider change the image!! Win-Win
import java.awt.Dimension;
import java.awt.Image;
import javax.swing.BoundedRangeModel;
public interface ZoomModel extends BoundedRangeModel {
public Image getImage();
public Dimension getScaledSize();
}
The Abstract
Next, I like to make an abstract version, this is where I put "common" functionality, which is likely to be the same for most implementations, in this case, it might not be required, but I'm finckle like this...
import java.awt.Dimension;
import java.awt.Image;
import javax.swing.DefaultBoundedRangeModel;
public abstract class AbstractZoomModel extends DefaultBoundedRangeModel implements ZoomModel {
public AbstractZoomModel() {
super(100, 0, 0, 200);
}
#Override
public Dimension getScaledSize() {
Dimension size = new Dimension(0, 0);
Image image = getImage();
if (image != null) {
double scale = getValue() / 100d;
size.width = (int) Math.round(image.getWidth(null) * scale);
size.height = (int) Math.round(image.getHeight(null) * scale);
}
return size;
}
}
So, you can see here, I've defined some basic properties, a starting zoom level of 100, a max level of 200 and a minimum level of 0, plus I've implemented the getScaledSize, which is used a bit and makes life easier...
The Default...
Now, because we like been nice, we provide a "default" implementation of the model. This is pretty basic in that all it does it takes a reference to an image...
import java.awt.Image;
public class DefaultZoomModel extends AbstractZoomModel {
Image image;
public DefaultZoomModel(Image image) {
this.image = image;
}
#Override
public Image getImage() {
return image;
}
}
You could create implementations that download images from an URL for example...
The View
Okay, this is the actually component itself, which gets added to your UI. It contains the basic functionality need to construct and prepare the UI delegate and manage the model. The key thing of interest here is the use of the property change support to provide notification of the change to the model, this is important as you will see...
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JComponent;
import javax.swing.UIManager;
public class ZoomComponent extends JComponent {
private static final String uiClassID = "ZoomComponentUI";
private ZoomModel model;
public ZoomComponent() {
setBackground(Color.black);
setFocusable(true);
updateUI();
}
public void setModel(ZoomModel newModel) {
if (model != newModel) {
ZoomModel old = model;
this.model = newModel;
firePropertyChange("model", old, newModel);
}
}
public ZoomModel getModel() {
return model;
}
#Override
public Dimension getPreferredSize() {
ZoomModel model = getModel();
Dimension size = new Dimension(100, 100);
if (model != null) {
size = model.getScaledSize();
}
return size;
}
public void setUI(BasicZoomUI ui) {
super.setUI(ui);
}
#Override
public void updateUI() {
if (UIManager.get(getUIClassID()) != null) {
ZoomUI ui = (ZoomUI) UIManager.getUI(this);
setUI(ui);
} else {
setUI(new BasicZoomUI());
}
}
public BasicZoomUI getUI() {
return (BasicZoomUI) ui;
}
#Override
public String getUIClassID() {
return uiClassID;
}
}
The UI Delegate
Now the other fun stuff...If we follow standard convention, you would normally provide an abstract concept of the UI delegate, for example...
import javax.swing.plaf.ComponentUI;
public abstract class ZoomUI extends ComponentUI {
}
From this, other delegates will grow...
Basic UI Delegate
Convention would normally suggest you provide a "basic" implementation, doing a lot of the heavy lifting, but allowing other implementations the opportunity to jump in change things to there likely
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
public class BasicZoomUI extends ZoomUI {
private ZoomComponent zoomComponent;
private MouseAdapter mouseHandler;
private ChangeListener changeHandler;
private Action zoomIn;
private Action zoomOut;
private PropertyChangeListener propertyChangeHandler;
protected ChangeListener getChangeHandler() {
if (changeHandler == null) {
changeHandler = new ChangeHandler();
}
return changeHandler;
}
protected void installMouseListener() {
mouseHandler = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
zoomComponent.requestFocusInWindow();
}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
int amount = e.getWheelRotation();
ZoomModel model = zoomComponent.getModel();
if (model != null) {
int value = model.getValue();
model.setValue(value + amount);
}
}
};
zoomComponent.addMouseListener(mouseHandler);
zoomComponent.addMouseWheelListener(mouseHandler);
}
protected void installModelPropertyChangeListener() {
propertyChangeHandler = new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
ZoomModel old = (ZoomModel) evt.getOldValue();
if (old != null) {
old.removeChangeListener(getChangeHandler());
}
ZoomModel newValue = (ZoomModel) evt.getNewValue();
if (newValue != null) {
newValue.addChangeListener(getChangeHandler());
}
}
};
zoomComponent.addPropertyChangeListener("model", propertyChangeHandler);
}
protected void installKeyBindings() {
zoomIn = new ZoomInAction();
zoomOut = new ZoomOutAction();
InputMap inputMap = zoomComponent.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "zoomIn");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), "zoomOut");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0), "zoomIn");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "zoomOut");
ActionMap actionMap = zoomComponent.getActionMap();
actionMap.put("zoomIn", zoomIn);
actionMap.put("zoomOut", zoomOut);
}
protected void installModelChangeListener() {
ZoomModel model = getModel();
if (model != null) {
model.addChangeListener(getChangeHandler());
}
}
#Override
public void installUI(JComponent c) {
zoomComponent = (ZoomComponent) c;
installMouseListener();
installModelPropertyChangeListener();
installKeyBindings();
installModelChangeListener();
}
protected void uninstallModelChangeListener() {
getModel().removeChangeListener(getChangeHandler());
}
protected void uninstallKeyBindings() {
InputMap inputMap = zoomComponent.getInputMap(JComponent.WHEN_FOCUSED);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "donothing");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), "donothing");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0), "donothing");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "donothing");
AbstractAction blank = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
}
};
ActionMap actionMap = zoomComponent.getActionMap();
actionMap.put("zoomIn", blank);
actionMap.put("zoomOut", blank);
}
protected void uninstallModelPropertyChangeListener() {
zoomComponent.removePropertyChangeListener(propertyChangeHandler);
propertyChangeHandler = null;
}
protected void uninstallMouseListener() {
zoomComponent.removeMouseWheelListener(mouseHandler);
mouseHandler = null;
}
#Override
public void uninstallUI(JComponent c) {
uninstallModelChangeListener();
uninstallModelPropertyChangeListener();
uninstallKeyBindings();
uninstallMouseListener();
mouseHandler = null;
zoomComponent = null;
}
#Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
paintImage(g);
}
protected void paintImage(Graphics g) {
if (zoomComponent != null) {
ZoomModel model = zoomComponent.getModel();
Image image = model.getImage();
Dimension size = model.getScaledSize();
int x = (zoomComponent.getWidth() - size.width) / 2;
int y = (zoomComponent.getHeight() - size.height) / 2;
g.drawImage(image, x, y, size.width, size.height, zoomComponent);
}
}
public static ComponentUI createUI(JComponent c) {
return new BasicZoomUI();
}
protected ZoomModel getModel() {
return zoomComponent == null ? null : zoomComponent.getModel();
}
protected class ChangeHandler implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
zoomComponent.revalidate();
zoomComponent.repaint();
}
}
protected class ZoomAction extends AbstractAction {
private int delta;
public ZoomAction(int delta) {
this.delta = delta;
}
#Override
public void actionPerformed(ActionEvent e) {
ZoomModel model = getModel();
if (model != null) {
model.setValue(model.getValue() + delta);
}
}
}
protected class ZoomOutAction extends ZoomAction {
public ZoomOutAction() {
super(-5);
}
}
protected class ZoomInAction extends ZoomAction {
public ZoomInAction() {
super(5);
}
}
}
From here you could go and devise platform specific implementations, but I've decided to stick with the basic delegate...
Putting it all together
If that wasn't enough, before you can use any of it, you must install the delegate...
UIManager.getDefaults().put("ZoomComponentUI", "your.awesome.package.name.BasicZoomUI");
nb: Change your.awesome.package.name to reflect your actual package name...
Runnable Example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestZoom100 {
public static void main(String[] args) {
new TestZoom100();
}
public TestZoom100() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
UIManager.getDefaults().put("ZoomComponentUI", "your.awesome.package.name.BasicZoomUI");
try {
DefaultZoomModel model = new DefaultZoomModel(ImageIO.read(new File("/your/awesome/image.jpg")));
model.setValue(50);
ZoomComponent zoomComp = new ZoomComponent();
zoomComp.setModel(model);
JSlider slider = new JSlider(model);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(zoomComp));
frame.add(slider, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
}
Don't forget to change the package name for the BasicZoomUI to the package name you have it stored in and actually specify a image file ;)

Implement custom java swing component into test application [duplicate]

I was given the task to create a custom swing component. I have my component functioning properly in a test application which includes JSlider that is used to zoom in and out on an Image. However I am required to present my custom component in a Model, UIDelegate, and Component class format and I am totally lost on how to convert my code so that it follows this format. Here is the code for my test application.
package test;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.*;
import java.io.File;
import java.net.URL;
import javax.imageio.ImageIO;
public class ZoomDemo extends JComponent implements ChangeListener {
JPanel gui;
/**
* Displays the image.
*/
JLabel imageCanvas;
Dimension size;
double scale = 1.0;
private BufferedImage image;
public ZoomDemo() {
size = new Dimension(10, 10);
setBackground(Color.black);
try {
image = ImageIO.read(new File("car.jpg"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void setImage(Image image) {
imageCanvas.setIcon(new ImageIcon(image));
}
public void initComponents() {
if (gui == null) {
gui = new JPanel(new BorderLayout());
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
imageCanvas = new JLabel();
JPanel imageCenter = new JPanel(new GridBagLayout());
imageCenter.add(imageCanvas);
JScrollPane imageScroll = new JScrollPane(imageCenter);
imageScroll.setPreferredSize(new Dimension(300, 100));
gui.add(imageScroll, BorderLayout.CENTER);
}
}
public Container getGui() {
initComponents();
return gui;
}
public void stateChanged(ChangeEvent e) {
int value = ((JSlider) e.getSource()).getValue();
scale = value / 100.0;
paintImage();
}
protected void paintImage() {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
BufferedImage bi = new BufferedImage(
(int)(imageWidth*scale),
(int)(imageHeight*scale),
image.getType());
Graphics2D g2 = bi.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform at = AffineTransform.getTranslateInstance(0, 0);
at.scale(scale, scale);
g2.drawRenderedImage(image, at);
setImage(bi);
}
public Dimension getPreferredSize() {
int w = (int) (scale * size.width);
int h = (int) (scale * size.height);
return new Dimension(w, h);
}
private JSlider getControl() {
JSlider slider = new JSlider(JSlider.HORIZONTAL, 1, 500, 50);
slider.setMajorTickSpacing(50);
slider.setMinorTickSpacing(25);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(this);
return slider;
}
public static void main(String[] args) {
ZoomDemo app = new ZoomDemo();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(app.getGui());
app.setImage(app.image);
// frame.getContentPane().add(new JScrollPane(app));
frame.getContentPane().add(app.getControl(), "Last");
frame.setSize(700, 500);
frame.setLocation(200, 200);
frame.setVisible(true);
}
}
The following code is the class format i need to follow
Component Class
package component;
import javax.swing.JComponent;
import javax.swing.JSlider;
import javax.swing.plaf.ComponentUI;
public class ProgressBar extends JComponent {
public static ComponentUI createUI(JComponent c) {
return new ZoomUI();
}
public void installUI(JComponent c){
}
public void uninstallUI (JComponent c){
}
}
Model CLass
public class ZoomModel extends JSLider {
}
UIDelegate Class
public class ZoomUI extends ComponentUI implements ChangeListener{
}
Any help on how I can implement my custom component in this format would be greatly appreciated. I am very new to Swing and documentation I have found on custom components has been very confusing and of little help.
test application
package test;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.*;
import java.io.File;
import java.net.URL;
import javax.imageio.ImageIO;
import component.ZoomComponent;
public class ZoomDemo extends JPanel implements PropertyChangeListener, ActionListener {
ZoomComponent zoomer;
JPanel board;
private BufferedImage image;
public ZoomDemo( ) {
super(true);
setLayout(new BorderLayout( ));
board = new JPanel(true);
board.setPreferredSize(new Dimension(300, 300));
board.setBorder(new LineBorder(Color.black, 5));
zoomer = new ZoomComponent();
add(board, BorderLayout.NORTH);
add(zoomer, BorderLayout.SOUTH);
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void propertyChange(PropertyChangeEvent arg0) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
UIManager.getDefaults().put("ZoomComponentUI", "component.BasicZoomUI");
ZoomDemo s= new ZoomDemo();
JFrame frame = new JFrame("Sample Sketch Application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(s);
frame.pack( );
frame.setVisible(true);
}
}
Okay, so that was a fun adventure into parts of the API I don't use :), start by having a read through How to Write a Custom Swing Component and it's associated links, this will give you the ground work to understand what is about to happen...
Model
The Interface
Personally, I always start with an interface, life is better with interfaces and it gives you more flexibility. Now, which model should you extend from (based on your requirements)...?
Well, the best choice I could find was the BoundedRangeModel, which is also used by the JSlider...this actually means that I can not only pass this model to the view, but to a JSlider and without any extra work, have the slider change the image!! Win-Win
import java.awt.Dimension;
import java.awt.Image;
import javax.swing.BoundedRangeModel;
public interface ZoomModel extends BoundedRangeModel {
public Image getImage();
public Dimension getScaledSize();
}
The Abstract
Next, I like to make an abstract version, this is where I put "common" functionality, which is likely to be the same for most implementations, in this case, it might not be required, but I'm finckle like this...
import java.awt.Dimension;
import java.awt.Image;
import javax.swing.DefaultBoundedRangeModel;
public abstract class AbstractZoomModel extends DefaultBoundedRangeModel implements ZoomModel {
public AbstractZoomModel() {
super(100, 0, 0, 200);
}
#Override
public Dimension getScaledSize() {
Dimension size = new Dimension(0, 0);
Image image = getImage();
if (image != null) {
double scale = getValue() / 100d;
size.width = (int) Math.round(image.getWidth(null) * scale);
size.height = (int) Math.round(image.getHeight(null) * scale);
}
return size;
}
}
So, you can see here, I've defined some basic properties, a starting zoom level of 100, a max level of 200 and a minimum level of 0, plus I've implemented the getScaledSize, which is used a bit and makes life easier...
The Default...
Now, because we like been nice, we provide a "default" implementation of the model. This is pretty basic in that all it does it takes a reference to an image...
import java.awt.Image;
public class DefaultZoomModel extends AbstractZoomModel {
Image image;
public DefaultZoomModel(Image image) {
this.image = image;
}
#Override
public Image getImage() {
return image;
}
}
You could create implementations that download images from an URL for example...
The View
Okay, this is the actually component itself, which gets added to your UI. It contains the basic functionality need to construct and prepare the UI delegate and manage the model. The key thing of interest here is the use of the property change support to provide notification of the change to the model, this is important as you will see...
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JComponent;
import javax.swing.UIManager;
public class ZoomComponent extends JComponent {
private static final String uiClassID = "ZoomComponentUI";
private ZoomModel model;
public ZoomComponent() {
setBackground(Color.black);
setFocusable(true);
updateUI();
}
public void setModel(ZoomModel newModel) {
if (model != newModel) {
ZoomModel old = model;
this.model = newModel;
firePropertyChange("model", old, newModel);
}
}
public ZoomModel getModel() {
return model;
}
#Override
public Dimension getPreferredSize() {
ZoomModel model = getModel();
Dimension size = new Dimension(100, 100);
if (model != null) {
size = model.getScaledSize();
}
return size;
}
public void setUI(BasicZoomUI ui) {
super.setUI(ui);
}
#Override
public void updateUI() {
if (UIManager.get(getUIClassID()) != null) {
ZoomUI ui = (ZoomUI) UIManager.getUI(this);
setUI(ui);
} else {
setUI(new BasicZoomUI());
}
}
public BasicZoomUI getUI() {
return (BasicZoomUI) ui;
}
#Override
public String getUIClassID() {
return uiClassID;
}
}
The UI Delegate
Now the other fun stuff...If we follow standard convention, you would normally provide an abstract concept of the UI delegate, for example...
import javax.swing.plaf.ComponentUI;
public abstract class ZoomUI extends ComponentUI {
}
From this, other delegates will grow...
Basic UI Delegate
Convention would normally suggest you provide a "basic" implementation, doing a lot of the heavy lifting, but allowing other implementations the opportunity to jump in change things to there likely
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
public class BasicZoomUI extends ZoomUI {
private ZoomComponent zoomComponent;
private MouseAdapter mouseHandler;
private ChangeListener changeHandler;
private Action zoomIn;
private Action zoomOut;
private PropertyChangeListener propertyChangeHandler;
protected ChangeListener getChangeHandler() {
if (changeHandler == null) {
changeHandler = new ChangeHandler();
}
return changeHandler;
}
protected void installMouseListener() {
mouseHandler = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
zoomComponent.requestFocusInWindow();
}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
int amount = e.getWheelRotation();
ZoomModel model = zoomComponent.getModel();
if (model != null) {
int value = model.getValue();
model.setValue(value + amount);
}
}
};
zoomComponent.addMouseListener(mouseHandler);
zoomComponent.addMouseWheelListener(mouseHandler);
}
protected void installModelPropertyChangeListener() {
propertyChangeHandler = new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
ZoomModel old = (ZoomModel) evt.getOldValue();
if (old != null) {
old.removeChangeListener(getChangeHandler());
}
ZoomModel newValue = (ZoomModel) evt.getNewValue();
if (newValue != null) {
newValue.addChangeListener(getChangeHandler());
}
}
};
zoomComponent.addPropertyChangeListener("model", propertyChangeHandler);
}
protected void installKeyBindings() {
zoomIn = new ZoomInAction();
zoomOut = new ZoomOutAction();
InputMap inputMap = zoomComponent.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "zoomIn");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), "zoomOut");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0), "zoomIn");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "zoomOut");
ActionMap actionMap = zoomComponent.getActionMap();
actionMap.put("zoomIn", zoomIn);
actionMap.put("zoomOut", zoomOut);
}
protected void installModelChangeListener() {
ZoomModel model = getModel();
if (model != null) {
model.addChangeListener(getChangeHandler());
}
}
#Override
public void installUI(JComponent c) {
zoomComponent = (ZoomComponent) c;
installMouseListener();
installModelPropertyChangeListener();
installKeyBindings();
installModelChangeListener();
}
protected void uninstallModelChangeListener() {
getModel().removeChangeListener(getChangeHandler());
}
protected void uninstallKeyBindings() {
InputMap inputMap = zoomComponent.getInputMap(JComponent.WHEN_FOCUSED);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "donothing");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), "donothing");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0), "donothing");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "donothing");
AbstractAction blank = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
}
};
ActionMap actionMap = zoomComponent.getActionMap();
actionMap.put("zoomIn", blank);
actionMap.put("zoomOut", blank);
}
protected void uninstallModelPropertyChangeListener() {
zoomComponent.removePropertyChangeListener(propertyChangeHandler);
propertyChangeHandler = null;
}
protected void uninstallMouseListener() {
zoomComponent.removeMouseWheelListener(mouseHandler);
mouseHandler = null;
}
#Override
public void uninstallUI(JComponent c) {
uninstallModelChangeListener();
uninstallModelPropertyChangeListener();
uninstallKeyBindings();
uninstallMouseListener();
mouseHandler = null;
zoomComponent = null;
}
#Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
paintImage(g);
}
protected void paintImage(Graphics g) {
if (zoomComponent != null) {
ZoomModel model = zoomComponent.getModel();
Image image = model.getImage();
Dimension size = model.getScaledSize();
int x = (zoomComponent.getWidth() - size.width) / 2;
int y = (zoomComponent.getHeight() - size.height) / 2;
g.drawImage(image, x, y, size.width, size.height, zoomComponent);
}
}
public static ComponentUI createUI(JComponent c) {
return new BasicZoomUI();
}
protected ZoomModel getModel() {
return zoomComponent == null ? null : zoomComponent.getModel();
}
protected class ChangeHandler implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
zoomComponent.revalidate();
zoomComponent.repaint();
}
}
protected class ZoomAction extends AbstractAction {
private int delta;
public ZoomAction(int delta) {
this.delta = delta;
}
#Override
public void actionPerformed(ActionEvent e) {
ZoomModel model = getModel();
if (model != null) {
model.setValue(model.getValue() + delta);
}
}
}
protected class ZoomOutAction extends ZoomAction {
public ZoomOutAction() {
super(-5);
}
}
protected class ZoomInAction extends ZoomAction {
public ZoomInAction() {
super(5);
}
}
}
From here you could go and devise platform specific implementations, but I've decided to stick with the basic delegate...
Putting it all together
If that wasn't enough, before you can use any of it, you must install the delegate...
UIManager.getDefaults().put("ZoomComponentUI", "your.awesome.package.name.BasicZoomUI");
nb: Change your.awesome.package.name to reflect your actual package name...
Runnable Example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestZoom100 {
public static void main(String[] args) {
new TestZoom100();
}
public TestZoom100() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
UIManager.getDefaults().put("ZoomComponentUI", "your.awesome.package.name.BasicZoomUI");
try {
DefaultZoomModel model = new DefaultZoomModel(ImageIO.read(new File("/your/awesome/image.jpg")));
model.setValue(50);
ZoomComponent zoomComp = new ZoomComponent();
zoomComp.setModel(model);
JSlider slider = new JSlider(model);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(zoomComp));
frame.add(slider, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
}
Don't forget to change the package name for the BasicZoomUI to the package name you have it stored in and actually specify a image file ;)

How do I implement Java swing GUI start screen for a game with drawString and drawImage?

I'm not sure how I would fix the errors in my program and how I would highlight the option the user is hovering on. I want it to highlight the code for each position, i.e position 1 would be highlighted(as a different color) to start game,etc. and up/down would change position and I would change the position with up ,down, left, right. This is what I have so far. At the moment its bugged and when compiled with my window it comes out as:
Which works for the main game and altered for this titleboard, what am I doing wrong and how do I fix it?
TitleBoard class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
//sound + file opening
import java.io.*;
import javax.sound.sampled.*;
public class TitleBoard extends JPanel implements ActionListener{
private ArrayList<String> OptionList;
private Image background;
private ImageIcon bgImageIcon;
private String cheatString;
private int position;
private Timer timer;
public TitleBoard(){
setFocusable(true);
addKeyListener(new TAdapter());
bgImageIcon = new ImageIcon("");
background = bgImageIcon.getImage();
String[] options = {"Start Game","Options","Quit"};
OptionList = new ArrayList<String>();
optionSetup(options);
position = 1;
timer = new Timer(8, this);
timer.start();
/*
1 mod 3 =>1 highlight on start
2 mod 3 =>2 highlight on options
3 mod 3 =>0 highlight on quit
*/
try{
Font numFont = Font.createFont(Font.TRUETYPE_FONT,new File("TwistedStallions.ttf"));
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(numFont);
setFont(numFont.deriveFont(24f)); //adjusthislater
}catch(IOException|FontFormatException e){
e.printStackTrace();
}
}
private void optionSetup(String[] s){
for(int i=0; i<s.length;i++) {
OptionList.add(s[i]);
}
}
public void paint(Graphics g){
super.paint(g);
Graphics g2d = (Graphics2D)g;
g2d.drawImage(background,0,0,this);
for (int i=0;i<OptionList.size();i++){
g2d.drawString(OptionList.get(i),200,120+120*i);
}/*
g2d.drawString(OptionList.get(1),400,240);
g2d.drawString(OptionList.get(2),400,360);
//instructions on start screen maybe??
//800x500
//highlighting*/
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void actionPerformed(ActionEvent e){
repaint();
}
public class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_UP||
e.getKeyCode() == KeyEvent.VK_RIGHT){
position++;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN||
e.getKeyCode() == KeyEvent.VK_LEFT){
position--;
}
}
}
}
Window Class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Window extends JFrame{
public Window(){
int width = 800, height = 600;
//TO DO: make a panel in TITLE MODE
///////////////////////////////////
//panel in GAME MODE.
add(new TitleBoard());
//set default close
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width,height);
//centers window
setLocationRelativeTo(null);
setTitle("Title");
setResizable(false);
setVisible(true);
}
public static void main(String[] args){
new Window();
}
}
There are any number of ways you might achieve this, for example, you could use some kind of delegation model.
That is, rather then trying to mange of each element in a single method (or methods), you could devise a delegate which provide a simple interface method that the paint method would call and it would know how to do the rest.
For example, Swing uses this type of concept with it's cell renderers for JList, JTable and JTree.
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MyAwesomeMenu {
public static void main(String[] args) {
new MyAwesomeMenu();
}
public MyAwesomeMenu() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<String> menuItems;
private String selectMenuItem;
private String focusedItem;
private MenuItemPainter painter;
private Map<String, Rectangle> menuBounds;
public TestPane() {
setBackground(Color.BLACK);
painter = new SimpleMenuItemPainter();
menuItems = new ArrayList<>(25);
menuItems.add("Start Game");
menuItems.add("Options");
menuItems.add("Exit");
selectMenuItem = menuItems.get(0);
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
String newItem = null;
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
if (bounds.contains(e.getPoint())) {
newItem = text;
break;
}
}
if (newItem != null && !newItem.equals(selectMenuItem)) {
selectMenuItem = newItem;
repaint();
}
}
#Override
public void mouseMoved(MouseEvent e) {
focusedItem = null;
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
if (bounds.contains(e.getPoint())) {
focusedItem = text;
repaint();
break;
}
}
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "arrowDown");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "arrowUp");
am.put("arrowDown", new MenuAction(1));
am.put("arrowUp", new MenuAction(-1));
}
#Override
public void invalidate() {
menuBounds = null;
super.invalidate();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (menuBounds == null) {
menuBounds = new HashMap<>(menuItems.size());
int width = 0;
int height = 0;
for (String text : menuItems) {
Dimension dim = painter.getPreferredSize(g2d, text);
width = Math.max(width, dim.width);
height = Math.max(height, dim.height);
}
int x = (getWidth() - (width + 10)) / 2;
int totalHeight = (height + 10) * menuItems.size();
totalHeight += 5 * (menuItems.size() - 1);
int y = (getHeight() - totalHeight) / 2;
for (String text : menuItems) {
menuBounds.put(text, new Rectangle(x, y, width + 10, height + 10));
y += height + 10 + 5;
}
}
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
boolean isSelected = text.equals(selectMenuItem);
boolean isFocused = text.equals(focusedItem);
painter.paint(g2d, text, bounds, isSelected, isFocused);
}
g2d.dispose();
}
public class MenuAction extends AbstractAction {
private final int delta;
public MenuAction(int delta) {
this.delta = delta;
}
#Override
public void actionPerformed(ActionEvent e) {
int index = menuItems.indexOf(selectMenuItem);
if (index < 0) {
selectMenuItem = menuItems.get(0);
}
index += delta;
if (index < 0) {
selectMenuItem = menuItems.get(menuItems.size() - 1);
} else if (index >= menuItems.size()) {
selectMenuItem = menuItems.get(0);
} else {
selectMenuItem = menuItems.get(index);
}
repaint();
}
}
}
public interface MenuItemPainter {
public void paint(Graphics2D g2d, String text, Rectangle bounds, boolean isSelected, boolean isFocused);
public Dimension getPreferredSize(Graphics2D g2d, String text);
}
public class SimpleMenuItemPainter implements MenuItemPainter {
public Dimension getPreferredSize(Graphics2D g2d, String text) {
return g2d.getFontMetrics().getStringBounds(text, g2d).getBounds().getSize();
}
#Override
public void paint(Graphics2D g2d, String text, Rectangle bounds, boolean isSelected, boolean isFocused) {
FontMetrics fm = g2d.getFontMetrics();
if (isSelected) {
paintBackground(g2d, bounds, Color.BLUE, Color.WHITE);
} else if (isFocused) {
paintBackground(g2d, bounds, Color.MAGENTA, Color.BLACK);
} else {
paintBackground(g2d, bounds, Color.DARK_GRAY, Color.LIGHT_GRAY);
}
int x = bounds.x + ((bounds.width - fm.stringWidth(text)) / 2);
int y = bounds.y + ((bounds.height - fm.getHeight()) / 2) + fm.getAscent();
g2d.setColor(isSelected ? Color.WHITE : Color.LIGHT_GRAY);
g2d.drawString(text, x, y);
}
protected void paintBackground(Graphics2D g2d, Rectangle bounds, Color background, Color foreground) {
g2d.setColor(background);
g2d.fill(bounds);
g2d.setColor(foreground);
g2d.draw(bounds);
}
}
}
For here, you could add ActionListener
When a GUI needs a button, use a JButton! The JButton API allows the possibility to add icons for many different circumstances. This example shows different icons for the standard icon, the hover icon, and the pressed icon. Your GUI would obviously use icons with text on them for the required effect.
The icons are pulled directly (hot-linked) from Example images for code and mark-up Q&As.
Standard
Hover over triangle
Press triangle
Code
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.net.URL;
public class IconHoverFocusIndication {
// the GUI as seen by the user (without frame)
// swap the 1 and 0 for single column
JPanel gui = new JPanel(new GridLayout(1,0,50,50));
public static final int GREEN = 0, YELLOW = 1, RED = 2;
String[][] urls = {
{
"http://i.stack.imgur.com/T5uTa.png",
"http://i.stack.imgur.com/IHARa.png",
"http://i.stack.imgur.com/wCF8S.png"
},
{
"http://i.stack.imgur.com/gYxHm.png",
"http://i.stack.imgur.com/8BGfi.png",
"http://i.stack.imgur.com/5v2TX.png"
},
{
"http://i.stack.imgur.com/1lgtq.png",
"http://i.stack.imgur.com/6ZXhi.png",
"http://i.stack.imgur.com/F0JHK.png"
}
};
IconHoverFocusIndication() throws Exception {
// adjust to requirement..
gui.setBorder(new EmptyBorder(15, 30, 15, 30));
gui.setBackground(Color.BLACK);
Insets zeroMargin = new Insets(0,0,0,0);
for (int ii = 0; ii < 3; ii++) {
JButton b = new JButton();
b.setBorderPainted(false);
b.setMargin(zeroMargin);
b.setContentAreaFilled(false);
gui.add(b);
URL url1 = new URL(urls[ii][GREEN]);
BufferedImage bi1 = ImageIO.read(url1);
b.setIcon(new ImageIcon(bi1));
URL url2 = new URL(urls[ii][YELLOW]);
BufferedImage bi2 = ImageIO.read(url2);
b.setRolloverIcon(new ImageIcon(bi2));
URL url3 = new URL(urls[ii][RED]);
BufferedImage bi3 = ImageIO.read(url3);
b.setPressedIcon(new ImageIcon(bi3));
}
}
public JComponent getGUI() {
return gui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
IconHoverFocusIndication ihfi =
new IconHoverFocusIndication();
JFrame f = new JFrame("Button Icons");
f.add(ihfi.getGUI());
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See https://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}

Categories