Custom button is shrinked when in a BoxLayout - java

I have a custom button class that I created that extends JButton. When I add this to a JFrame, I get this:
But when I place this custom button into the frame with BoxLayout, the button becomes smaller and is not desirable this way:
Here is my code for the frame:
Test.java
import javax.swing.BoxLayout;
import javax.swing.JFrame;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame();
//When you uncomment this, the button is sized really small
//frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.PAGE_AXIS));
frame.add(new CButton("Hello"));
frame.pack();
frame.setVisible(true);
}
}
And here is the code for the custom button, CButton:
CButton.java
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JToolTip;
public class CButton extends JButton implements ComponentListener {
protected static final int BORDER_WIDTH = 5;
private static final Insets INSETS_MARGIN = new Insets(2, 5, 2, 5);
private static final long serialVersionUID = 1L;
protected Area m_areaDraw = null;
private Area m_areaFill = null;
private double m_dHeightDraw = 0d;
private double m_dHeightFill = 0d;
private double m_dWidthDraw = 0d;
private double m_dWidthFill = 0d;
private int m_nMinHeight = 0;
private int m_nMinWidth = 0;
private int m_nStringHeightMax = 0;
private int m_nStringWidthMax = 0;
private RoundRectangle2D m_rrect2dDraw = null;
private RoundRectangle2D m_rrect2dFill = null;
private Shape m_shape = null;
public CButton(String strLabel) {
setContentAreaFilled(false);
setMargin(INSETS_MARGIN);
setFocusPainted(false);
addComponentListener(this);
setText(strLabel);
}
#Override
public void componentHidden(ComponentEvent e) {
}
#Override
public void componentMoved(ComponentEvent e) {
}
// Needed if we want this button to resize
#Override
public void componentResized(ComponentEvent e) {
m_shape = new Rectangle2D.Float(0, 0, getBounds().width,
getBounds().height);
m_dWidthFill = (double) getBounds().width - 1;
m_dHeightFill = (double) getBounds().height - 1;
m_dWidthDraw = ((double) getBounds().width - 1)
- (CButton.BORDER_WIDTH - 1);
m_dHeightDraw = ((double) getBounds().height - 1)
- (CButton.BORDER_WIDTH - 1);
setShape();
repaint();
}
#Override
public void componentShown(ComponentEvent e) {
}
#Override
public boolean contains(int nX, int nY) {
if ((null == m_shape) || m_shape.getBounds().equals(getBounds())) {
m_shape = new Rectangle2D.Float(0, 0, this.getBounds().width,
this.getBounds().height);
}
return m_shape.contains(nX, nY);
}
#Override
public void paintBorder(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hints);
g2.setColor(Color.black);
Stroke strokeOld = g2.getStroke();
g2.setStroke(new BasicStroke(CButton.BORDER_WIDTH,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
if (getModel().isRollover()) {
g2.setColor(Color.ORANGE);
}
if (!getModel().isEnabled()) {
g2.setColor(Color.GRAY);
}
g2.draw(m_areaDraw);
g2.setStroke(strokeOld);
};
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hints);
if (getModel().isArmed()) {
g2.setColor(Color.CYAN.darker());
} else {
g2.setColor(Color.CYAN);
}
g2.fill(m_areaFill);
super.paintComponent(g2);
}
private void setShape() {
// Area
double dArcLengthFill = Math.min(m_dWidthFill, m_dHeightFill);
m_rrect2dFill = new RoundRectangle2D.Double(0d, 0d, m_dWidthFill,
m_dHeightFill, dArcLengthFill, dArcLengthFill);
// WARNING: arclength and archeight are divided by 2
// when they get into the roundedrectangle shape
m_areaFill = new Area(m_rrect2dFill);
// Border
double dArcLengthDraw = Math.min(m_dWidthDraw, m_dHeightDraw);
m_rrect2dDraw = new RoundRectangle2D.Double(
(CButton.BORDER_WIDTH - 1) / 2, (CButton.BORDER_WIDTH - 1) / 2,
m_dWidthDraw, m_dHeightDraw, dArcLengthDraw, dArcLengthDraw);
m_areaDraw = new Area(m_rrect2dDraw);
}
#Override
public void setText(final String strText) {
super.setText(strText);
Frame frame = JOptionPane.getRootFrame();
FontMetrics fm = frame.getFontMetrics(getFont());
m_nStringWidthMax = fm.stringWidth(getText());
m_nStringWidthMax = Math.max(m_nStringWidthMax,
fm.stringWidth(getText()));
// WARNING: use getMargin. it refers to dist btwn text and border.
// Also use getInsets. it refers to the width of the border
int nWidth = Math.max(m_nMinWidth, m_nStringWidthMax + getMargin().left
+ getInsets().left + getMargin().right + getInsets().right);
m_nStringHeightMax = fm.getHeight();
// WARNING: use getMargin. it refers to dist btwn text and border.
// Also use getInsets. it refers to the width of the border
int nHeight = Math.max(m_nMinHeight, m_nStringHeightMax
+ getMargin().left + getInsets().left + getMargin().right
+ getInsets().right);
setPreferredSize(new Dimension(
nWidth + ((2 * getFont().getSize()) / 5), nHeight
+ ((2 * getFont().getSize()) / 5)));
// Set the initial draw and fill dimensions
setShape();
}
}
Is there a way I can fix this and make it the full size?

