I am trying to create my own component for swing, but when i try to paint the border of it with drawRect, it only draws the left and top edges! Why is that, and how can it be fixed?
Here is my paintComponent method:
#Override
protected void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.red);
g.drawRect(0, 0, getWidth(), getHeight());
}
Screenshot:
I am trying to create my own component for swing, but when i try to paint the border of it with drawRect,
Why are you trying to draw a Border. Swing supports borders. if your component needs a border then you should be using:
setBorder( new LineBorder(Color.RED) );
and let swing draw the border for you.
it only draws the left and top edges!
I think you should be using:
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
Maybe this will help you as a starting point:
package de.professional_webworkx.graphics;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class DrawFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = -1285962479945295143L;
private JPanel northPanel;
public DrawFrame() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Draw");
this.setLayout(new BorderLayout());
this.getContentPane().add(createNorthPanel(), BorderLayout.BEFORE_FIRST_LINE);
this.getContentPane().add(new DrawPanel(), BorderLayout.CENTER);
this.setSize(1024, 768);
this.setVisible(true);
}
public JPanel createNorthPanel() {
northPanel = new JPanel();
northPanel.setBackground(Color.MAGENTA);
JLabel jLabel = new JLabel("XXXXXXXXXXXX");
jLabel.setForeground(Color.WHITE);
northPanel.add(jLabel);
return northPanel;
}
public static void main(String[] args) {
new DrawFrame();
}
}
DrawPanel.class
package de.professional_webworkx.graphics;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 4949248244138855737L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.drawRect(10, 10, getWidth()/2, getHeight()/2);
g.setColor(Color.YELLOW);
g.fillRect(11, 11, getWidth()/2-1, getHeight()/2-1);
g.draw3DRect(10, getHeight()/2+20, 600, 280, true);
}
}
Patrick
UPDATE: Thanks to camickr.
Related
I'm trying to get JButtons which have been added to a JPanel to show up during the execution of a program, however they only appear when I hover the mouse of them, they remain invisible until then.
Below is my code, I've tried repaint() and revalidate() with no luck.
There also seems to be an issue with the height of the JPanel, it seems to be larger than the main Window for some reason
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public final class SideMenu extends JPanel implements ActionListener{
private final int width;
private final int height;
public SideMenu(int width, int height){
this.width = width;
this.height = height;
this.setLayout(new GridLayout(0,1));
this.add(new JButton("button1"));
this.add(new JButton("button2"));
this.add(new JButton("button3"));
this.revalidate();
this.repaint();
}
#Override
public void paint(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.fillRect(0, 0, width, height);
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
public static void main(String[] args){
int width = 300, height = 400;
JFrame jf = new JFrame();
jf.setTitle("Fish Tank");
jf.setSize(width, height);
jf.setVisible(true);
jf.setLayout(null);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
///jf.setResizable(false);
SideMenu side_menu = new SideMenu(100,height);
jf.add(side_menu);
side_menu.setBounds(200, 0, 100, height);
}
}
Use paintComponent(..) method instead of paint(..):
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.fillRect(0, 0, width, height);
}
Read more about custom paintings.
Also call jf.setVisible(true); at the end of construction of GUI, when you add all components to JFrame.
For some reason, a string drawn to a BufferedImage appears differently to one drawn straight to a JComponent.
Here's an example. The top string is drawn directly, while the bottom is drawn using a buffer.
What is going on here?
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Map;
public class Main {
static class Canvas extends JComponent
{
#Override
public void paintComponent(Graphics g)
{
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.BLACK);
g.drawString("OMFG look at this 'S'", 10, 20);
BufferedImage bi = new BufferedImage(150,50,BufferedImage.TYPE_INT_RGB);
Graphics2D imageG = bi.createGraphics();
imageG.setColor(Color.WHITE);
imageG.fillRect(0, 0, 150, 50);
imageG.setColor(Color.BLACK);
imageG.setFont(g.getFont());
imageG.drawString("OMFG look at this 'S'", 10, 10);
g.drawImage(bi, 0, 30, this);
}
}
public static void main(String[] args) {
JFrame jf = new JFrame();
jf.setMinimumSize(new Dimension(150, 80));
jf.add(new Canvas());
jf.setVisible(true);
}
}
I am working on learning how to create custom components. I would like to be able to include all of the methods that it calls to start with and to be able to change even the border method. Below my code does not repaint the paintBorder(...) method
public void paintBorder(Component t, Graphics g, int x, int y, int h, int w) {
super.paintBorder(g);
g.setColor(Color.YELLOW);
g.fillOval(100, 100, 50, 50);
System.out.println("PaintBorder");
}
Why would this not be being painted. The code in the paintComponent(...) does work and paint the circle but what if I want to set the border to something different or even if I just want to see a message go to the console with a println(...).
Paint Call:
There are three methods called
paintComponent()
paintBorder()
paintChildren()
How can I get my paintBorder() to be called? I would imagine that if I make a instance of this in another class than I should be able to call repaint() which calls update which intern schedules a call to paint which calls the three methods listed above (paintComponent, paintBorder, paintChildren)
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class testBall {
public static void main(String[] args) {
new testBall();
}
public testBall() {
JPanel testPane = new JPanel();
testPane.setBackground(Color.green);
testPane.setLayout(new BorderLayout());
testPane.add(new Ball(30,30,10));
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(testPane);
frame.pack();
frame.setSize(300, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class MyBall extends JComponent{
private static final long serialVersionUID = 1L;
public static Color colorBall = Color.red;
public MyBall() {
super();
System.out.println("MyBall (0)");
}
public MyBall(int x, int y, int diameter){
super();
this.setLocation(x, y);
this.setSize(diameter, diameter);
System.out.println("MyBall (1)");
}
public void paintBorder(Graphics g) {
super.paintBorder(g);
g.setColor(Color.YELLOW);
g.fillOval(100, 100, 50, 50);
System.out.println("PaintBorder");
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(colorBall);
g.fillOval(0, 0, 50, 50);
System.out.println("paintComponent");
}
public void paint(Graphics g) {
super.paint(g);
paintComponent(g);
paintBorder(this, g,10,10,10,10);
paintChildren(g);
System.out.println("Paint");
}
}
Working Code: I was creating an instance of a different ball class which was something that I did not see. If a person is going to over write the paintBorder(...) method in a class the extends JComponent(...) how should the border be painted? Does anyone have any good links for such a task?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class testBall
{
public static void main(String[] args)
{
new testBall();
}
public testBall()
{
JPanel testPane = new JPanel();
testPane.setBackground(Color.green);
testPane.setLayout(new BorderLayout());
testPane.add(new MyBall(30,30,10));
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(testPane);
frame.pack();
frame.setSize(300, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class MyBall extends JComponent
{
private static final long serialVersionUID = 1L;
private Color colorBall = Color.red;
public void setColorBall(Color c)
{
this.colorBall = c;
}
public MyBall()
{
super();
System.out.println("MyBall (0)");
}
public MyBall(int x, int y, int diameter)
{
super();
this.setLocation(x, y);
this.setSize(diameter, diameter);
System.out.println("MyBall (1)");
}
public void paintBorder(Graphics g)
{
super.paintBorder(g);
g.setColor(Color.YELLOW);
g.fillOval(100, 100, 50, 50);
System.out.println("PaintBorder");
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(colorBall);
g.fillOval(0, 0, 50, 50);
System.out.println("paintComponent");
}
public void paint(Graphics g)
{
super.paint(g);
paintComponent(g);
paintBorder(g);
paintChildren(g);
System.out.println("Paint");
}
}
There is no such method in JComponent
public void paintBorder(Component t, Graphics g, int x, int y, int h, int w)
It's method of border so it's never invoked in JComponent. Override
protected void paintBorder(Graphics g)
Instead and add your code there.
I want to set up a mathematical (where y grows up not down) coordinate space from (-1, -1) to (+1, +1) and have it fit in the window regardless of the window size.
I am using an anonymous JComponent subclass in Java SE 7 and casting the incoming Graphics in paintComponent to Graphics2D and then drawing on the Graphics2D
But the Graphics2D is set to a computer coordinate space that changes with the size of the window. How to get it to rescale according to window size and have Y go upwards? The following program should show a dark square in upper right quadrant.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class G {
public static void main (String [] args) {
JFrame frame = new JFrame(G.class.getCanonicalName());
frame.setUndecorated(true);
JComponent component = new JComponent() {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent (Graphics g) {
super.paintComponent(g);
paint2D((Graphics2D)g);
}
protected void paint2D (Graphics2D g2) {
g2.draw(new Rectangle2D.Double(0.1, 0.1, 0.9, 0.9));
}
};
frame.add(component);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
}
Setup the coordinate system how you want, using transform() and translate(). So:
you want the origin to be at (0, height); bottom left.
then you want to flip the Y axis.
Example code:
AffineTransform tform = AffineTransform.getTranslateInstance( 0, height);
tform.scale( 1, -1);
g2.setTransform( tform);
[My edited version]:
public static void main (String [] args) {
JFrame frame = new JFrame( G2dTransform_Question.class.getCanonicalName());
JComponent component = new JComponent() {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent (Graphics g) {
super.paintComponent(g);
paint2D((Graphics2D)g);
}
protected void paint2D (Graphics2D g2) {
AffineTransform tform = AffineTransform.getTranslateInstance( 0, getHeight());
tform.scale( getWidth(), -getHeight()); // NOTE -- to make 1.0 'full width'.
g2.setTransform( tform);
g2.setColor( Color.BLUE); // NOTE -- so we can *see* something.
g2.fill( new Rectangle2D.Double(0.1, 0.1, 0.8, 0.8)); // NOTE -- 'fill' works better than 'draw'.
}
};
frame.setLayout( new BorderLayout()); // NOTE -- make the component size to frame.
frame.add( component, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
[Hovercraft's version]: Thanks Hover!
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class G {
public static final int PREF_W = 400;
public static final int PREF_H = PREF_W;
public static void main (String [] args) {
JFrame frame = new JFrame(G.class.getCanonicalName());
frame.setUndecorated(true);
JComponent component = new JComponent() {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent (Graphics g) {
super.paintComponent(g);
AffineTransform tform = AffineTransform.getTranslateInstance( 0, getHeight());
tform.scale( 1, -1);
Graphics2D g2 = (Graphics2D) g.create();
g2.setTransform( tform);
paint2D(g2);
g2.dispose();
}
protected void paint2D (Graphics2D g2) {
g2.draw(new Rectangle2D.Double(10, 10, 20, 30));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
};
frame.add(component);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
I made my own BottomBar with a simple gradient extending JComponent and adjusting the paintComponent() method.
Then I add it to the SOUTH of my JFrame which uses BorderLayout.
Everything looks correct at the beginning.
When I resize the frame the BottomBar gets repainted and set to the new position correctly. The think is, it happens a few milliseconds to late, so that one can see the JFrame 's background for a second.
The funny thing is, that when I set the execution environment to Java-SE 1.6 it works... (instead of 1.7)
Also, Im running it on a mac, if that makes a difference.
Code - JButton Example
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Main {
public static void main(String args[]){
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Resize Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JButton(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
}
Code - BottomBar Example
Main:
public class Main {
public static void main(String args[]){
Frame window = new Frame();
window.setSize(500, 400);
window.setVisible(true);
}
}
Frame:
import java.awt.BorderLayout;
import javax.swing.JFrame;
public class Frame extends JFrame{
private static final long serialVersionUID = 1L;
public Frame() {
setLayout( new BorderLayout() );
getContentPane().add( BorderLayout.SOUTH, new BottomBar() );
}
}
BottomBar
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JComponent;
public class BottomBar extends JComponent {
private static final long serialVersionUID = 1L;
public BottomBar() {
setSize(200, 30);
setPreferredSize( new Dimension(200, 30) );
}
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint gradient = new GradientPaint(0, 0, new Color(185, 185, 185), 0, getHeight() , new Color(151, 151, 151) );
g2.setPaint(gradient);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor( new Color(64, 64, 64) );
g2.drawLine(0, 0, getWidth(), 0);
g2.setColor( new Color(215, 215, 215) );
g2.drawLine(0, 1, getWidth(), 1);
}
}
I am unable to reproduce the effect you describe on 1.6; you might try the sscce below on 1.7. Note, several suggestions for your example:
Avoid setXxxxSize(), as discussed here. If you just want a 30 pixel high bar in SOUTH, override getPreferredSize() as shown below. If you later decide to add components, you'll need to add a layout manager.
#Override
public Dimension getPreferredSize() {
return new Dimension(0, 30);
}
Use pack() to let the Window adopt the preferred sizes of the enclosed components. I've added an arbitrary size JPanel to the CENTER; resize the frame to see how the bar grows horizontally in SOUTH.
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see https://stackoverflow.com/a/13610367/230513 */
public class Main {
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("BottomBar");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
}, BorderLayout.CENTER);
frame.add(new BottomBar(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
private static class BottomBar extends JComponent {
#Override
public Dimension getPreferredSize() {
return new Dimension(0, 30);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint gradient = new GradientPaint(
0, 0, new Color(185, 185, 185),
0, getHeight(), new Color(151, 151, 151));
g2.setPaint(gradient);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(new Color(64, 64, 64));
g2.drawLine(0, 0, getWidth(), 0);
g2.setColor(new Color(215, 215, 215));
g2.drawLine(0, 1, getWidth(), 1);
}
}
}