Can't draw line(method: paintComponent) - Java - java

I'm trying to draw a line in a JFrame, but line isn't drawn.
I tried to use the method setOpaque(true) for contentPane, lblNewLabel and l but nothing changed. I also tried call repaint(); outside this class but the situation is still the same. Here's the code:
public class DrawingClass extends JFrame
{
private JPanel contentPane;
public DrawingClass(int n, int s, int p) {
Line l= new Line();
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setBounds(700, 300, 480, 640);
contentPane = new JPanel();
contentPane.setOpaque(true);
setResizable(false);
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblNewLabel = new JLabel("");
lblNewLabel.setIcon(new ImageIcon("image.png"));
lblNewLabel.setBounds(0, 0, 480, 640);
contentPane.add(lblNewLabel);
l.setBounds(0,0,480,640);
contentPane.add(l);
repaint();
}
class Line extends JPanel
{
public void paintComponent(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect(10, 10, 15, 12);
}
}
}
I expect a little line on the top left of the JFrame, above the background wallpaper, but nothing happen. It shows only the wallpaper.

There are several errors in your code:
You're extending JFrame but you're not changing its behavior, so why are you doing that? JFrame is a rigid component, so it's never a good idea to extend from it, build your GUI based on JPanels instead. See: Extends JFrame vs. creating it inside the program
Don't explicitly set the size of the JFrame, call pack() on it and instead override getPreferredSize from the JPanel, see: Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
You don't need to call setOpaque(...) in this case.
Don't use a null-layout, it might lead to strange errors, because null Layout is Evil and frowned upon
We don't have access to your image so we cannot test the ImageIcon and it's also not related to your question. However you should load your images as resources
Don't explicitly set the bounds of each element, this is related to point (4) and you should use a Layout Manager or combinations of them to get your desired GUI.
Don't call repaint() that way, it has no effect, it is supposed to repaint your UI when there's a change in it. However there is no change at the start of your program.
You're breaking the paint-chain by not calling super.paintComponent(...) inside your paintComponent(...) method. Check the Tutorial on Custom Painting in Swing so that you learn how to do it properly
And be careful, as paintComponents(...) (With a trailing s) is different from paintComponent(...) (Look at your title)
So, after doing all of the above changes, we get to this simple program:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class DrawingClass {
private JPanel contentPane;
private JFrame frame;
public static void main(String args[]) {
SwingUtilities.invokeLater(() -> new DrawingClass().createAndShowGUI());
}
public void createAndShowGUI() {
frame = new JFrame(getClass().getSimpleName());
Line line = new Line();
frame.add(line);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
class Line extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(10, 10, 15, 12);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(480, 640);
}
}
}
Which produces the following output:

Related

How to paint in a split panel in Java swing

