I'm having problems adding a JPanel, which has a paintComponent in it, to a JFrame.
If this is the only thing I add to the frame, it works. But as soon as I add a layout manager and add other components to the JFrame, it no longer shows the panel with the painting!
To make this clearer ...
This is the code that works and the JPanel is successfully shown:
The panel that draws the sign (in reality i am not trying to paint hello, this is to simply the code here)
public class SignPanel2 extends JPanel {
public int hello;
public void paintComponent(Graphics comp) {
Graphics g = (Graphics) comp;
g.setColor(Color.LIGHT_GRAY);
g.fillRect(70, 250, 150, 150);
g.setColor(Color.BLACK);
if (hello > 0)
g.drawString("h",135, 270);
if (hello > 1 )
g.drawString("h e",135, 270);
if (hello > 2)
g.drawString("h e l",135, 270);
if (hello > 3)
g.drawString("h e l l",135, 270);
if (hello > 4)
g.drawString("h e l l o",135, 270);
}
}
The frame i put the panel on:
public class SignFrame extends JFrame {
// the constructor method
public SignFrame () {
super("This is the title of the Sign Frame");
setSize(300,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// make a container for the frame
Container content = getContentPane();
// call from the drawing panel
SignPanel2 signpanel = new SignPanel2();
// change class variable of SignPanel
signpanel.hello = 5;
signpanel.repaint();
// add signpanel to container
content.add(signpanel);
setContentPane(content);
setVisible(true);
}
}
The main class
public class TheSignMain {
public static void main (String[] args) {
SignFrame signframe = new SignFrame();
}
}
The above works perfectly fine and gives me a frame with the desired drawing in it.
But if I add other components to the frame and add a layout manager, it no longer shows me the painting. even if I use repaint().
I have to include a layout manager, otherwise it adds the panel with the painting, but not the other components.
This is how my frame class looks now, and this is where i'm having problems.
public class SignFrame extends JFrame {
// the constructor method
public SignFrame () {
super("This is the title of the Sign Frame");
setSize(300,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// make a container for the frame
Container content = getContentPane();
// need a layout manager to decide the arrangement of the components on the container
FlowLayout flo = new FlowLayout();
// designate the layout manager to the container
content.setLayout(flo);
// make components
JPanel buttons = new JPanel();
JButton play = new JButton("Play");
JButton pause = new JButton("Pause");
JButton stop = new JButton("Stop");
// add components to a panel
buttons.add(play);
buttons.add(pause);
buttons.add(stop);
// add panel to frame container
content.add(buttons);
// call from the drawing panel
SignPanel2 signpanel = new SignPanel2();
// change class variable of SignPanel
signpanel.hello = 5;
signpanel.repaint();
// add signpanel to container
content.add(signpanel);
setContentPane(content);
setVisible(true);
}
}
I am totally new to Java, so any help will be much appreciated.
Sorry for all that code and thanks for your help!!
Not tested, but the flow layout probably uses the preferred size of your panel, and you probably haven't overridden getPreferredSize() to return something other than a [0, 0] dimension.
Also, you should encapsulate the change of the hello variable in a setHello() method that calls repaint(). The calling code shouldn't have to deal with repaint. The panl should know when it has to be repainted, and call repaint itself.
Related
So basically when I add a button it essentially pushes the black rectangle drawn in this program down, putting it out of its given location. How would you fix this?
import javax.swing.*;
import java.awt.*;
public class Grid {
public class homeGraphics extends JComponent {
homeGraphics() {
setPreferredSize(new Dimension(450, 600));
}
public void paint(Graphics g) {
super.paint(g);
g.fillRect(200, 275, 50, 50);
}
}
public void homeFrame() {
JFrame frame1 = new JFrame();
frame1.setSize(450, 600);
frame1.setResizable(false);
frame1.setDefaultCloseOperation(frame1.EXIT_ON_CLOSE);
JButton playButton = new JButton("Play");
playButton.setPreferredSize(new Dimension(60, 30));
JPanel panel1 = new JPanel();
panel1.add(playButton);
panel1.add(new homeGraphics());
frame1.add(panel1);
frame1.setVisible(true);
}
public static void main(String args[]) {
Grid frame = new Grid();
frame.homeFrame();
}
}```
it essentially pushes the black rectangle drawn in this program down, putting it out of its given location.
What do you mean out of its location? Painting is always done relative to the component. So your painting will always be done at (200, 275) of the component.
If you are attempting to paint at (200, 275) relative to the "frame", then don't. That is NOT how painting works.
Other problems with your code:
Don't attempt to set the size of your frame. If the custom panel is (450, 600) how can the frame possibly be the same size? The frame also contains the "title bar" and "borders". Instead of using setSize(), you invoke frame.pack()just beforeframe1.setVisible(….)`.
Class names start with an upper case character. Learn by example. Have you ever seen a class name in the JDK that doesn't start with an upper case character?
Custom painting is done by overriding paintComponent(…), not paint().
By default a JPanel uses a FlowLayout. So what you see it the button on one line and then the "HomeGraphics" class is too big to fit on the same line so it wraps the to the second line.
You should be more explicit when you do frame layout. So your code should be something like:
JPanel wrapper = new JPanel();
wrapper.add( playButton );
//JPanel panel1 = new JPanel();
//panel1.add(playButton);
//panel1.add(new homeGraphics());
JPanel panel1 = new JPanel( new BorderLayout() );
panel1.add(wrapper, BorderLayout.PAGE_START);
panel1.add(new HomeGraphics(), BorderLayout.CENTER);
Now the code shows your layout attempt more clearly.
I want to use a JLabel in a very simple environment but I'm wondering why I have to set the location on every repaint.
Code:
public class Example {
public static void main(String[] args) {
JFrame frame = buildFrame();
TestPane pane = new TestPane();
frame.add(pane);
while (true) {
pane.repaint();
frame.setVisible(true);
}
}
private static JFrame buildFrame() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(480, 272);
frame.setVisible(true);
return frame;
}
}
public class TestPane extends JPanel {
JLabel testLabel = new JLabel("TEST");
TestPane() {
super();
add(testLabel);
testLabel.setLocation(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
testLabel.setLocation(200, 200); // without this line, the label will always be at the top center
}
}
The loop-based layout comes from various animations with images I'm doing. Why does the repaint always reset the location of all labels so I have to setLocation on every paintComponent?
why I have to set the location on every repaint.
You don't. Actually, you should never set the position or any kind of constraint of a component inside paintComponent method. paintComponent method is only for painting, not for orientation or anything else.
When you jpanel.add(myComponent, constraints) component's position will be decided by container's current LayoutManager. (When you jpanel.add(myComponent); without any constraints, the default constraints will take place, with every layout manager having its own default).
The label is placed at the top of the panel because you do not set the layout of the panel, so it has its default, which is FlowLayout. In order to change it you will have to use another layout manager with the proper constraints.
For example, in order to place it at the center of the panel, you must do:
jpanel.setLayout(new BorderLayout());
jpanel.add(myLabel,BorderLayout.CENTER);
Finally doing while(true) inside the Thread where you GUI is running, it will hang the thread, means that the GUI will be "frozen" since events cannot take place.
When I run this program it appears as an empty window until you fullscreen, then it can be resized as you like, why is it doing this/how do I stop it?
the program is very basic just a menubar and two panels split.
public class SplitPane {
public static void main(String[] args) {
window view = new window();
}
private static class window extends JFrame {
public window() {
this.setSize(1000, 750);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//menubar is here, must lower code quantity for stack
//panels
//graph half
JPanel graphRep = new JPanel();
//Background colour - graphRep.setBackground(Color.RED);
graphRep.setVisible(true);
String graphTitle = "Textual Representation.";
Border graphBorder = BorderFactory.createTitledBorder(graphTitle);
graphRep.setBorder(graphBorder);
//text half
JPanel textRep = new JPanel();
textRep.setVisible(true);
String textTitle = "Graphical Representation.";
Border textBorder = BorderFactory.createTitledBorder(textTitle);
textRep.setBorder(textBorder);
//splitpane
JSplitPane splitPane = new JSplitPane();
splitPane.setSize(600, 750);
splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
splitPane.setOneTouchExpandable(true);
splitPane.setDividerSize(10);
splitPane.setDividerLocation(250);
splitPane.setLeftComponent(graphRep);
splitPane.setRightComponent(textRep);
this.add(splitPane);
}
}
this.setVisible(true);
You are making the frame visible BEFORE you add components to the frame. The layout manager is never invoked so the size of all the components remains (0, 0) so there is nothing to paint.
The frame should be made visible AFTER all the components have been added to the frame.
And the code should be:
frame.pack();
frame.setVisible();
So each component is displayed at its proper size. Don't hardcode the size() because you don't know what the size of a users screen might be.
I am trying to place a JPanel on top of another JPanel which contains a JTextArea and a button and i want to the upper apnel to be transparent. I have tried it by making the setOpaque(false) of the upper panel. but it is not working. Can anyone help me to get through this? Thanks in advance!
public class JpanelTest extends JPanel
{
public JpanelTest()
{
super();
onInit();
}
private void onInit()
{
setLayout(new BorderLayout());
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JTextArea(100,100),BorderLayout.CENTER);
panel.add(new JButton("submit"),BorderLayout.SOUTH);
JPanel glass = new JPanel();
glass.setOpaque(false);
add(panel,BorderLayout.CENTER);
add(glass,BorderLayout.CENTER);
setVisible(true);
}
public static void main(String args[])
{
new JpanelTest();
}
}
Indeed, it would be useful to tell the reason why you want panels one over another.
Starting with your code, and changing it a lot, I got it to work, but it might not do what you expect...
import java.awt.*;
import javax.swing.*;
public class Test extends JFrame
{
public Test()
{
super();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 200);
onInit();
setVisible(true);
}
private void onInit()
{
JLayeredPane lp = getLayeredPane();
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JTextArea(), BorderLayout.CENTER);
panel.add(new JButton("Submit"), BorderLayout.SOUTH);
panel.setSize(300, 150); // Size is needed here, as there is no layout in lp
JPanel glass = new JPanel();
glass.setOpaque(false); // Set to true to see it
glass.setBackground(Color.GREEN);
glass.setSize(300, 150);
glass.setLocation(10, 10);
lp.add(panel, Integer.valueOf(1));
lp.add(glass, Integer.valueOf(2));
}
public static void main(String args[])
{
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new Test();
}
});
}
}
If totally transparent, well, it is like it isn't here! When opaque, it just covers some of the GUI, but doesn't prevent mouse clicks, for example.
1) there are a few ways, there no issue to put JPanel, with covering full JFrames/JPanel area or only part of Rectangle / Dimension that returns JFrames/JPanel
use JLayer(Java7) based on JXLayer (Java6)
use GlassPane
use JViewport
use OverlayLayout
use transucent JDialog / JWindow
2) everything depends of if you want to protect against mouse and key events from the top layer to bottom, or not (to avoiding redispatch events from - to and vice versa)
Check out this tutorial on using Swing Root Panes.
The glass pane is useful when you want to be able to catch events or paint over an area that already contains one or more components. For example, you can deactivate mouse events for a multi-component region by having the glass pane intercept the events. Or you can display an image over multiple components using the glass pane.
For my assignment, I am given this piece of code:
// This class/method uses a global variable that MUST be set before calling/using
// note: You can not call the paint routine directly, it is called when frame/window is shown
// look up the repaint() routine in the book
// Review Listings 8.5 and 8.6
//
public static class MyPanel extends JPanel {
public void paintComponent (Graphics g) {
int xpos,ypos;
super.paintComponent(g);
// set the xpos and ypos before you display the image
xpos = 10; // you pick the position
ypos = 10; // you pick the position
if (theimage != null) {
g.drawImage(theimage,xpos,ypos,this);
// note: theimage global variable must be set BEFORE paint is called
}
}
}
My professor also says: You will also need to to look up how to create AND add a JPanel to a JFrame. If you can create AND add a JPanel, then all you need to do is substitute 'MyPanel' for the class name 'JPanel' and this code will display an image on the window frame.
What does he mean by "then all you need to do is substitute 'MyPanel' for the class name 'JPanel' and this code will display an image on the window frame"? I'm confused as to where I'm supposed to substitute MyPanel. Here's my code:
public static class MyPanel extends JPanel {
public void paintComponent (Graphics g) {
int xpos,ypos;
super.paintComponent(g);
JPanel panel= new JPanel();
JFrame frame= new JFrame();
frame.setSize(500,400);
frame.add(panel);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set the xpos and ypos before you display the image
xpos = 600; // you pick the position
ypos = 600; // you pick the position
if (theimage != null) {
g.drawImage(theimage,xpos,ypos,this);
// note: theimage global variable must be set BEFORE paint is called
}
}
}
If I understand what you're asking right... In your assignment, you're being asked to extend JPanel for your own needs. Note how you would add a JPanel if it were not being extended:
JFrame myFrame = new JFrame();
JPanel myPanel = new JPanel();
myFrame.add(myPanel);
myFrame.pack();
myFrame.setVisible(true);
This adds the JPanel to the JFrame, packs it and sets it to be visible. Since your myFrame class extends JPanel, you should be able to do something very similar by creating a new instance of your panel class and adding it to your JFrame.
You won't want to be doing this part in paintComponent(), as paintComponent() can potentially be called multiple times. Check here to see what paintComponent() does.
#Hyper Anthony
So it would be something similar to this?:
MyPanel Mypanel= new MyPanel();
JFrame Myframe= new JFrame();
Myframe.setSize(500,400);
Myframe.add(Mypanel);
Myframe.setVisible(true);
Myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);