How do you add a JPanel onto another JPanel that has graphics? - java

Basically what im trying to do is to add a JPanel onto another JPanel that has painted graphics on it using the paintComponent() method. But the JPanel I am trying to add is not shown because it is covered up by the JPanel w/ Graphics on it.
How can I make it so that when I add the JPanel to the one w/ graphics it will show the JPanel in the front instead of being covered up by the Graphics?
All answers are appreciated! :)
If you need the code just tell me and I will gladly put it on here.
Alright here is the code:
package javavideogame;
public class Game extends JPanel implements ActionListener, Runnable
{
public Game(MainCharacter character)
{
setLayout(null);
setFocusable(true);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(ground, 0, 0, this);
g.drawImage(character.getImage(), character.getX(), character.getY(), this);
g.setColor(Color.RED);
g.drawRect(10, 10, character.getMaxHealth(), 10);
g.fillRect(10, 10, character.getHealth(), 10);
g.dispose();
}
public void getInventoryScreen()
{
Main.inv = new Inventory();
Main.game.add(Main.inv);
}
}
And here is the code for the JPanel that I'm adding to the Game JPanel
public class Inventory extends JPanel
{
public Inventory()
{
setLayout(null);
setSize(400, 300);
setBackground(Color.BLACK);
addKeyListener(this);
setFocusable(true);
}
}

Custom painting is done by overriding the paintComponent(...) method. My guess is that you are overriding the paint() method.
Read this section from the Swing tutorial on Custom Painting. Because you are overriding the wrong method, you end up painting the children first and then the custom painting is done on top.
If you need more help than post your SSCCE demonstrating the problem.

Just a reminder: java.awt and javax.swing don't mix well. When you're painting stuff on one panel AND trying to add a JPanel to it, you are bound to run into problems somewhere. A far better solution is to have 2 different JPanels, one for your graphics, and one for your inventory.
Something like this:
JPanel mainPanel = new JPanel(); //will hold BOTH panels
JPanel gamePanel = new Game(myCharacter); //declare game panel
JPanel inventoryPanel = new Inventory(); //declare inventory panel
//set up some layout
mainPanel.setLayout(new GridLayout(2, 1));
//add the graphics panel, then add the inventory
mainPanel.add(gamePanel);
mainPanel.add(inventoryPanel);
This will keep your swing and awt components from mixing and save you a lot of headaches.

Related

Make JScrollPanel dynamically resizable with JPanel drawing

I have a JScrollPanel and a JPanel added to it. I would like to draw to the JPanel and make the scrollbars of the JScrollPane appear whenever the drawing exceeds the size of the panel and be able to scroll the drawing both vertically and horizontally.
I have tried consulting with various forums and the official docs and tried a few things (setting the borders, the preferred size, etc.) but none seems to yield the desired effects.
I have a JFrame (with GridBagLayout, btw.) :
JFrame frame1 = new JFrame("Application");
frame1.setVisible(true);
frame1.setMinimumSize(new Dimension(580,620));
frame1.setResizable(false);
frame1.setLocationRelativeTo(null);
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
The relevant components are :
JPanel panel1 = new JPanel();
JScrollPane scrollPane = new JScrollPane(panel1);
frame1.add(scrollPane, gbc_panel1); //added with layout constraints
JPanel :
panel1.setBackground(Color.BLACK);
panel1.setPreferredSize(new Dimension(500,500));
panel1.setMinimumSize(new Dimension(360,360));
panel1.setMaximumSize(new Dimension(1000,1000));
JScrollPane :
scrollPane.setAutoscrolls(true);
The relevant code from the action event
of a button that does the drawing :
Graphics g;
g = panel1.getGraphics();
panel1.paint(g);
g.setColor(new Color(0,128,0));
/* this is followed by some more code that
does the drawing of a maze with g.drawLine() methods */
The code does the drawing perfectly, I just can't seem to figure it out how to make the scrolling and dynamic resizing happen.
I would appreciate any helpful comments or remarks!
Thank you!
Ultimately rewriting the paint method did the trick as #MadProgrammer suggested. I was just hoping that I could do the painting without having to define my custom JPanel class, but looks like it doesn't work that way.
The custom class looks like this:
class Drawing extends JPanel {
int mazeSize;
public Drawing(JTextField jtf)
{
try {
this.mazeSize = Integer.parseInt(jtf.getText());
}
catch (Exception e)
{
JOptionPane.showMessageDialog(this, "ERROR! Invalid size value!");
}
} // the constructor gets the size of the drawing from a textField
public Dimension getPreferredSize() {
return new Dimension(mazeSize*10,mazeSize*10);
} //getPreferredSize - this method is used by the scroll pane to adjust its own size automatically
public void drawMaze (Graphics g)
{
/* some irrelevant code that does the desired drawing to the panel by calling g.drawLine()*/
} // drawMaze method that does the de facto drawing
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
drawMaze(g);
}// paintComponent() #Override method - this was the tricky part
}//Drawing JPanel subclass
It is also worth noting (if some noob like myself happens to stumble upon this question), that after instantiating the new JPanel subclass in the action event, I had to add it to the JScrollPanel in the following way, instead of just simply using its add() method:
Drawing drawPanel = new Drawing(textfield1);
scrollPane.getViewport().add(drawPanel);
Again, thanks for the suggestion!
Once finished with the program (a random maze generator that uses a recursive backtracking algorithm), I will make the source code available at my github profile.

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.