Recently, I've met an issue that the paintComponent function is not invoked in the function, and I found that when I use splitpane function, it will disable the paint function, and gives error:
cannot add to layout: unknown constraint: null
I think the paint function may not be added to the right way, below is my code(partly):
Class: test
public class Test extends JFrame{
public Test() throws IOException{
//JFrame jf = new JFrame("my frame");
this.add(new NewPanel(this));
this.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
this.setBounds(300,200,1050,600);
this.setVisible (true);
}
public static void main (String[] args) throws IOException{
Test test = new Test ();
test.setTitle("Hello");
//frame.pack ();
}
}
Class: NewPanel
public class NewPanel extends JPanel{
public NewPanel(JFrame frame) throws IOException{
JTabbedPane jTabbedpane = new JTabbedPane();
JSplitPane splitPane = new JSplitPane();
JPanel p1 = new JPanel();
p1.setLayout(null);
p2.setLayout(new FlowLayout());
splitPane.setOneTouchExpandable(true);
splitPane.setContinuousLayout(true);
//splitPane.setPreferredSize(new Dimension (250,500));
splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
splitPane.setLeftComponent(p1);
splitPane.setRightComponent (p2);
splitPane.setDividerSize(3);
splitPane.setDividerLocation(250); //balance two panels width
jTabbedpane.addTab("ABC",p2);
jTabbedpane.addTab("AB",p3);
jTabbedpane.addTab("AC",p4);
jTabbedpane.addTab("BC",p5);
frame.setContentPane(splitPane);
frame.add(jTabbedpane);
}
}
public void paintComponent(Graphics g){
super.paint(g);
g.setColor(Color.BLUE);
g.drawLine(303, 90, 303, 200);
g.drawLine(583, 90, 583, 200);
g.drawLine(863, 90, 863, 200);
}
}
When I comment frame.add(jTabbedpane),the line could be drawn in the panel, BUT it is only available in one panel, I cannot draw it into another split panel, I don't know why.. And when I uncomment frame.add(jTabbedpane), it pops up the above mentioned error.
Your UI assembly doesn't make sense. You're calling 'setContentPane' to the splitpane, which is sort-of OK (but unusual), but then you're calling add() to the frame, which tries to then add something else to the contentPane (the JSplitPane). You should either add the JTabbedPane to the SplitPane before adding the splitPane to the JPanel, or set up your layout differently.
//These don't make sense together.
frame.setContentPane(splitPane);
frame.add(jTabbedpane);
Your second question about drawing the blue line is more complicated.
You're doing a bunch of crazy stuff - you're creating a NewPanel and trying to add it to the JFrame, but then you're setting the contentPane of the JFrame to a different component later. You need to go through the Swing Tutorial and lay out your UI better.
I think the paint function may not be added to the right way,
public void paintComponent(Graphics g){
super.paint(g);
You are overriding paintComponent(...), so why are you calling super.paint(...)?
Start by reading the Swing Tutorial for Swing basics. All sections in the tutorial have working examples you can download and test.
So you might start with:
How to Use Split Panes - it will show you how to add a split pane to a frame
Performing Custom Painting - it will explain how painting works and show how to override the paintComponent(...) method.

How do you draw shapes on a JPanel, which is within another JPanel?

I'm currently trying to draw shapes on a JPanel, which is within another JPanel, within a JFrame.
I've searched Google and Youtube and found out how to draw shapes within a JFrame that has one panel, but have found nothing which can help me with what I'm doing. (maybe I'm not seeing something).
Code I've seen so far:
public class GameScreen
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
g.drawRect(100, 10, 30, 40);
}
public static void main(String[] args)
{
GameScreen gs = new GameScreen();
JFrame f = new JFrame();
f.setTitle("");
f.setSize(400,400);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(gs);
}
This is all good for when I'm dealing with just one panel, but I wanna display shapes on a panel which is within the 1'st panel I've created.
Add a JPanel to the JFrame in the same way as you're doing now, but do it with your own subclass of JPanel.
class MyPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.drawRect(100, 10, 30, 40);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400,400); // As suggested by camickr
}
}
You can add this to a JPanel which sits within the JFrame
public static void main(String[] args)
{
MyPanel mp = new MyPanel();
JPanel jp = new JPanel();
jp.add(mp);
JFrame f = new JFrame();
f.setTitle("");
f.setSize(400,400);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(jp);
}
This can work for components within components, if you add them as children components. The key is to extend the component and override the methods you wish to change.
This is all good for when I'm dealing with just one panel,
The code you posted works fine because a frame uses a BorderLayout. So, when you add your panel to the frame is will increase in size and your custom painting will be seen.
I wanna display shapes on a panel which is within the 1'st panel I've created.
When you create a panel it uses a FlowLayout by default. When you add a custom painting panel to that panel it will be displayed at its preferred size, which will be (0, 0) since you didn't specify the preferred size.
On the panels that do custom painting you also need to implement the getPreferredSize() method so the layout manager knows how to arrange the panels. For example:
public Dimension getPreferredSize()
{
return new Dimension(200, 200);
}

JButton absolute underneath my paint() board