Override the getPreferredSize(). BoxLayout respects preferred sizes. If you don't the preferred size will be determined by the text. It is bigger in the frame because the default BorderLayout of the frame doesn't respect preferred size, and will stretch the button. Another thing you can do instead is set bigger margins and/or bigger font, as that will also increase the preferred size. So you have a few options/things to consider
Have a look here as which layout respect preferred sizes and which ones don't. Another always good resources is Laying out Components Within a Container

Related

Zoom-in and zoom-out of a grid and an Image in swing

I am display an image on JPanel and on that image i am creating a Grid of 8*8 by setStroke of Graphics2D. Now when i zooming that grid lines by setting setStroke it does not work for all images. I am thinking that this problem is associated with resolution of images. How can i solve this problem
BufferedImage bi; //loading buffered image some how
JCombobox jComboBox; //creating combobox having different zoom factor
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int gridLinesThikness = (int) ((float) jComboBox.getSelectedIndex() * (float) (bi.getWidth() / (float) screen.width));
if (gridLinesThikness < 1)
gridLinesThikness = 1;
g2.setStroke(new BasicStroke(gridLinesThikness));
Try this code:
package sad;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class zoom extends javax.swing.JPanel {
private static int prevN = 0;
private Dimension preferredSize = new Dimension(400,400);
private Rectangle2D[] rects = new Rectangle2D[50];
public static void main(String[] args) {
JFrame jf = new JFrame("test");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(800, 800);
JPanel containerPanel = new JPanel(); // extra JPanel
containerPanel.setLayout(new GridBagLayout());
containerPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(1, 0, 1)));
zoom zoomPanel = new zoom();
containerPanel.add(zoomPanel);
zoomPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
jf.add(new JScrollPane(containerPanel));
jf.setVisible(true);
}
public zoom() {
// generate rectangles with pseudo-random coords
for (int i=0; i<rects.length; i++) {
rects[i] = new Rectangle2D.Double(
Math.random()*.8, Math.random()*.8,
Math.random()*.2, Math.random()*.2);
}
addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
updatePreferredSize(e.getWheelRotation(), e.getPoint());
}
});
}
private void updatePreferredSize(int n, Point p) {
if(n == 0) // ideally getWheelRotation() should never return 0.
n = -1 * prevN; // but sometimes it returns 0 during changing of zoom
// direction. so if we get 0 just reverse the direction.
double d = (double) n * 1.08;
d = (n > 0) ? 1 / d : -d;
int w = (int) (getWidth() * d);
int h = (int) (getHeight() * d);
preferredSize.setSize(w, h);
int offX = (int)(p.x * d) - p.x;
int offY = (int)(p.y * d) - p.y;
getParent().setLocation(getParent().getLocation().x-offX,getParent().getLocation().y-offY);
//in the original code, zoomPanel is being shifted. here we are shifting containerPanel
getParent().doLayout(); // do the layout for containerPanel
getParent().getParent().doLayout(); // do the layout for jf (JFrame)
prevN = n;
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
private Rectangle2D r = new Rectangle2D.Float();
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.red);
int w = getWidth();
int h = getHeight();
for (Rectangle2D rect : rects) {
r.setRect(rect.getX() * w, rect.getY() * h,
rect.getWidth() * w, rect.getHeight() * h);
((Graphics2D)g).draw(r);
}
}
}

Java layouts not updating component size when custom button changes text

