How to replace a JPanel with another while the program is running - java

The code has a JPanel with an inner JPanel that displays awt drawing. Upon mouseclick the inner JPanel is to be replaced by one of its polymorphic siblings. This code isn't replacing the jPanel.
class ContentPanel extends JPanel {
private GraphicPanel graphicPanel;
public ContentPanel(GraphicPanel graphicPanel) {
this.graphicPanel = graphicPanel;
add(this.graphicPanel);
public void setGraphicPanel(GraphicPanel graphicPanel) {
this.graphicPanel = graphicPanel;
// invalidate();
// revalidate();
// repaint();
}
Setting the graphicPanel to a polymorphic relative doesn't cause any errors, it just isn't painting the new graphicPanel. Using cardLayout is not preferred, there must be a cleaner way. How to proceed?

in setGraphicPanel, you need to remove the current graphicPanel and add the new one. THEN call revalidate.
something like this:
public void setGraphicPanel(GraphicPanel graphicPanel) {
this.removeAll();
this.graphicPanel = graphicPanel;
this.add(graphicPanel);
this.revalidate();
}
Although CardLayout was designed to do just this thing. Are you sure you don't want to use CardLayout?

Related

JPanel How to create an instance/object

I keep mixing up JFrame and JPanel. I have a code that compiles but nothings happens and the program ends.
This is a homework assignment that requires us to draw a triangle. Then add a button, when button is pressed the triangle will flip upside down. Press again to return to the first location.
Any assistance would be great. This is my countless rough draft and I'm just trying to initiate the object to view.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import java.awt.Color;
public class Triangle extends JPanel implements ActionListener
{
JButton button = new JButton("Just Flip It");
public Triangle()
{
add(button);
button.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(125,75,100,200);
g.drawLine(125,75,150,200);
g.drawLine(100,200,150,200);
}
public static void main(String[] args)
{
Triangle frame = new Triangle();
frame.setSize(400, 400);
frame.setVisible(true);
}
}
Think of a JPanel as a piece of paper and a JFrame as a book.
If you never add the piece of paper to the book, it will never be shown.
So, here are the steps to get your program running:
Create a JFrame that will hold your JPanel (Triangle) inside it
Add some logic in your ActionListener to have a boolean flag, that will be changed to true or false depending on the current state and based on it repaint the pane
Have some logic inside the paintComponent(...) method that draws the triangle upside down or upside up based on the state of the boolean flag above
So, from the above in your main(...) method you should have
JFrame frame = new JFrame("My frame");
//Initialize your Triangle here
frame.add(triangle);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
Your actionPerformed() method should look like this:
public void actionPerformed(ActionEvent e)
{
clicked = !clicked;
repaint();
}
And your paintComponent():
super.paintComponent();
if (clicked) {
//Draw upside up
} else {
//Draw upside down
}
As we're using pack() instead of setSize(...) method, we should override getPreferredSize() method of our JPanel as well:
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
Otherwise we could get a really small JFrame (and it's a good practice to do it this way)
Also don't forget to place your program on the EDT (as I show in the point #2 of this answer)
As a side note, you might also want to move to use the Shape's API as recommended by #MadProgrammer in this answer
Both links above have cool examples and tips, check them out!
You need to add your JPanel to a JFrame object in your main method in the same way you add a button to your panel. The JFrame is the window that your JPanel exists inside of.
Make sure that you set the JFrame object to visible and set its size.
Not related to your question, but I would suggest at least separating out a private class for you ActionListener rather than having the Triangle class be both. If you're feeling adventurous, you could look into using an anonymous inner class or a lambda expression.

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.

Calling a JPanel from Another Class onto the Main Class' JPanel

Good afternoon,
As a personal project intended to help me practice using JPanels and subclasses, I am coding a professional web portfolio containing my education, work and volunteer experience, and other notable works using JApplets.
I have the layout set to BorderLayout with the JButtons aligned WEST. When a button is clicked, the JPanels in the CENTER are supposed to switch out with the appropriate panel. However, I am not that far yet.
As of now, I only have a JLabel onto my Home JPanel that says "Home," because I'd like to make sure the method from the Home JPanel class is working before doing anything more. The issue is that the JPanel isn't displaying on the applet.
The thing is, when I move all the code into from the JPanel's class onto the main class, it displays just fine. So I know the problem is with either how I'm constructing the method, or with how I constructed my JPanel's class.
I've tried setting it to visible-- that didn't work. I've tried setting the LayoutManager as a parameter for the class constructor, I've tried adding paintComponent and super.paint(g), I tried using this.home.addHomePanel-- but nothing worked.
I know I'm missing a few things. It would be appreciated if someone could give me a hand. Please let me know if you need more information. Thank you for reading.
Main Class:
public class myWebFolio extends JApplet implements ActionListener
{
JButton[ ] menu =
{
new JButton("Home"),
new JButton("Education"),
new JButton("Work Experience"),
new JButton("Programming Projects"),
new JButton("Other")
};
//adds panel to memory
private JPanel buttonPanel = new JPanel();
private Home home;
public void init()
{
setLayout (new BorderLayout( ) ); //changes the layout of the appl
home = new Home();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
/*
* Adds an ActionListener to each button
* and then adds the button to the buttonPanel.
* Also adds an invisible componenet to give the buttons
* spacing.
*/
for (int i=0; i<menu.length; i++)
{
menu[i].addActionListener(this);
buttonPanel.add(Box.createVerticalStrut(100));
buttonPanel.add(menu[i]);
}
add(buttonPanel,BorderLayout.WEST);
home.addHomePanel();
}
public void actionPerformed(ActionEvent event)
{
}
public void paintComponent(Graphics g)
{
super.paint(g);
}
}
Home Panel's Class:
public class Home extends JPanel
{
JPanel homePanel = new JPanel(new FlowLayout());
JLabel label = new JLabel("Home");
/**
* Constructor for objects of class Home
*/
public Home()
{
}
public void addHomePanel()
{
homePanel.add(label, FlowLayout.LEFT);
homePanel.setVisible(true);
add(homePanel, BorderLayout.CENTER);
}
public void paintComponent(Graphics g)
{
super.paint(g);
}
}

JTabbedPane repaint does not work

This is not a repeat question. Yes there are similar, but none have provided a working answer.
public class Tool extends JPanel implements ActionListener{
public JPanel Panel;
public Tool() {
}
public void show(){
displayStuff();
Panel.setVisible(true);
revalidate();
repaint();
}
}
Tool MyTool = new Tool();
JPanel Master = new JPanel();
JPanel Dash = = new JPanel();
JTabbedPane Tabs = new JTabbedPane();
JTabbedPane Tabs.addTab("Dash", Dash);
JTabbedPane Tabs.addTab("Tool", MyTool.Panel);
Master.add(Tabs);
The real code is much more complex. But the basic issue is that when changes occurs on MyTool.Panel as a result of user pressing some buttons.
MyTool.Panel does NOT get repainted until I use mouse to move Master.
How can I force it to repaint?
Its not a perfect solution but you can validate and redraw the entire application, thats what I have done in the past. I've used something like
class MyPanel extends JPanel{
public void doRedraw(){
getTopLevelAncestor().revalidate();
getTopLevelAncestor().repaint();
}
}
Hope this helps.

Moving a JLabel's position for every update

I'm learning Swing and I have the following code:
public class SimView {
private JFrame frame;
private JLabel background;
private JPanel car_panel;
public SimView() {
frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 500);
frame.getContentPane().setLayout(null);
background = new JLabel("");
background.setIcon(new ImageIcon(
"C:\\Users\\D__\\Desktop\\background.png"));
background.setBounds(0, 0, 384, 462);
frame.getContentPane().add(background);
frame.setVisible(true);
car_panel = new JPanel();
car_panel.setBounds(175, 430, 16, 21);
car_panel.setVisible(true);
car_panel.setBackground(Color.BLACK);
background.add(car_panel);
MoveCarRunnable carMover = new MoveCarRunnable(car_panel);
}
private static class MoveCarRunnable implements Runnable {
private JPanel car;
MoveCarRunnable(final JPanel car) {
this.car = car;
}
#Override
public void run() {
// Should I call rePaint() on the car_panel here then ?
}
}
What I want to do is to move the JLabel called "car" 's y coordinates for every update to get the effect of it moving by itself i.e. no user interaction. I'm not quite sure how to do this, I suppose I need to have some sort of repaint() method redrawing the position of the JLabel for every update. But how do I get this class to know that it needs to update the position?
Any pointers (links/code) would be appreciated. I want to get the concept of how Swing and its components work in this case, rather than just employing a solution but of course I am interested in a solution so I can study it closer. Thanks
EDIT:
Please see my edit code above
You will have to create a separate Thread that would modify the location of your label and then call validate() and repaint() on the container (frame.getContentPane()). Don't forget to put some sleep() value inside the thread.
However, there would be a better approach to create a separate JPanel. Inside it you would override the paintComponent method or the paint method and there you would draw an image instead of moving JLabels around.
You should better add a JPanel instead of the label to your layout. Choose the dimensions of the JPanel so that it can contain your car in every phase.
Then overwrite the paint method of that panel to position the image on it.

Categories