I have a poker game where I designed a nice pretty GUI that displays the cards and players. I did it all extending JPanel inside paint() with a lot of g2d.drawImage's and g2d.drawString()'s, with definite x and y locations.
My problem now is that I need to have a couple interactive buttons underneath it.. but whenever I try to add a JButton, it appears top and center. I've used setLocation(x, y) and setLayout(null) and everything I've seen in other replies, but none of them seem to match my need (Or at least I don't have a very well understanding of where to put it)
This is how my code is set up:
pokerserver.java
public class pokerserver extends JFrame {
public pokerserver() {
add(new drawing());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(720, 640);
setLocationRelativeTo(null);
setTitle("Poker HANGOUTS");
setResizable(false);
setVisible(true);
}
public static void main(String args[]) {
new pokerserver();
}
And then in drawing.class
public drawing() {
setFocusable(true);
setBackground(new Color(39,91,46));
setDoubleBuffered(true);
gameCards = new cards();
gameCards.shuffle();
for (int i = 0; i < 10; i++)
seats[i] = -1;
HQ = new HeadQuarters(this);
HQ.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
//All my UI code
}
My last attempt was trying to add
JButton button = new JButton("TEST");
add(button);
button.setLocation(10, 500);
at the end of public drawing(). I Keep seeing things on layout management, but it's not helping me -- mainly because I'm not sure how to implement it
Here's a screenshot to help visualize what I'm talking about->
http://i.imgur.com/ttvif.png
Trying to get the button underneath. Unless there's a way to add an ActionListener to a drawImage()?
For your main panel use a BorderLayout.
Then to the "CENTER" you can add your game panel with all your custom painting.
Then create a panel and add the buttons to it. Now you can add this panel to the NORTH of the main panel.
In other words you are not restricted to using a single panel.
Also, custom painting should be done in the paintComponent() method of your panel, NOT the paint() method.
I'm not really sure what you are after, but here are two interpretations.
I suspect you want the 1st one 'Buttons over custom painting', but as a user I'd prefer the 2nd, with 'Buttons below custom painting'.
import java.awt.image.*;
import java.awt.*;
import javax.swing.*;
class PaintPanel extends JPanel {
BufferedImage bg;
PaintPanel(LayoutManager2 layout) {
super(layout);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (bg==null) {
bg = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bg.createGraphics();
GradientPaint gp = new GradientPaint(
0,0,Color.RED,500,500,Color.BLUE);
g2.setPaint(gp);
g2.fillRect(0,0,500,500);
g2.dispose();
}
g.drawImage(bg,0,0,getWidth(),getHeight(),this);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JPanel buttons = new JPanel(
new FlowLayout(FlowLayout.CENTER));
buttons.setOpaque(false);
buttons.add(new JButton("Start"));
buttons.add(new JButton("Stop"));
PaintPanel pp = new PaintPanel(new BorderLayout());
pp.setPreferredSize(new Dimension(200,100));
pp.add(buttons, BorderLayout.SOUTH);
JOptionPane.showMessageDialog(null,pp);
JPanel gui = new JPanel(new BorderLayout());
gui.setBackground(Color.ORANGE);
gui.add(pp, BorderLayout.CENTER);
gui.add(buttons, BorderLayout.SOUTH);
JOptionPane.showMessageDialog(null,gui);
}
});
}
}

Painting a custom JButton and a text line