I am making a button where when you click on it it changes the text. But when I click on the button and change the text, the button does not change size according to the text. Instead, it gets smaller and attempts to make that "..." thing when it does not have enough room. Here is my code:
Text.java
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args){
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.add(panel);
final CButton button = new CButton("");
panel.add(button);
button.addMouseListener(new MouseListener(){
#Override
public void mouseClicked(MouseEvent arg0) {
button.setText(button.getText()+"f");
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
});
frame.setSize(500,500);
frame.setVisible(true);
}
}
CButton.java
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JButton;
import javax.swing.JOptionPane;
public class CButton extends JButton implements ComponentListener, KeyListener {
protected static final int BORDER_WIDTH = 5;
private static final Font font = new Font("Arial", Font.PLAIN, 30);
private static final Insets INSETS_MARGIN = new Insets(2, 5, 2, 5);
private static final long serialVersionUID = 1L;
protected Area m_areaDraw = null;
private Area m_areaFill = null;
private double m_dHeightDraw = 0d;
private double m_dHeightFill = 0d;
private double m_dWidthDraw = 0d;
private double m_dWidthFill = 0d;
private int m_nMinHeight = 0;
private int m_nMinWidth = 0;
private int m_nStringHeightMax = 0;
private int m_nStringWidthMax = 0;
private RoundRectangle2D m_rrect2dDraw = null;
private RoundRectangle2D m_rrect2dFill = null;
private Shape m_shape = null;
public CButton(String strLabel) {
super(strLabel);
setContentAreaFilled(false);
setMargin(CButton.INSETS_MARGIN);
setFocusPainted(false);
addComponentListener(this);
addKeyListener(this);
// Determine the buttons initial size
setFont(CButton.font);
Frame frame = JOptionPane.getRootFrame();
FontMetrics fm = frame.getFontMetrics(getFont());
m_nStringWidthMax = fm.stringWidth(getText());
m_nStringWidthMax = Math.max(m_nStringWidthMax,
fm.stringWidth(getText()));
// WARNING: use getMargin. it refers to dist btwn text and border.
// Also use getInsets. it refers to the width of the border
int nWidth = Math.max(m_nMinWidth, m_nStringWidthMax + getMargin().left
+ this.getInsets().left + getMargin().right
+ this.getInsets().right);
m_nStringHeightMax = fm.getHeight();
// WARNING: use getMargin. it refers to dist btwn text and border.
// Also use getInsets. it refers to the width of the border
int nHeight = Math.max(m_nMinHeight, m_nStringHeightMax
+ getMargin().left + this.getInsets().left + getMargin().right
+ this.getInsets().right);
setPreferredSize(new Dimension(
nWidth + ((2 * getFont().getSize()) / 5), nHeight
+ ((2 * getFont().getSize()) / 5)));
// Set the initial draw and fill dimensions
setShape();
}
#Override
public void componentHidden(ComponentEvent e) {
}
#Override
public void componentMoved(ComponentEvent e) {
}
// Needed if we want this button to resize
#Override
public void componentResized(ComponentEvent e) {
m_shape = new Rectangle2D.Float(0, 0, getBounds().width,
getBounds().height);
m_dWidthFill = (double) getBounds().width - 1;
m_dHeightFill = (double) getBounds().height - 1;
m_dWidthDraw = ((double) getBounds().width - 1)
- (CButton.BORDER_WIDTH - 1);
m_dHeightDraw = ((double) getBounds().height - 1)
- (CButton.BORDER_WIDTH - 1);
setShape();
repaint();
}
#Override
public void componentShown(ComponentEvent e) {
}
#Override
public boolean contains(int nX, int nY) {
if ((null == m_shape) || m_shape.getBounds().equals(getBounds())) {
m_shape = new Rectangle2D.Float(0, 0, this.getBounds().width,
this.getBounds().height);
}
return m_shape.contains(nX, nY);
}
// This is so the button is triggered when it has focus
// and we press the Enter key.
#Override
public void keyPressed(KeyEvent e) {
if ((e.getSource() == this) && (e.getKeyCode() == KeyEvent.VK_ENTER)) {
doClick();
}
};
#Override
public void keyReleased(KeyEvent e) {
};
#Override
public void keyTyped(KeyEvent e) {
};
#Override
public void paintBorder(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hints);
g2.setColor(Color.black);
Stroke strokeOld = g2.getStroke();
g2.setStroke(new BasicStroke(CButton.BORDER_WIDTH,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.draw(m_areaDraw);
if (getModel().isRollover()) {
g2.setColor(Color.GRAY);
g2.draw(m_areaDraw);
}
g2.setStroke(strokeOld);
};
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hints);
if (getModel().isArmed()) {
g2.setColor(Color.CYAN.darker());
} else {
g2.setColor(Color.CYAN);
}
g2.fill(m_areaFill);
super.paintComponent(g2);
}
private void setShape() {
// Area
double dArcLengthFill = Math.min(m_dWidthFill, m_dHeightFill);
m_rrect2dFill = new RoundRectangle2D.Double(0d, 0d, m_dWidthFill,
m_dHeightFill, dArcLengthFill, dArcLengthFill);
// WARNING: arclength and archeight are divided by 2
// when they get into the roundedrectangle shape
m_areaFill = new Area(m_rrect2dFill);
// Border
double dArcLengthDraw = Math.min(m_dWidthDraw, m_dHeightDraw);
m_rrect2dDraw = new RoundRectangle2D.Double(
(CButton.BORDER_WIDTH - 1) / 2, (CButton.BORDER_WIDTH - 1) / 2,
m_dWidthDraw, m_dHeightDraw, dArcLengthDraw, dArcLengthDraw);
m_areaDraw = new Area(m_rrect2dDraw);
}
#Override
public void setText(String strText) {
super.setText(strText);
int nWidth = Math.max(m_nMinWidth, m_nStringWidthMax + getInsets().left
+ getInsets().right);
int nHeight = Math.max(0, getPreferredSize().height);
setPreferredSize(new Dimension(nWidth, nHeight));
m_dWidthFill = getBounds().width - 1;
m_dHeightFill = getBounds().height - 1;
if ((m_dWidthFill <= 0) || (m_dHeightFill <= 0)) {
m_dWidthFill = (double) getPreferredSize().width - 1;
m_dHeightFill = (double) getPreferredSize().height - 1;
}
m_dWidthDraw = m_dWidthFill - (CButton.BORDER_WIDTH - 1);
m_dHeightDraw = m_dHeightFill - (CButton.BORDER_WIDTH - 1);
setShape();
}
}
You call
setPreferredSize(new Dimension(
nWidth + ((2 * getFont().getSize()) / 5), nHeight
+ ((2 * getFont().getSize()) / 5)));
in the constructor, but never change it. This means that each time the layout manager asks the component what size it would like to be, it always gets the same value.
A preferred solution would be to override getPreferredSize and calculate the size there, if it's not to complicated or time consuming
The next question is why are you going to all this extra effort. Basically, you should simply allow the parent JButton to provide its preferred size and add your requirements around it, or simply use the margins properties or even a Border
You're KeyListener also seems useless as this is the default behaviour of the button anyway and in any case, key bindings would be a preferred solution
My first thought was that it had to do with your humongous CButton implementation. At least, copy/paste of your code created a working application. That's a big plus in my book.
When I simply replaced the strange nWidth calculation in the setText() method with:
int nWidth = 100;
The size was increased after a click and showed an "f", which I assume is what you wanted.
So, I can't really say how to calculate the width, but at least you know where to look and which line to change.