Understanding painting in swing

I'm trying to understand what actually paints components in Swing. I read this article about painting in AWT and Swing and now tried to write the following simple program:
//A simple wrapper to understan how paint() works
public class MyButton extends JButton{
/**
* Default serialVersionUID
*/
private static final long serialVersionUID = 1L;
private final JButton jButton;
public MyButton(JButton jButton) {
this.jButton = jButton;
}
#Override
public void paint(Graphics g){
jButton.paint(g);
}
}
But when I try to add MyButton to frame
JFrame frame = new JFrame("Hello swing");
JPanel panel = new JPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.add(new MyButton(button));
frame.add(panel);
it renders nothing
But after deleting
#Override
public void paint(Graphics g){
jButton.paint(g);
}
it renders the empty button:
QUESTION: Why does it behave that way? Why does the delegating cause rendering to fail?
First of all when you post a question you should post a proper SSCCE that demonstrates the problem. We can't copy/compile random lines of code. Until a problem is solved, you don't know what part of the code is causing the problem.
Why does the delegating cause rendering to fail?
My guess would be that the size of the button is (0, 0) so there is nothing to paint.
When you get rid of the custom paint method, then the real button can be painted because it does have a size because the layout manager has done its job.
public class Demo extends JFrame{
public static void main(String[] args)
{
JPanel panel = new JPanel();
getContentPane().setLayout(new BorderLayout());
panel.add(new JButton("Test"));
this.getContentPane().add(panel, BorderLayout.CENTER);
this.setSize(200,200);
this.setVisible(true);
}
}
If you want to add UI Components do it like that, don't use paint in any way.
If you want to paint for example a rectangle follow this tutorial: https://docs.oracle.com/javase/tutorial/uiswing/painting/
Your paint method does not draw the MyButton object, but instead draws the JButton which is member of your class. The problem now is, that this Button has not been added to the panel and so it's drawn on nothing. By removing your paint method, super.paint(g) is called because your class has no paint method and so your button, but not the member JButton is drawn.
I hope you understand what I am trying to explain to you.

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);
}

Drawing a line on another JFrame in a class that extends JFrame

I have a class with two JFrames and am trying to draw a line on a particular frame .
I tried the code below but it only appears in the first frame which is the success frame.
It also appears above all the other components of the success frame thus making all other
components invisible. It does not appear in the comp Frame.
How do I correct this.
Here is the code I have so far :
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
public class lineGUI{
public static void main(String []args){
Success s=new Success();
s.setVisible(true);
}
}
class Success extends JFrame{
JPanel alas =new JPanel();
JFrame comp =new JFrame();
public Success(){
JPanel panel=new JPanel();
getContentPane().add(panel);
setSize(450,450);
JButton button =new JButton("press");
panel.add(button);
comp.setSize(650,500);
comp.setTitle("View Report");
JRootPane compPane=comp.getRootPane();
Container contePane=compPane.getContentPane();
contePane.add(alas);
ActionListener action =new ActionListener(){
public void actionPerformed(ActionEvent e){
if (e.getSource()==button){
comp.setVisible(true);
}
}
};
button.addActionListener(action);
JButton button2=new JButton("access");
alas.add(button2);
}
public void paint(Graphics g) {
comp.paint(g);
Graphics2D g2 = (Graphics2D) g;
Line2D lin = new Line2D.Float(100, 100, 250, 260);
g2.draw(lin);
}
}
You've got some crazy code up there. Suggestions:
Don't draw directly in a JFrame, but in a the paintComponent method of an object derived from JComponent such as JPanel or JComponent itself.
Your drawing directly in another component's paint(...) method is not kosher at all. Why not simply share the data between classes, and use the data (the ints) to draw where desired.
You would rarely want to have a GUI display more than one JFrame at a time. Usually one window is the main window (the JFrame), and it often owns any other windows which would be dialog windows such as JDialogs.
Read the graphics tutorials to learn the correct way to do Swing Graphics
Two things:
If you want to draw in the "comp" frame, then you should extend that frame explicitly to overload its paint method. Right now you're overloading the paint method of "Success" frame. The line comp.paint(g) is using the paint method of comp (a standard JFrame) to draw on the Graphics object of the "Success" frame. You probably want to make that into super.paint(g) instead, then put this paint function into it's own JFrame and create comp from that.
http://pastebin.com/ZLYBHpmj
(Sorry, first post, couldn't figure out how to get Stackoverflow to quit complaining about format)

Categories