I'm designing an optimization system for public transport in a big city. So I have a map with some points on it, but don't care about it)
All I need is: my own JButton, which looks like a color-filled circle and a small text tag near it. I got some problems while overriding the paintComponent() method.. the round button is painted correctly, but not the text.
BUT, when i'm resizing the window manually, the text appears for a second, then it gets repainted again and dissapears.
Hope you guys understood my needs, thanks for help ;)
import java.awt.*;
import javax.swing.*;
public class JRoundButton extends JButton {
String label;
Color color;
int x,y;
public JRoundButton(Color color,int x,int y,String str)
{
label=str;
this.x=x;
this.y=y;
this.color=color;
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Dimension size = getPreferredSize();
setPreferredSize(size);
this.setBounds(0, 0, 10, 10);
setContentAreaFilled(false);
g.setFont(new Font("Arial",Font.BOLD,14));
g.drawChars(label.toCharArray(), 0, label.length(), 12,12);
g.fillOval(0,0,8,8);
}
public void paintBorder(Graphics g)
{
g.setColor(Color.white);
g.drawOval(0,0, 9, 9);
}
public static void main(String[] args)
{
JButton button = new JRoundButton(Color.GRAY,150,150,"Times Square");
JFrame frame = new JFrame();
frame.getContentPane().setBackground(Color.black);
frame.setSize(300, 300);
frame.setVisible(true);
frame.add(button);
}
}
Seems that the call to 'setBounds( 0, 0, 10, 10 )' sets a component footprint that is too small to accomodate the text string. Extending the bounds to 100px wide and bringing down the point size to 6 looks to work okay.
1) NEVER set properties of the button in the paintComponent() method.
Dimension size = getPreferredSize();
setPreferredSize(size);
this.setBounds(0, 0, 10, 10);
setContentAreaFilled(false);
Get rid of the above code.
2) Dont set the Font of the Graphics object in the paintComponent() method. Thats what the setFont(...) method is used for.
3) There is no need to do any custom painting. If you want a circle, then add an Icon to the JLabel.
4) Don't override the paintBorder() method. If you want a Border then create a custom border and add it to the button using the setBorder() method.
In short there is no need to extend the button. Get rid of your JRoundButton class. Your code should simply look something like:
JButton = new JButton("Times Square");
button.setFont( new Font("Arial",Font.BOLD,14) );
button.setIcon( new OvalIcon(Color.WHITE, iconSize) );
Of course you will need to create an OvalIcon class but that is easy to implement since there are only three methods and you already know what the painting code should be.
I'd just cheat and use a unicode circle in the JButton's text. E.g.:
import javax.swing.*;
JFrame frame = new JFrame();
frame.getContentPane().add(new JButton("<html><font size='+10' color='red'>●</font> I'm next to a red circle!</html>"));
frame.pack();
frame.show();

drawing on Jframe

I cannot get this oval to draw on the JFrame.
static JFrame frame = new JFrame("New Frame");
public static void main(String[] args) {
makeframe();
paint(10,10,30,30);
}
//make frame
public static void makeframe(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(375, 300));
frame.getContentPane().add(emptyLabel , BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
// draw oval
public static void paint(int x,int y,int XSIZE,int YSIZE) {
Graphics g = frame.getGraphics();
g.setColor(Color.red);
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}
The frame displays but nothing is drawn in it. What am I doing wrong here?
You have created a static method that does not override the paint method. Now others have already pointed out that you need to override paintComponent etc. But for a quick fix you need to do this:
public class MyFrame extends JFrame {
public MyFrame() {
super("My Frame");
// You can set the content pane of the frame to your custom class.
setContentPane(new DrawPane());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 400);
setVisible(true);
}
// Create a component that you can actually draw on.
class DrawPane extends JPanel {
public void paintComponent(Graphics g) {
g.fillRect(20, 20, 100, 200); // Draw on g here e.g.
}
}
public static void main(String args[]){
new MyFrame();
}
}
However, as someone else pointed out...drawing on a JFrame is very tricky. Better to draw on a JPanel.
Several items come to mind:
Never override paint(), do paintComponent() instead
Why are you drawing on a JFrame directly? Why not extends JComponent (or JPanel) and draw on that instead? it provides more flexibility
What's the purpose of that JLabel? If it sits on top of the JFrame and covers the entire thing then your painting will be hidden behind the label.
The painting code shouldn't rely on the x,y values passed in paint() to determine the drawing routine's start point. paint() is used to paint a section of the component. Draw the oval on the canvas where you want it.
Also, you're not seeing the JLabel because the paint() method is responsible for drawing the component itself as well as child components. Overriding paint() is evil =)
You are overriding the wrong paint() method, you should override the method named paintComponent like this:
#Override
public void paintComponent(Graphics g)
You need to Override an exist paint method that actually up to dates your Frame. In your case you just created your custom new method that is not called by Frame default.
So change your method to this:
public void paint(Graphics g){
}

Categories