Java JButton not updating

I have a JButton that when I call setText(), the text does not update. But as soon as I hover over the button, it updates. How can I fix this so that when I call setText(), the button updates? I will just post the methods that the EDT takes to get to it. It goes in order :)
public void mouseClicked(MouseEvent e) {//This is a differn't event. This is not executed by clicking on the same button. It's a differn't one.
click(new Point(e.getX() + gridScrollPaneViewport.getViewPosition().x, e.getY() + gridScrollPaneViewport.getViewPosition().y));
}
public void click(Point point) {
map.selectPlot((PlotGUI) map.getComponentAt(point));
}
public void selectPlot(PlotGUI plot) {
ChickenTycoon.getInstance().getScreen().getPlayingScreen().sideBar
.setPlot(plot);
selectedPlot = plot;
}
public void setPlot(PlotGUI plot) {
title.setText(plot.getName() + plot.getX() + plot.getY());
for (Component comp : stuffPanel.getComponents()) {
stuffPanel.remove(comp);
}
for (Component comp : plot.getComponentList()) {
stuffPanel.add(comp);
}
update();
}
public void update() {
if (ChickenTycoon.getInstance().getScreen().getPlayingScreen().map
.getSelectedPlot() != null) {
ChickenTycoon.getInstance().getScreen().getPlayingScreen().map
.getSelectedPlot().update();
}
}
public void update() {
Log.m("Updating LandGUI");
((CButton) componentList[0]).setText("Buy for $ "//I know I am casting this to a CButton, it's my custom version of JButton. I tried it with a JButton and the same thing happens.
+ ((Land) parentPlot).getPurchasePrice());
}
CButton.java
package gui;
import game.GameConfiguration;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import chicken.GlobalConfiguration;
public class CButton extends JButton implements ComponentListener {
protected static final int BORDER_WIDTH = 5;
private static final Font font = GlobalConfiguration.font;
private static final Insets INSETS_MARGIN = new Insets(2, 5, 2, 5);
private static final long serialVersionUID = 1L;
protected Area m_areaDraw = null;
private Area m_areaFill = null;
private double m_dHeightDraw = 0d;
private double m_dHeightFill = 0d;
private double m_dWidthDraw = 0d;
private double m_dWidthFill = 0d;
private int m_nMinHeight = 0;
private int m_nMinWidth = 0;
private int m_nStringHeightMax = 0;
private int m_nStringWidthMax = 0;
private RoundRectangle2D m_rrect2dDraw = null;
private RoundRectangle2D m_rrect2dFill = null;
private Shape m_shape = null;
public CButton(String strLabel) {
setContentAreaFilled(false);
setMargin(CButton.INSETS_MARGIN);
setFocusPainted(false);
addComponentListener(this);
setFont(CButton.font);
setText(strLabel);
}
#Override
public void componentHidden(ComponentEvent e) {
}
#Override
public void componentMoved(ComponentEvent e) {
}
// Needed if we want this button to resize
#Override
public void componentResized(ComponentEvent e) {
m_shape = new Rectangle2D.Float(0, 0, getBounds().width,
getBounds().height);
m_dWidthFill = (double) getBounds().width - 1;
m_dHeightFill = (double) getBounds().height - 1;
m_dWidthDraw = ((double) getBounds().width - 1)
- (CButton.BORDER_WIDTH - 1);
m_dHeightDraw = ((double) getBounds().height - 1)
- (CButton.BORDER_WIDTH - 1);
setShape();
repaint();
}
#Override
public void componentShown(ComponentEvent e) {
}
#Override
public boolean contains(int nX, int nY) {
if ((null == m_shape) || m_shape.getBounds().equals(getBounds())) {
m_shape = new Rectangle2D.Float(0, 0, this.getBounds().width,
this.getBounds().height);
}
return m_shape.contains(nX, nY);
}
#Override
public void paintBorder(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hints);
g2.setColor(Color.black);
Stroke strokeOld = g2.getStroke();
g2.setStroke(new BasicStroke(CButton.BORDER_WIDTH,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.draw(m_areaDraw);
if (getModel().isRollover()) {
g2.setColor(Color.GRAY);
g2.draw(m_areaDraw);
}
g2.setStroke(strokeOld);
};
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hints);
if (getModel().isArmed()) {
g2.setColor(Color.CYAN.darker());
} else {
g2.setColor(Color.CYAN);
}
g2.fill(m_areaFill);
super.paintComponent(g2);
}
private void setShape() {
// Area
double dArcLengthFill = Math.min(m_dWidthFill, m_dHeightFill);
m_rrect2dFill = new RoundRectangle2D.Double(0d, 0d, m_dWidthFill,
m_dHeightFill, dArcLengthFill, dArcLengthFill);
// WARNING: arclength and archeight are divided by 2
// when they get into the roundedrectangle shape
m_areaFill = new Area(m_rrect2dFill);
// Border
double dArcLengthDraw = Math.min(m_dWidthDraw, m_dHeightDraw);
m_rrect2dDraw = new RoundRectangle2D.Double(
(CButton.BORDER_WIDTH - 1) / 2, (CButton.BORDER_WIDTH - 1) / 2,
m_dWidthDraw, m_dHeightDraw, dArcLengthDraw, dArcLengthDraw);
m_areaDraw = new Area(m_rrect2dDraw);
}
#Override
public void setText(final String strText) {
CButton.super.setText(strText);
Frame frame = JOptionPane.getRootFrame();
FontMetrics fm = frame.getFontMetrics(font);
m_nStringWidthMax = fm.stringWidth(getText());
m_nStringWidthMax = Math.max(m_nStringWidthMax,
fm.stringWidth(getText()));
// WARNING: use getMargin. it refers to dist btwn text and border.
// Also use getInsets. it refers to the width of the border
int nWidth = Math.max(m_nMinWidth, m_nStringWidthMax + getMargin().left
+ getInsets().left + getMargin().right + getInsets().right);
m_nStringHeightMax = fm.getHeight();
// WARNING: use getMargin. it refers to dist btwn text and border.
// Also use getInsets. it refers to the width of the border
int nHeight = Math.max(m_nMinHeight, m_nStringHeightMax
+ getMargin().left + getInsets().left + getMargin().right
+ getInsets().right);
setPreferredSize(new Dimension(
nWidth + ((2 * getFont().getSize()) / 5), nHeight
+ ((2 * getFont().getSize()) / 5)));
// Set the initial draw and fill dimensions
setShape();
}
}
I fixed it. I needed to add a repaint to the container for the button. Simple as that!
button.setText("Some Text");
buttonContainer.repaint();

