I want my JToggleButton not to repaint when It is selected. I indicate state changing by pair of words ("check/next").
Standard behavior is blue lighting but I want to disable it.
Perhaps you could show the words on ImageIcons. For example:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
public class ToggleFun {
private static final Color BACKGROUND_COLOR = new Color(200, 200, 255);
public static void main(String[] args) {
int biWidth = 60;
int biHeight = 30;
BufferedImage checkImg = new BufferedImage(biWidth, biHeight, BufferedImage.TYPE_INT_RGB);
BufferedImage nextImg = new BufferedImage(biWidth, biHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = checkImg.createGraphics();
g2.setColor(BACKGROUND_COLOR);
g2.fillRect(0, 0, biWidth, biHeight);
g2.setColor(Color.black);
g2.drawString("Check", 10, 20);
g2.dispose();
g2 = nextImg.createGraphics();
g2.setColor(BACKGROUND_COLOR);
g2.fillRect(0, 0, biWidth, biHeight);
g2.setColor(Color.black);
g2.drawString("Next", 15, 20);
g2.dispose();
ImageIcon checkIcon = new ImageIcon(checkImg);
ImageIcon nextIcon = new ImageIcon(nextImg);
JToggleButton toggleBtn = new JToggleButton(checkIcon);
toggleBtn.setSelectedIcon(nextIcon);
toggleBtn.setContentAreaFilled(false);
toggleBtn.setBorder(BorderFactory.createLineBorder(Color.black));
JPanel panel = new JPanel();
panel.add(toggleBtn);
JOptionPane.showMessageDialog(null, panel);
}
}
See: AbstractButton.setContentAreaFilled(false).
But note that users generally prefer a GUI element that follows the 'path of least surprise'. This type of rendering might be better described as going off on a bit of a crash-bang through the undergrowth beside that path.
Related
I'm trying to make outer stroke for text. When I increase width parameter of BasicStroke my outline spreads both inside and outside text, but I need only outside part.
My result:
Are there some properties for that? Or maybe there is a way to cut stroke from within text?
Example code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import javax.swing.JPanel;
import javax.swing.JApplet;
import javax.swing.JFrame;
public class FontPaint extends JApplet {
public void init() {
FontPanel fontPanel = new FontPanel();
getContentPane().add(fontPanel, BorderLayout.CENTER);
}
public static void main(String[] args) {
FontPanel starPanel = new FontPanel();
JFrame f = new JFrame("Font");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.getContentPane().add(starPanel, BorderLayout.CENTER);
f.setSize(new Dimension(550, 200));
f.setVisible(true);
}
}
class FontPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.white);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
FontRenderContext frc = g2.getFontRenderContext();
Font f = new Font("Helvetica", 1, 60);
String s1 = "Java Source and Support.";
TextLayout textTl = new TextLayout(s1, f, frc);
AffineTransform transform1;
Shape outline1 = textTl.getOutline(null);
transform1 = g2.getTransform();
double newWidth1 = 301;
double newHeight1 = 427;
textTl.draw(g2, (int)newWidth1, (int)newHeight1);
transform1.translate(newWidth1, newHeight1);
g2.transform(transform1);
g2.setColor(Color.blue);
g2.setStroke(new BasicStroke(4.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND));
g2.draw(outline1);
}
}
There probably is no nice "half stroke." So first draw the outline, then fill the glyph vector. (For opaque colors only.)
transform1 = g2.getTransform();
double newWidth1 = 301;
double newHeight1 = 427;
transform1.translate(newWidth1, newHeight1);
g2.transform(transform1);
g2.setColor(Color.blue);
g2.setStroke(new BasicStroke(4.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND));
g2.draw(outline1);
textTl.draw(g2, 0, 0);
Which should be a short cut for:
...
transform1.translate(-newWidth1, -newHeight1);
textTl.draw(g2, (int)newWidth1, (int)newHeight1);
This example draws a simple PolyLine.
Is it possible to draw an outline around this PolyLine in red.
Not a single large red square but one that outlines the original PolyLine by 3-5 points away from all areas.
Some calculations were attempted and work for a fixed value, but when the PolyLine values are random, the algorithm doesn't always work as the next section of the line could turn right instead of left or up instead of down.
You almost have to look 2-3 points ahead to know if you are going to have add or subtract.
Is there an easier way to do it?
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PolyLine extends JPanel
{
public void paint(Graphics g) {
int[] xs = {25, 125, 85, 75, 25, 65, };
int[] ys = {50, 50, 100, 110, 150, 100};
BasicStroke traceStroke = new BasicStroke (1);
Graphics2D gc = (Graphics2D) g.create();
gc.setStroke(traceStroke);
gc.setColor(Color.BLUE);
gc.drawPolyline(xs, ys, 6);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new PolyLine());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(20,20, 1500,1500);
frame.setVisible(true);
}
}
First, a remark: It's usually preferable to have the geometric primitives as a Shape. The drawPolyline function (which uses these odd integer array coordinates) is somewhat out-dated. Creating the polyline as a Path2D is far more flexible.
For the task that you described, it will also be necessary to convert the polyline coordinates into a Path2D (if you switched to Path2D anyhow, you could omit this conversion step).
When you have the polyline as a Shape, the task is rather simple: You can create a stroked version of this shape, using a BasicStroke with the desired thickness and cap/join characteristics, by calling BasicStroke#createStrokedShape. This shape will basically be the shape of a "thick line". In order to avoid artifacts at the joins, you can create an Area from this Shape, and then draw this area.
So in the end, painting the actual outline is done with 2 lines of code, and the result is as follows:
But the MCVE here, for completeness:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ShapeOutlineTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new ShapeOutlineTestPanel());
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class ShapeOutlineTestPanel extends JPanel
{
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr;
int[] xs = { 25, 125, 85, 75, 25, 65, };
int[] ys = { 50, 50, 100, 110, 150, 100 };
BasicStroke traceStroke = new BasicStroke(1);
g.setStroke(traceStroke);
g.setColor(Color.BLUE);
g.drawPolyline(xs, ys, 6);
Path2D path = new Path2D.Double();
for (int i = 0; i < xs.length; i++)
{
if (i == 0)
{
path.moveTo(xs[i], ys[i]);
}
else
{
path.lineTo(xs[i], ys[i]);
}
}
g.setColor(Color.RED);
BasicStroke stroke = new BasicStroke(
10.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
g.draw(new Area(stroke.createStrokedShape(path)));
}
}
I'm new to Java and I'm trying to create a heading using a JLabel and for its fill to be a gradient. I cannot get it to work and I've been trying for a while. I've been grabbing bits of come from here and other websites and cannot seem to make this work, nor make sense of other peoples more complex code that does work. Here are my two classes so far:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EtchedBorder;
public class Test {
public static void main(String[] args) {
new Test().setupGUI();
}
public void setupGUI() {
//set up frames and buttons etc.
JFrame theFrame = new JFrame ("Crystal Ball");
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel background = new JPanel();
background.setBackground(Color.BLUE);
background.setLayout(new BoxLayout(background, BoxLayout.PAGE_AXIS));
theFrame.setSize(500,1000);
DLabel heading = new DLabel("Guess a Number");
heading.setText("GUESS A NUMBER");
heading.setPreferredSize(new Dimension(theFrame.getWidth(),100));
heading.setFont(new Font("Serif", Font.PLAIN, 40));
heading.setAlignmentX(Component.CENTER_ALIGNMENT);
//heading.setBackground(Color.YELLOW);
heading.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
background.add(heading);
theFrame.getContentPane().add(background);
theFrame.pack();
theFrame.setVisible(true);
//startGame();
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
public class DLabel extends JLabel
{
Dimension size = new Dimension(70, 80);
public DLabel(String name)
{
this.setPreferredSize(size);
this.setText(name);
this.setBorder(BorderFactory.createBevelBorder(TOP, Color.white, Color.black));
this.setOpaque(true);
}
public void paintComponent(Graphics g) {
// super.paintComponent(g); // *** commented
Graphics2D g2d = (Graphics2D) g;
Color color1 = Color.YELLOW;
Color color2 = color1.brighter();
int w = getWidth();
int h = getHeight();
GradientPaint gp = new GradientPaint(0, 0, color1, 0, h, color2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
super.paintComponent(g); // *** added
}
}
There is one little "trick" you can actually do, by leaving the label transparent, you can actually paint under the text by painting BEFORE you call super.paintComponent, for example...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestLabel101 {
public static void main(String[] args) {
new TestLabel101();
}
public TestLabel101() {
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 JLabel {
public TestPane() {
setText("Happy, Happy");
setForeground(Color.WHITE);
setHorizontalAlignment(CENTER);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
LinearGradientPaint lgp = new LinearGradientPaint(
new Point(0, 0),
new Point(0, getHeight()),
new float[]{0.142f, 0.284f, 0.426f, 0.568f, 0.71f, 0.852f, 1f},
new Color[]{Color.PINK, Color.MAGENTA, Color.BLUE, Color.GREEN, Color.YELLOW, Color.ORANGE, Color.RED});
g2d.setPaint(lgp);
g2d.fill(new Rectangle(0, 0, getWidth(), getHeight()));
g2d.dispose();
super.paintComponent(g);
}
}
}
nb: I should point out that this process is inefficient, as the RepaintManager will still want to paint under the component
There is another trick, but my two year old daughter wants to check to see if Santa is here ;)
Updated
The other trick involves understanding how the paint process actually works. When you call super.paintComponent, it calls the update method on the ComponentUI (look and feel delegate), this is actually the method that fills the background if the component is opaque, this method then calls the look and feels delegate's paint method, which actually does the base painting...
We can circumvent the process slightly and instead of calling super.paintComponent, we can call the look and feels delegate's paint method directly...
public class TestPane extends JLabel {
public TestPane() {
setText("Happy, Happy");
setForeground(Color.WHITE);
setHorizontalAlignment(CENTER);
setOpaque(true);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
LinearGradientPaint lgp = new LinearGradientPaint(
new Point(0, 0),
new Point(0, getHeight()),
new float[]{0.142f, 0.284f, 0.426f, 0.568f, 0.71f, 0.852f, 1f},
new Color[]{Color.PINK, Color.MAGENTA, Color.BLUE, Color.GREEN, Color.YELLOW, Color.ORANGE, Color.RED});
g2d.setPaint(lgp);
g2d.fill(new Rectangle(0, 0, getWidth(), getHeight()));
g2d.dispose();
getUI().paint(g, this);
}
}
This is more efficient then the previous example, as it doesn't require the RepaintManager to paint the area underneath this component, but it might not work with all look and feels
The problem is that you made the JLabel opaque, which means it will paint the background. So the call to super.paintComponent(...) over paints the gradient background. So get rid of:
//this.setOpaque(true);
Another problem with the code is that color1.brighter() doesn't work. Try something like:
Color color2 = Color.RED;
Also, You should not change the Graphics object, since that object is also used to paint other Swing components. Instead you should use g.create() to get a copy of the Graphics object. Make your changes to that object, do the painting and then dispose() the object.
So the (untested) code would be something like:
Graphics2D g2d = (Graphics2D)g.create();
...
g2d.fillRect(...);
g2d.dispose();
super.paintCompoenent(g);
You should set your gradientPaint object to your Graphics and then pass that into super.paintComponent
try this:
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Color color1 = Color.YELLOW;
Color color2 = color1.brighter();
int w = getWidth();
int h = getHeight();
GradientPaint gp = new GradientPaint(0, 0, color1, 0, h, color2);
g2d.setPaint(gp);
super.paintComponent(g2d);
}
When run this code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JButton;
import javax.swing.JLabel;
public class CustomButton extends JButton {
int width = 100;
int height = 50;
int radius = 10;
JLabel lab;
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.ORANGE);
g2.fillRoundRect(0, 0, width, height, radius, radius);
g2.dispose();
super.paintComponent(g2);
super.paintComponent(g);
}
}
And my other class:
package custom.frame;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CustomFrame {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new FlowLayout());
f.setSize(500,500);
f.setLocationRelativeTo(null);
JPanel pane = new JPanel();
pane.setBounds(0,0,500,500);
CustomButton btn = new CustomButton();
pane.add(btn);
f.add(btn);
f.setVisible(true);
}
}
I get a get a regular rectangle with only 1 rounded side. Please see the image below.
Is this the expected function?
If not, how can I fix this.
Edit
I can get 2 rounded corners if I do this:
g2.fillRoundRect(0, 0, 50, 50, 7, 7);
The only thing I can really think of is that the window containing the rectangle is too small and is cutting off the other three corners, but that seems pretty unlikely.
I've written this small program which attempts to create a custom JButton unfortunately I can't manage to remove the border. I thought button.setBorder(null); would remove it but this has been ineffective. Does anyone know how to remove the border from the button so it's just the icon? Any help greatly appreciated.
My code is as follows:
package custombuttons;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CustomButtons {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
CustomButtons h = new CustomButtons();
h.setUp();
}
JFrame frame;
JPanel panel;
JButton button;
BufferedImage b;
String toolTip = "Configure";
public void setUp() {
frame = new JFrame("Custom Buttons");
try {
b = ImageIO.read(CustomButtons.class.getResource("/images/config.png"));
} catch (IOException ex) {
Logger.getLogger(CustomButtons.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
}
Image b1 = (Image) b;
ImageIcon iconRollover = new ImageIcon(b1);
int w = iconRollover.getIconWidth();
int h = iconRollover.getIconHeight();
GraphicsConfiguration gc = frame.getGraphicsConfiguration();
Image image = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
Graphics2D g = (Graphics2D) image.getGraphics();
g.drawImage(iconRollover.getImage(), 0, 0, null);
g.dispose();
ImageIcon iconDefault = new ImageIcon(b1);
image = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
g = (Graphics2D) image.getGraphics();
g.drawImage(iconRollover.getImage(), 2, 2, null);
g.dispose();
ImageIcon iconPressed = new ImageIcon(b1);
JButton button = new JButton();
button.setIgnoreRepaint(true);
button.setFocusable(false);
button.setToolTipText(toolTip);
button.setBorder(null);
button.setContentAreaFilled(false);
button.setIcon(iconDefault);
button.setRolloverIcon(iconRollover);
button.setPressedIcon(iconPressed);
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout(FlowLayout.LEFT));
panel = new JPanel();
panel.setOpaque(false);
panel.add(button);
frame.getContentPane().add(panel);
frame.setVisible(true);
}
}
have look at button.setBorderPainted(false) more about JButton here
actually i tested your code on my Netbeans IDE and got no borders as you desire
using only button.setBorder(null); or button.setBorderPainted(false); or both of them but
i think you should make sure that your original image is really do not have any borders it self