// This works!
JPanel background = new JPanel();
background.setBackground(Color.BLACK);
background.setBounds(0,0,this.getSize().width,this.getSize().height);
add(background);`
// Ihis method doesn't work! Why ? And the classic method setBackground(Color.BLACK); has the same problem
JPanel background = new JPanel()
{
#Override
public void setBackground(Color bg){
super.setBackground(Color.BLACK);
}
#Override
public void setBounds(int a, int b, int c, int d){
super.setBounds(0,0,this.getSize().width,this.getSize().height);
}
};
add(background);
Definite issue you are going to encounter will come from calling setBounds method.
Call setBackground for your panel and just add it to JFrame by calling add method. JPanel will be added on center of JFrame by default since default layout for JFrame is a BorderLayout and it will perfectly fit without of calling setBounds. There is absolutely no need to complicate things by overriding any method.
This:
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestPanel {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JPanel panel = new JPanel();
panel.setBackground(Color.BLACK);
JFrame frame = new JFrame();
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//frame.pack();
frame.setSize(400, 300);
frame.setVisible(true);
});
}
}
...will work perfectly.
Though you have ovverriden methods, you haven't called them.
Related
I've built a simple gui that adds panels based on user input. My initial problem was that when the panel was added the frame did not resize. Because it was a jpanel object that handled the user input adding a new panel to itself and therefore could not 'see' the jframe (at least I couldn't find how it could) I couldn't work out how to call repaint() or revalidate() on the parent frame from within that object. However,through trial and error I did find that this worked
JFrame jFrame = new JFrame(title){
#Override
public void invalidate(
super.invalidate();
this.pack();
}
};
But because I don't really know what goes on behind the scenes with invalidate I want to know whether this is a good idea or not (It seems kinda sketchy). Any advice would be great, thanks.
EDIT
Hope this makes the problem a bit clearer
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class TestFrame {
JFrame jframe;
NewPanel jpanel;
public TestFrame(){
jframe = new JFrame(); // without above addition frame won't resize
jpanel = new NewPanel();
jframe.add(jPanel);
jframe.pack();
jframe.setVisible(true);
}
public static void main(String [] args){
TestFrame testframe= new TestFrame();
}
}
class NewPanel extends JPanel implements ActionListener{
public NewPanel(){
JTextField textField = new JTextField (10);
textField.addActionListener(this);
this.add(textField);
}
// Adds a label when action is performed on textfield
#Overide
public void actionPerformed(ActionEvent ae){
JPanel extraPanel = new JPanel();
extraPanel.add(new JLabel("hi"));
this.add(extraPanel);
this.revalidate(); this.repaint();
}
}
Your issue is not that revalidate() or repaint() aren't working.
The issue here is that your JFrame has been pack()ed already and thus it has a preferred size set. If you want to change its size you need to call pack() on it again. Not necessarily to call it on invalidate().
I made some changes to your code to compile (typos) and I came with this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestFrame {
JFrame jframe;
NewPanel jpanel;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new TestFrame());
}
public TestFrame(){
jframe = new JFrame(); // without above addition frame won't resize
jpanel = new NewPanel();
jframe.add(jpanel);
jframe.pack();
jframe.setVisible(true);
}
class NewPanel extends JPanel implements ActionListener{
public NewPanel(){
JTextField textField = new JTextField (10);
textField.addActionListener(this);
this.add(textField);
}
// Adds a label when action is performed on textfield
#Override
public void actionPerformed(ActionEvent ae){
System.out.println("WOLOLO");
JPanel extraPanel = new JPanel();
extraPanel.add(new JLabel("hi"));
this.add(extraPanel);
this.revalidate();
this.repaint();
jframe.pack();
}
}
}
Another way to solve this is to override getPreferredSize method from the JPanel:
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
And you can delete jframe.pack() in the previous code.
i just started studying gui in java. i am now able to create windows with specific sizes while extending JFrame. however, i came to read posts from here that it is better not to extend JFrame. then i tried to create a window by setting the size in the JPanel instead, but the setSize doesn't seem to work (my code must lack something)
here's my code for my frame
import javax.swing.JFrame;
public class MyFrame{
private JFrame mainFrame;
private MyPanel mainPanel;
public MyFrame(){
mainFrame = new JFrame();
mainPanel = new MyPanel(50, 50);
mainFrame.add(mainPanel);
mainFrame.setVisible(true);
}
}
and here's my code for my panel
import javax.swing.JPanel;
public class MyPanel extends JPanel{
public MyPanel(int i, int j){
setSize(i, j);
}
}
i tried adding frame.pack() in my Frame class, because i thought the frame, not having it's size set, is too small for the panel to be seen -i was wrong
what's lacking in my code?
what's lacking in my code?
A preferred size for the custom component (Panel) for starters. #Override getPreferredSize() to return a logical value.
Then pack() the frame to ensure it is the smallest size needed to display the panel and any other components.
So, something like this:
import javax.swing.*;
public class Application {
private JFrame frame;
private CustomPanel panel;
public Application() {
frame = new JFrame();
// next 2 lines, just a good idea
frame.setLocationByPlatform(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// at 50x50, the title bar on Windows is wider!
panel = new CustomPanel(200, 200);
frame.add(panel);
// make the frame smallest it can be and still show components
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new Application();
}
};
SwingUtilities.invokeLater(r);
}
}
class CustomPanel extends JPanel {
public CustomPanel(int w, int h) {
setPreferredSize(new java.awt.Dimension(w, h));
}
}
I have a problem. Now I'm working with 3 panels, mainPanel and 2 others ( btnPanel and iconPanel).
So the problem is when I push button "reset" I delete iconPanel and add it again it moves slightly to right on its own. Maybe someone can check my code where the problem?
Also I dont want to create another question so I give 2 extra questions.
Do I delete JPanel properly?
If I delete JPanel with components inside they also will be removed from memory?
P.s. Im beginner so dont judge me :)
Main.java
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Main extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Made by Mac4s");
frame.setVisible(true);
frame.setSize(310, 654);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setResizable(false);
MainScreen screenObj = new MainScreen();
screenObj.setPreferredSize(new Dimension(310, 650));
frame.add(screenObj);
}
});
}
}
MainScreen.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class MainScreen extends JPanel {
private JButton resetBtn;
private JPanel btnPanel;
private JPanel iconPanel;
public MainScreen() {
JPanel mainPanel = new JPanel(new BorderLayout());
this.setBackground(Color.BLACK);
setBtnPanelAndComp();
setIconPanelAndComp();
add(mainPanel);
}
private void setBtnPanelAndComp() {
btnPanel = new JPanel(new BorderLayout());
btnPanel.setBackground(Color.GREEN);
btnPanel.setPreferredSize(new Dimension(295, 30));
setButtons();
this.add(btnPanel, BorderLayout.NORTH);
}
private void setButtons() {
resetBtn = new JButton("Reset");
resetBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
resetIconLabel();
}
});
btnPanel.add(resetBtn, BorderLayout.WEST);
}
private void resetIconLabel() {
this.remove(iconPanel);
this.repaint();
this.revalidate();
setIconPanelAndComp();
}
private void setIconPanelAndComp() {
iconPanel = new JPanel(new BorderLayout());
iconPanel.setBackground(Color.YELLOW);
iconPanel.setPreferredSize(new Dimension(295, 580));
this.add(iconPanel, BorderLayout.SOUTH);
}
}
"the problem is when I push button "reset" I delete iconPanel and add it again it moves slightly to right on its own."
The reason this happens is because a JPanel has a FlowLayout by default. You're trying add to a BorderLayout position that is non-existent.
this.add(iconPanel, BorderLayout.SOUTH);
The FlowLayout has default gaps on the edges, so when you set the size of the frame, those gaps aren't respected. To over come this, it is also preferable to pack() the frame, instead of setSize()
The reason BorderLayout works (doesn't shift) is because preferred sizes aren't respected.
If you set the layout in the constructor to this.setLayout(new BorderLayout()); You won't have the shift.
public MainScreen() {
JPanel mainPanel = new JPanel(new BorderLayout());
this.setLayout(new BorderLayout()); <----
setBtnPanelAndComp();
setIconPanelAndComp();
add(mainPanel);
}
Notes
You should setVisible() after adding components. That's why your frame jumps when you first open it. You are setting the frame visible, then moving it around with the location, and adding components.
I have a text area, whenever the scroll bar is scrolled, I want to call a method. On what event I should call the method? I tried:
private void jScrollPane1MouseReleased(java.awt.event.MouseEvent evt) {
//execute();
System.out.println("Scroller Moved");
}
You want to use the AdjustmentListener on the JScrollBar (choose the one you want to listen for movement on). Here's an example of listening on the vertical bar.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TempProject extends JPanel{
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(300, 2000));
JScrollPane pane = new JScrollPane(panel);
pane.setPreferredSize(new Dimension(400, 300));
pane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener(){
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.println("Hi Mom!");
}});
frame.setContentPane(pane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
You should use a mouselistener event instead.
If you'd like to know more about it check it out here - http://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html
use the mouseclicked method then get the coordinates using getX() and getY(), then with an if test, test to see whether the coordinates are within the dimensions of your JScrollPane. Just remember to implement mouselister and add all inherited abstract methods :)
I'm trying to write custom JFrame and JPanel for my Java application. Currently, I just want to have a JPanel with a start button in the very middle of the screen. So, here's the code I have:
package gui;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class SubitizingFrame extends JFrame implements KeyListener {
public SubitizingFrame() {
super("Subitizing");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addKeyListener(this);
add(new LaunchPanel());
pack();
setVisible(true);
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_F5)
System.out.println("F5 pressed");
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
and here is my panel:
package gui;
import instructions.Settings;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class LaunchPanel extends JPanel implements ActionListener {
private JButton startButton;
public LaunchPanel() {
int width = Settings.getScreenSizeX(), height = Settings.getScreenSizeY();
setPreferredSize(new Dimension(width, height));
setLayout(null);
startButton = new JButton("Start");
startButton.setLocation((width/2) - (startButton.getWidth()/2), (height/2) - (startButton.getHeight()/2));
add(startButton);
}
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
But when the application launches, I don't see anything. Just a big gray screen.
Do not use a null layout. If you simply use the default layout manager of JPanel (i.e. FlowLayout), the JButton with "automagically" be placed in the center. Also, in order to place the JFrame in the middle of the screen, invoke setLocationRelativeTo(null).
Since it's hard to tell what you mean by "screen", this example shows how you center a JButton in a JPanel in a JFrame, that is then centered on the monitor.
public final class CenterComponentsDemo {
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI(){
final JFrame frame = new JFrame("Center Components Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ButtonPane());
frame.setSize(new Dimension(300, 100)); // Done for demo
//frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static class ButtonPane extends JPanel{
public ButtonPane(){
super();
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setBackground(Color.PINK);
final JButton button = new JButton("Start");
button.setAlignmentX(Component.CENTER_ALIGNMENT);
add(Box.createVerticalGlue());
add(button);
add(Box.createVerticalGlue());
}
}
}
Recommendations:
Avoid using null layout as this makes your app difficult to upgrade and maintain and makes it potentially very ugly or even non-usable on boxes with different OS's or screen resolutions.
If you have your JPanel use a GridBagLayout and add a single component to it without using GridBagConstraints, it will be placed in the center of the JPanel.
You almost never have to or should extend JFrame and only infrequently need to extend JPanel. Usually it's better to enhance your GUI classes through composition rather than inheritance.
Avoid having your "view" or gui classes implement your listener interfaces. This is OK for "toy" programs, but as soon as your application gains any appreciable size or complexity, this gets hard to maintain.
If you don't use any LayoutManager (which btw you probably should), then you'll need to set the size of the panel as well (along with its position).
Although we strongly recommend that you use layout managers, you can perform layout without them. By setting a container's layout property to null, you make the container use no layout manager. With this strategy, called absolute positioning, you must specify the size and position of every component within that container. One drawback of absolute positioning is that it does not adjust well when the top-level container is resized. It also does not adjust well to differences between users and systems, such as different font sizes and locales.
From: http://download.oracle.com/javase/tutorial/uiswing/layout/using.html
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class LaunchPanel extends JPanel {
private JButton startButton;
public LaunchPanel() {
int width = 200, height = 100;
setPreferredSize(new Dimension(width, height));
setLayout(new GridBagLayout());
startButton = new JButton("Start");
add(startButton);
setBorder( new LineBorder(Color.RED, 2));
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JOptionPane.showMessageDialog(null, new LaunchPanel());
}
});
}
}
addKeyListener(this);
Don't use KeyListeners. Swing was designed to be used with Key Bindings. Read the section from the Swing tutorial on How to Use Key Bindings for more information.
The tutorial also has a section on Using Layout Manager which you should read. You should not create GUI's with a null layout.