Java Swing - creating tag-like dynamic width buttons

I'm making my first steps with desktop GUI design. What I'm trying to achieve is displaying in one of table columns. I want them to be visually attractive and also clickable.
At first, I thought that it's possible to do that with JButton with some hacks, as suggested in this thread. But then I realized that I don't know how to manage dynamic width of labels and stretching the graphics to fill buttons in 100%.
I want to achieve something similar to image below. In HTML+CSS it's very easy, each tag:
has left edge as graphics
has repeatable 1px wide background
has right edge as graphics
But how to do that in Java?
info: I don't care if this is a JButton or not, as long as it's nice, clickable and draggable.
UPDATE
Mockup below represents what I want to do. It involves JTable or multiple JLists as well as those tags floating left next to the word. It's easy to do in HTML+CSS, but almost impossible for me to do that in Java.
I have no doubt there are multitudes of ways to achieve this, a better way would be to simply write a UI delegate, but let's try and keep it basic for the moment...
(I've updated the button code, so I've included it in the update)
The problem you have is JTable just isn't designed to do what you are trying to. Grouped rows and variable row heights are not easily achieved.
This is just an example, but what I've done is generate a series of compound components which "mimic" your basic requirements...
The following makes use `WrapLayout' written by own camrik and SwingLabs, SwingX libraries
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractButton;
import javax.swing.DefaultButtonModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.MatteBorder;
import org.jdesktop.swingx.*;
public class TestTagButton {
public static void main(String[] args) {
new TestTagButton();
}
public TestTagButton() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JPanel wordsPane = new JPanel(new VerticalLayout());
wordsPane.setBackground(Color.WHITE);
Word word = new Word("Hand");
word.addTag("body parts", 55);
List<String> translations = new ArrayList<>(3);
translations.add("Reka");
translations.add("Dion");
translations.add("Garsec");
wordsPane.add(new WordGroupPane(word, translations));
word = new Word("Roof");
word.addTag("house", 17);
word.addTag("architecture", 8);
translations = new ArrayList<>(3);
translations.add("Dach");
translations.add("Zadaszenie");
wordsPane.add(new WordGroupPane(word, translations));
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
// frame.add(new JScrollPane(wordsPane));
frame.add(wordsPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class WordGroupPane extends JPanel {
public WordGroupPane(Word word, List<String> translations) {
setOpaque(false);
setLayout(new GridLayout(0, 2));
add(new WordPane(word));
add(new TranslationsPane(translations));
}
}
public static class TranslationsPane extends JPanel {
protected static final Border SPLIT_BORDER = new MatteBorder(0, 0, 1, 0, Color.GRAY);
public TranslationsPane(List<String> translations) {
setOpaque(false);
setLayout(new GridLayout(0, 1));
for (String translation : translations) {
JLabel lbl = new JLabel(translation);
lbl.setHorizontalAlignment(JLabel.LEFT);
lbl.setBorder(SPLIT_BORDER);
add(lbl);
}
}
}
public static class WordPane extends JPanel {
public WordPane(Word word) {
setBorder(new MatteBorder(0, 0, 1, 1, Color.GRAY));
setOpaque(false);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.NORTH;
gbc.insets = new Insets(10, 8, 10, 8);
JLabel label = new JLabel(word.getWord());
add(label, gbc);
gbc.gridx = 1;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(0, 0, 0, 0);
JPanel tagsPane = new JPanel(new WrapLayout(WrapLayout.LEFT));
tagsPane.setOpaque(false);
for (Tag tag : word.getTags()) {
TagButton tb = new TagButton(tag.getText());
Font font = tb.getFont();
font = font.deriveFont(font.getSize() - 3f);
tb.setFont(font);
tb.setTag(Integer.toString(tag.getCount()));
tb.setSelected(true);
tagsPane.add(tb);
}
add(tagsPane, gbc);
}
}
public class Word {
private String word;
private List<Tag> tags;
public Word(String word) {
this.word = word;
this.tags = new ArrayList<>(25);
}
public void addTag(String text, int count) {
addTag(new Tag(text, count));
}
public String getWord() {
return word;
}
public List<Tag> getTags() {
return tags;
}
public void addTag(Tag tag) {
tags.add(tag);
}
}
public class Tag {
private String text;
private int count;
public Tag(String text, int count) {
this.text = text;
this.count = count;
}
public String getText() {
return text;
}
public int getCount() {
return count;
}
}
public static class TagButton extends AbstractButton {
private JLabel renderer;
private String tag;
public TagButton(String text) {
this();
setText(text);
}
public TagButton() {
setModel(new DefaultButtonModel());
setMargin(new Insets(8, 8, 8, 8));
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
getModel().setPressed(true);
}
#Override
public void mouseReleased(MouseEvent e) {
getModel().setPressed(false);
getModel().setSelected(!isSelected());
}
});
setFont(UIManager.getFont("Button.font"));
}
public void setTag(String value) {
if (tag == null ? value != null : !tag.equals(value)) {
String old = tag;
tag = value;
firePropertyChange("tag", old, tag);
revalidate();
}
}
public String getTag() {
return tag;
}
protected JLabel getRenderer() {
if (renderer == null) {
renderer = new JLabel(getText());
}
return renderer;
}
#Override
public Dimension getPreferredSize() {
Insets margin = getMargin();
Dimension size = new Dimension();
size.width = margin.left + margin.right;
size.height = margin.top + margin.bottom;
JLabel renderer = getRenderer();
renderer.setText(getText());
size.width += renderer.getPreferredSize().width;
size.height += renderer.getPreferredSize().height;
size.width += getTagWidth();
return size;
}
protected int getTagWidth() {
JLabel renderer = getRenderer();
renderer.setText(getTag());
renderer.setFont(getFont());
return renderer.getPreferredSize().width + 16;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
// int fullWidth = getTagWidth() + 8;
int width = getTagWidth() + 8;
int height = getHeight() - 3;
int tagWidth = getWidth() - 1 - width;
Shape insert = new TagInsert(width, height);
int x = getWidth() - width - 1;
if (!isSelected()) {
x -= getTagWidth();
}
x -= 4;
g2d.translate(x, 1);
g2d.setPaint(new Color(242, 95, 0));
g2d.fill(insert);
g2d.setPaint(new Color(222, 83, 0));
g2d.draw(insert);
Stroke stroke = g2d.getStroke();
BasicStroke stitch = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[]{3f}, 0f);
g2d.setStroke(stitch);
g2d.setColor(new Color(167, 65, 1));
g2d.drawLine(0, 2, width, 2);
g2d.drawLine(0, height - 2, width, height - 2);
g2d.setColor(new Color(249, 127, 50));
g2d.drawLine(0, 3, width, 3);
g2d.drawLine(0, height - 1, width, height - 1);
g2d.setStroke(stroke);
if (isSelected()) {
JLabel renderer = getRenderer();
renderer.setFont(getFont());
renderer.setText(getTag());
renderer.setSize(width - 8, renderer.getPreferredSize().height);
renderer.setForeground(Color.WHITE);
renderer.setHorizontalAlignment(JLabel.CENTER);
int xPos = 4;//((tagWidth - renderer.getWidth()) / 2);
int yPos = (height - renderer.getHeight()) / 2;
g2d.translate(xPos, yPos);
renderer.printAll(g2d);
g2d.translate(-xPos, -yPos);
}
g2d.translate(-x, -1);
height = getHeight() - 1;
Shape baseShape = new TagShape(tagWidth, height);
LinearGradientPaint lgpFill = new LinearGradientPaint(
new Point(0, 0),
new Point(0, getHeight() - 1),
new float[]{0f, 1f},
new Color[]{new Color(248, 248, 248), new Color(241, 241, 241)}
);
g2d.setPaint(lgpFill);
g2d.fill(baseShape);
LinearGradientPaint lgpOutline = new LinearGradientPaint(
new Point(0, 0),
new Point(0, getHeight() - 1),
new float[]{0f, 1f},
new Color[]{UIManager.getColor("Button.shadow"), UIManager.getColor("Button.darkShadow")}
);
g2d.setPaint(lgpOutline);
g2d.draw(baseShape);
JLabel renderer = getRenderer();
renderer.setFont(getFont());
renderer.setText(getText());
renderer.setSize(renderer.getPreferredSize());
renderer.setForeground(getForeground());
x = (tagWidth - renderer.getWidth()) / 2;
int y = (height - renderer.getHeight()) / 2;
renderer.setLocation(x, y);
g2d.translate(x, y);
renderer.printAll(g2d);
g2d.translate(-x, -y);
g2d.setColor(Color.RED);
// g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.dispose();
}
}
protected static class TagInsert extends Path2D.Float {
public TagInsert(float width, float height) {
float gap = 3;
float radius = (height - (gap * 5)) / 4f;
moveTo(0, 0);
lineTo(width, 0);
float yPos = 0;
lineTo(width, 1);
float topY = gap;
for (int index = 0; index < 4; index++) {
float bottomY = topY + radius;
float x = width - (radius / 2);
lineTo(width, topY);
curveTo(x, topY, x, bottomY, width, bottomY);
topY += radius;
topY += gap;
lineTo(width, topY);
}
lineTo(width, height);
lineTo(0, height);
lineTo(0, 0);
}
}
protected static class TagShape extends Path2D.Float {
protected static final float RADIUS = 8;
public TagShape(float width, float height) {
moveTo(RADIUS, 0);
lineTo(width, 0);
float clip = RADIUS / 2f;
float topY = (height / 2f) - clip;
float bottomY = (height / 2f) + clip;
lineTo(width, topY);
curveTo(width - clip, topY, width - clip, bottomY, width, bottomY);
lineTo(width, height);
lineTo(RADIUS, height);
curveTo(0, height, 0, height, 0, height - RADIUS);
lineTo(0, RADIUS);
curveTo(0, 0, 0, 0, RADIUS, 0);
}
}
}
use javafx buttons rather than swing.
javafx buttons have css properties.
Based on your requirements it does seem like JButton is a good starting point because it has most of what you want.
As far as the width goes, you will most likely need to subclass JButton so that you can you can update the width in the constructor, something like this:
private static class FancyButton extends JButton{
public FancyButton(String name) {
super(name);
//Calculate new width
setPreferredSize(new Dimension(newWidth, 30));
}
}
Or have a method that sets up your buttons that determines and sets the width.
As you want to use these in a JTable, you'll need a custom renderer that draws the button with or without the number showing. The numeric value and state should be stored in your TableModel. To get the behavior of a button, you'll need a custom editor, perhaps one returning an instance of JToggleButton. In this example, an instance of JCheckBox (a subclass of JToggleButton) is used to display both state and value in a column.

Code is producing a gray screen

I can't seem to work out what the problem is here.
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable, MouseMotionListener {
private static final int SCREEN_WIDTH = 640;
private static final int SCREEN_HEIGHT = 480;
private static final int INDENT = 20;
private int playerOneScore = 0;
private int playerTwoScore = 0;
private ImageEntity playerOne = new ImageEntity("Images/bouncer.bmp");
private ImageEntity playerTwo = new ImageEntity("Images/bouncer.bmp");
private int mouseX = 0;
private int mouseY = 0;
private BufferedImage gameScreen = new BufferedImage(SCREEN_WIDTH,
SCREEN_HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D gameScreenGraphics = gameScreen.createGraphics();
public GamePanel() {
paintBackground(gameScreenGraphics);
paintScore(gameScreenGraphics);
paintBouncers(gameScreenGraphics);
}
public void run() {
}
public void mouseMoved(MouseEvent m) {
mouseX = m.getXOnScreen();
mouseY = m.getYOnScreen();
}
public void mouseDragged(MouseEvent m) {
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(gameScreen, 0, 0, this);
}
private void paintBackground(Graphics2D g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g.setColor(Color.WHITE);
for (int i = 0; i < 10; i++) {
g.fillRect(SCREEN_WIDTH / 2 - 5, i * SCREEN_HEIGHT / 10, 10,
(SCREEN_HEIGHT / 10) - 10);
}
}
private void paintScore(Graphics2D g) {
Font scoreFont = new Font("Impact", Font.PLAIN, 72);
g.setFont(scoreFont);
FontMetrics scoreFontMetrics = g.getFontMetrics();
g.drawString("" + playerOneScore, SCREEN_WIDTH / 2 - 30
- scoreFontMetrics.stringWidth("" + playerOneScore),
SCREEN_HEIGHT / 2);
g.drawString("" + playerTwoScore, SCREEN_WIDTH / 2 + 30,
SCREEN_HEIGHT / 2);
}
private void paintBouncers(Graphics2D g) {
g.drawImage(playerOne.getImage(), playerOne.getX(), playerOne.getY(),
this);
g.drawImage(playerTwo.getImage(), playerTwo.getX(), playerTwo.getY(),
this);
}
public static void main(String[] args) {
JFrame mainPane = new JFrame("Pong - Mrinank Sharma");
mainPane.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
mainPane.setVisible(true);
mainPane.setResizable(false);
GamePanel gp = new GamePanel();
mainPane.add(gp);
}
}
I run this and end up getting a grey screen. Any help?
ImageEntity is basically an Image Wrapper type thing for BufferedImage. The problem seems to be in the paintScore() method, as if I comment off the calling of the method, it works as intended. This is for a Pong type game I am trying to make.
Oddly, this single change (after a number of changes to get it to compile) fixes the stated problem:
Font scoreFont = new Font("Arial", Font.PLAIN, 72);
remove paintscore from gamepanel() and add it in main after mainpanel.add(gp)
gp.paintScore(gp.gameScreenGraphics);
there is something else wrong with your code though
change font size to 24

Categories

Resources