I can't figure out why this simple program I wrote gets an IndexOutOfBounds exception when trying to update the coordinates of the mouse when the mouse leaves the tracking area (the white JPanel). I thought that the check on line 38 would take care of it. Any suggestions? Thanks!
import java.awt.*;
import javax.swing.JFrame;
public class MainFrame extends JFrame {
private static final long serialVersionUID = 1L;
Label coorLabel;
Panel coorPanel, content;
public MainFrame(String s){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cont = getContentPane();
coorLabel = new Label("Mouse Coordinates: ");
coorPanel = new Panel();
coorPanel.setPreferredSize(new Dimension(400,400));
coorPanel.setBackground(Color.WHITE);
/**
content = new Panel();
content.add(coorPanel, BorderLayout.PAGE_START);
content.add(coorLabel, BorderLayout.PAGE_END);
**/
cont.add(coorPanel, BorderLayout.PAGE_START);
cont.add(coorLabel, BorderLayout.PAGE_END);
pack();
setVisible(true);
}
public void updateCoor(){
if(coorPanel.getMousePosition()!=null){
coorLabel.setText("Mouse Coordinates: "+getMousePosition().x+", "+getMousePosition().y);
coorLabel.repaint();
}
}
public static void main(String[]args){
MainFrame frame = new MainFrame("Coor App");
while(true){
frame.updateCoor();
}
}
}
Take a look at Concurrency in Swing tutorial. You are completely hogging initial
thread with a while(true) loop and updating user interface outside of Event Dispatch Thread.
See Introduction to Event Listeners to get familiar with Swing event model and How to Write a Mouse-Motion Listener in particular for mouse motion listener example.
Here is what you should do:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.*;
public class Stack extends JFrame implements MouseMotionListener{
int x;
int y;
JPanel p = new JPanel();
JPanel detectPanel = new JPanel();
JTextField t = new JTextField(10);
JLabel l = new JLabel("Position's inside of bordered panel: ");
public Stack(){
setLayout(new BorderLayout());
t.setEditable(false);
p.add(l);
p.add(t);
detectPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
add(p,BorderLayout.NORTH);
add(detectPanel,BorderLayout.CENTER);
detectPanel.addMouseMotionListener(this);
}
public static void main(String[] a){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
Stack s = new Stack();
s.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
s.setLocationByPlatform(true);
s.setPreferredSize(new Dimension(640,480));
s.pack();
s.setVisible(true);
}
});
}
public void mouseDragged(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
x= e.getX();
y= e.getY();
t.setText(x+", "+y);
}
}
You check to see if coorPanel.getMousePosition() is not null, but then reference (this.)getMouseLocation(); try changing that to just say getMousePosition in the check, and add a print:
if( this.getMousePosition() != null ){
System.out.println(getMousePosition());
coorLabel.setText("Mouse Coordinates: "+getMousePosition().x+", "+getMousePosition().y);
coorLabel.repaint();
}
Related
I've been trying to figure out what's wrong with my code. I have to build a GUI and there are no errors. The program builds successfully, but no GUI pops up. So in the main method, I commented out the GUI programming and added a simple System.out.println("hello"); but it does the same thing, i.e., it builds successfully, but does not print anything. Can someone please tell me what's wrong? Thanks!
/*
* To change this license header, choose License Headers in Project
Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package gui;
import java.awt.*;
import javax.swing.*;
import java.awt.Event.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class GUI extends JFrame {
GridLayout g = new GridLayout(5, 2);
private JLabel baseIn = new JLabel("Base Input");
private JLabel heightIn = new JLabel("Height Input");
private JTextField base = new JTextField();
private JTextField height = new JTextField();
private JTextField area = new JTextField();
private JButton calc = new JButton("Calculate Area");
public GUI() {
super("Triangle Area Calculator");
setSize(500, 300);
setLayout(g);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(baseIn);
add(heightIn);
add(base);
add(height);
add(area);
add(calc);
area.setEditable(false);
calc.addActionListener((ActionListener) this);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
try {
double bInput = Integer.valueOf(base.getText());
double hInput = Integer.valueOf(height.getText());
double aOutput = 0.5*bInput*hInput;
area.setText("Area of your triangle is: " + aOutput);
} catch (NumberFormatException n) {
System.out.println(n.getMessage());
}
}
public static void main(String[] args) {
/*JFrame frame = new JFrame();
GUI one = new GUI();
frame.getContentPane().add(one);
frame.pack();
frame.setVisible(true);*/
System.out.println("hello world");
}
}
First, going back to the basic code...
public class GUI extends JFrame {
//...
public static void main(String[] args) {
JFrame frame = new JFrame();
GUI one = new GUI();
frame.getContentPane().add(one);
frame.pack();
frame.setVisible(true);
}
}
Will fail, because you can't add a window based component to a window. As a general rule of thumb, you should avoid overriding JFrame (and other top level containers) directly and favour something less complex, like JPanel
public class GUI extends JPanel {
//...
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new GUI());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Next...
calc.addActionListener((ActionListener) this);
The fact that you need to perform a cast in order to get the code to work is a clear sign that something else is wrong and this is likely to cause a runtime error and crash your program. Perhaps you should start by having a read of How to write a Action Listener and How to Use Buttons, Check Boxes, and Radio Buttons to get a better understanding of how the API works
This is further supported by making use of the #Override annotation, which should be used when ever you "think" you're implementing or overriding existing functionality...
#Override
public void actionPerformed(ActionEvent e) {
//...
}
This would then fail to compile, as you're not implementing any existing functionality. This functionality is described by the ActionListener interface which you are not implementing.
While you could implement this interface directly, I prefer to avoid doing so, as it exposes functionality that other classes shouldn't have access to and you run the risk of building a "god" method, which is never a good idea.
Instead, I prefer to make use of Java's Anonymous Classes, which provides a much better means for isolating functionality to single use case, for example...
calc.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
double bInput = Integer.valueOf(base.getText());
double hInput = Integer.valueOf(height.getText());
double aOutput = 0.5 * bInput * hInput;
area.setText("Area of your triangle is: " + aOutput);
} catch (NumberFormatException n) {
System.out.println(n.getMessage());
}
}
});
Runnable Example
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class GUI extends JPanel {
GridLayout g = new GridLayout(5, 2);
private JLabel baseIn = new JLabel("Base Input");
private JLabel heightIn = new JLabel("Height Input");
private JTextField base = new JTextField();
private JTextField height = new JTextField();
private JTextField area = new JTextField();
private JButton calc = new JButton("Calculate Area");
public GUI() {
setLayout(g);
add(baseIn);
add(heightIn);
add(base);
add(height);
add(area);
add(calc);
area.setEditable(false);
calc.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
double bInput = Integer.valueOf(base.getText());
double hInput = Integer.valueOf(height.getText());
double aOutput = 0.5 * bInput * hInput;
area.setText("Area of your triangle is: " + aOutput);
} catch (NumberFormatException n) {
System.out.println(n.getMessage());
}
}
});
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new GUI());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Netbeans properties...
Now, if all that still fails to net you a result, you need to make sure that your GUI class is configured as the "Main class".
Start by right clicking the Netbeans project node and select "Properties" (it's at the bottom).
From the "Projects Properties", select "Run" from the "Build" options down the left side.
Make sure that your GUI class is marked as the "Main Class", use "Browse" to find it if it's not
Try this
calc.addActionListener(new OptionButtonHandler());
I added one optionButtonHandler class which implements ActionListener. I checked on my IDE and I was able to get the area of the triangle.
private class OptionButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
try {
double bInput = Integer.valueOf(base.getText());
double hInput = Integer.valueOf(height.getText());
double aOutput = 0.5 * bInput * hInput;
area.setText("Area of your triangle is: " + aOutput);
} catch (NumberFormatException n) {
System.out.println(n.getMessage());
}
}
}
In your case, GUI is not an ActionListener, so that will fail.
Can you right click on the file with the main method in Netbeans, you should see the run option there, select it. This would allow you set your main method. After this, subsequent clicks on the Green play Button should work.
You do not need to cast your Frame class to an ActionListener. Instead, make it implement the ActionListener interface and your code for the button action should work. But in future, its better to add logic to detect what component triggered the action.
I don't know, but how can you write this :
calc.addActionListener((ActionListener) this);
Your object (this) is a JFrame, you should add 'implements ActionListener' first, or create a separate implementation ...
Next error, you do :
GUI one = new GUI();
frame.getContentPane().add(one);
GUI extends JFrame, its a JFrame, you can't add a JFrame in another one !
I tested with add of 'implements ActionListener' and it runs, but some errors remains ;)
Copy/paste needs wisdom, hum ^^
EDIT
this code is not perfect (and very ugly) but it works for your example :
package com.mead.helmet.core;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class GUI extends JPanel implements ActionListener {
public static void main(final String[] args) {
JFrame frame = new JFrame("Triangle Area Calculator");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
GUI one = new GUI();
frame.getContentPane().add(one);
frame.pack();
frame.setVisible(true);
System.out.println("hello world");
}
GridLayout g = new GridLayout(5, 2);
private final JLabel baseIn = new JLabel("Base Input");
private final JLabel heightIn = new JLabel("Height Input");
private final JTextField base = new JTextField();
private final JTextField height = new JTextField();
private final JTextField area = new JTextField();
private final JButton calc = new JButton("Calculate Area");
public GUI() {
super();
setSize(500, 300);
setLayout(g);
add(baseIn);
add(heightIn);
add(base);
add(height);
add(area);
add(calc);
area.setEditable(false);
calc.addActionListener((ActionListener) this);
setVisible(true);
}
/**
*
* #param event
*/
#Override
public void actionPerformed(final ActionEvent e) {
try {
double bInput = Integer.valueOf(base.getText());
double hInput = Integer.valueOf(height.getText());
double aOutput = 0.5 * bInput * hInput;
area.setText("Area of your triangle is: " + aOutput);
} catch (NumberFormatException n) {
System.out.println(n.getMessage());
}
}
}
I have a quick question.
I'm getting a little bit of experience with Swing and the easiest way to do this was to draw up a reasonably big GUI.
As part of the GUI, I want to have Forward and Back Buttons. The Approach I'm trying to take is to implement methods that will push the current JPanel to a stack and retrieve the previous value (Be that in a forwards or reverse direction (hence 2 stacks)). I can't get it to work though. Perhaps I'm going about it completely the wrong way or maybe a stack can't be used int the way I'm using it. In either case, it's really bugging me. I imagine there are probably easier ways like a card layout but I think this approach should work and that's what's so annoying.
It may be worth noting that I'm using a JFrame "base class" and changing the central JPanel depending on the screen. The nav bar is constant as a part of the "base class" however
The code of this "base class":
public class Main_Frame extends JFrame{
static JPanel nav_bar_panel;
JButton home;
JButton back;
JButton forward;
JPanel currentPanel;
static Stack<JPanel> previousPanels;
static Stack<JPanel> forwardPanels;
public Main_Frame(){
super("DEMO");
setSize(800,600);
setLayout(new BorderLayout());
setVisible(true);
add(nav_bar(), BorderLayout.NORTH);
currentPanel = init_display();
add(currentPanel, BorderLayout.CENTER);
previousPanels = new Stack<JPanel>();
forwardPanels = new Stack<JPanel>();
}
private JPanel nav_bar(){
ButtonPressHandler handler = new ButtonPressHandler();
nav_bar_panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10));
back = new JButton("Back");
back.addActionListener(handler);
home = new JButton("Home");
home.addActionListener(handler);
forward = new JButton("Forward");
forward.addActionListener(handler);
nav_bar_panel.add(back);
nav_bar_panel.add(home);
nav_bar_panel.add(forward);
return nav_bar_panel;
}
private JPanel init_display(){
Home_Panel home_panel = new Home_Panel();
return home_panel;
}
public void change_display(JPanel myPanel){
invalidate();
remove(currentPanel);
previousPanels.push(currentPanel);
currentPanel = myPanel;
add(currentPanel);
validate();
}
public void previous_display(){
if(!previousPanels.empty()){
invalidate();
remove(currentPanel);
forwardPanels.push(currentPanel);
currentPanel = previousPanels.pop();
add(currentPanel);
validate();
}
}
public void forward_display(){
if(!forwardPanels.empty()){
invalidate();
remove(currentPanel);
previousPanels.push(currentPanel);
currentPanel = forwardPanels.pop();
add(currentPanel);
validate();
}
}
private class ButtonPressHandler implements ActionListener
{
public void actionPerformed( ActionEvent event )
{
if(event.getSource() == back){
previous_display();
System.out.print("You selected back");
} else if(event.getSource() == forward){
forward_display();
System.out.print("You selected forward");
}
} // end method actionPerformed
} // end private inner class TextFieldHandler
}
Here's an example using CardLayout.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/** #see http://stackoverflow.com/questions/5654926 */
public class CardPanel extends JPanel {
private static final Random random = new Random();
private static final JPanel cards = new JPanel(new CardLayout());
private final String name;
public CardPanel(String name) {
this.name = name;
this.setPreferredSize(new Dimension(320, 240));
this.setBackground(new Color(random.nextInt()));
this.add(new JLabel(name));
}
#Override
public String toString() {
return name;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
create();
}
});
}
private static void create() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int i = 1; i < 9; i++) {
CardPanel p = new CardPanel("Panel " + String.valueOf(i));
cards.add(p, p.toString());
}
JPanel control = new JPanel();
control.add(new JButton(new AbstractAction("\u22b2Prev") {
#Override
public void actionPerformed(ActionEvent e) {
CardLayout cl = (CardLayout) cards.getLayout();
cl.previous(cards);
}
}));
control.add(new JButton(new AbstractAction("Next\u22b3") {
#Override
public void actionPerformed(ActionEvent e) {
CardLayout cl = (CardLayout) cards.getLayout();
cl.next(cards);
}
}));
f.add(cards, BorderLayout.CENTER);
f.add(control, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
the idea of making whatever I get reusable is a good one. Pity Swing didn't have this functionality built in though
Check out Card Layout Actions which is may attempt at making the Card Layout a little easier to use for something like this.
The way I usually do it is as follows:
I've got a StepManager class (write it once, use it forever) which handles all logic related to the steps. It got methods like next(), previous(), reset(), isFirst() and isLast().
I've then got 'Next' and 'Previous' buttons with appropriate actions (or whatever you choose to use to listen for user interaction).
The code related to the 'Next' button calls stepManager.next() to retrieve the index for the next step. Then (when I've got the next step) I simply invoke (another method) showStep(int index) to display the actual step user interface corresponding to the current step index.
Each step is a separate JPanel (Step01, Step02, Step03...).
public void showStep(int index) {
ContentPanel.removeAll();
ContentPanel.setLayout(new BorderLayout());
switch (index) {
case 0:
ContentPanel.add(Step01, BorderLayout.CENTER);
break;
case 1:
ContentPanel.add(Step02, BorderLayout.CENTER);
break;
case 2:
ContentPanel.add(Step03, BorderLayout.CENTER);
break;
case 3:
ContentPanel.add(Step04, BorderLayout.CENTER);
}
ContentPanel.validate();
ContentPanel.repaint();
}
I have a JFrame, and whenever I switch from one JFrame using a JButton it starts out normally, but whenever I create a new instance of the first JFrame, the JButton is in an incorrect location and is the wrong size.
Example on startup
and when another one is created
Code:
public class Menu extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
public static int Number_of_Participants = 0;
protected JPanel window = new JPanel();
double p;
private JButton Participants;
private Rectangle rParticipants;
protected int Button_width = 240;
protected int Button_height = 48;
boolean running = false;
Thread thread;
JFrame frame = new JFrame();
public Menu() {
window.setBackground(Color.BLUE);
frame.setSize(new Dimension(800, 600));
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.getContentPane().add(window);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Image image = null;
try {
image = ImageIO.read(new File("res/BG.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
generateFiles();
drawButtons();
startMenu();
frame.repaint();
}
public void drawButtons() {
rParticipants = new Rectangle(520, 12, Button_width, Button_height);
Participants = new JButton("A");
Participants.setBounds(rParticipants);
window.add(Participants);
Participants.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.dispose();
new Participant(Number_of_Participants);
}
});
}
}
Participant.java extends Menu.java
int Participant_ID;
public Participant(int Participant_ID) {
super();
this.Participant_ID = Participant_ID;
}
makes a JButton that goes back to Menu.java
As mentioned in the comment, your problem is most likely related to the call to setVisible(true). This should always be the LAST call in the constructor. Particularly, it should only be called AFTER all components have been added to the frame.
Apart from that, from the code that you posted, it seems like you want to switch through a seqence of frames, starting with a "main" menu, and then going through one frame for each "Participant". This intention could already be considered as questionable, because closing and disposing a JFrame just in order to create a new one does not seem to be very elegant. Most likely, a more elegant solution would be possible with a CardLayout : http://docs.oracle.com/javase/tutorial/uiswing/layout/card.html
However, some general hints:
Create the GUI on the Event Dispatch Thread
Don't extend JFrame. Instead, create a JFrame and fill it as needed
Don't implement Runnable with your top level class
Obey the standardJavaNamingConventions!
Don't try to do manual layouts with setBounds
This code is still not "beautiful", but at least shows how the goal of switching through several frames might be achieved, taking into account these points
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MenuExample
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
JPanel mainMenuPanel = new MainMenuPanel();
createAndShowFrame(mainMenuPanel);
}
});
}
static void createAndShowFrame(JPanel panel)
{
JFrame frame = new JFrame();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(800, 600));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
static JButton createNextParticipantButton(
final JComponent container, final int nextID)
{
JButton nextParticipantButton = new JButton("New Participant");
nextParticipantButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
Window window =
SwingUtilities.getWindowAncestor(container);
window.dispose();
ParticipantPanel participantPanel =
new ParticipantPanel(nextID);
createAndShowFrame(participantPanel);
}
});
return nextParticipantButton;
}
}
class MainMenuPanel extends JPanel
{
public MainMenuPanel()
{
setBackground(Color.BLUE);
add(MenuExample.createNextParticipantButton(this, 0));
}
}
class ParticipantPanel extends JPanel
{
private final int participantID;
public ParticipantPanel(int participantID)
{
this.participantID = participantID;
add(new JLabel("Add the contents for participant "+participantID));
add(MenuExample.createNextParticipantButton(this, participantID+1));
}
}
JButton and JLabel disappears when adding custom background. I don't see any problems in my program, but maybe you guys find an solution! I think it's only a little thing I forgot, but I can't figure it out.
Here's the code:
GameWindow.java:
setContentPane(new StartImagePanel(RollrackLogo));
out.println("adding JLWelcome");
JLWelcome.setText("Welcome to Rollrack, " + namewindow.name);
add(JLWelcome);
JLWelcome.setVisible(true);
out.println("JLWelcome added");
out.println("adding JBRandom");
JBRandom.setText("Random");
add(JBRandom);
JBRandom.setVisible(true);
out.println("added JBRandom");
The background appears perfect, but not the JButton and JLabel!
Code to the StartImagePanel.java:
public class StartImagePanel extends JComponent{
private Image image;
public StartImagePanel(Image image) {
this.image = image;
}
#Override
protected void paintComponent(Graphics g) {
g.drawImage(image, 0, 0, null);
}
}
Your button and label are added to your GameWindow frame while they should be added to its contentPane, setContentPane(new StartImagePanel(RollrackLogo)); instead. That's why they are not showing, they are added to the frame.
Make a variable of the StartImagePanel and add the button and label to it and they should show up.
StartImagePanel contentPanel = new StartImagePanel(RollrackLogo);
setContentPane(contentPanel);
...
out.println("adding JLWelcome");
JLWelcome.setText("Welcome to Rollrack, " + namewindow.name);
contentPanel.add(JLWelcome);
JLWelcome.setVisible(true);
out.println("JLWelcome added");
out.println("adding JBRandom");
JBRandom.setText("Random");
contentPanel.add(JBRandom);
JBRandom.setVisible(true);
out.println("added JBRandom");
Answer dispute
The claims in the first paragraph are plain wrong. Here is source that proves it.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class AddToCustomContentPane {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
// the GUI as seen by the user (without frame)
JPanel gui = new JPanel(new FlowLayout());
gui.setBorder(new EmptyBorder(2, 3, 2, 3));
gui.setBackground(Color.RED);
JFrame f = new JFrame("Demo");
f.setContentPane(gui);
// Acid test. Can we add buttons direct to the frame?
f.add(new JButton("Button 1"));
f.add(new JButton("Button 2"));
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See http://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
Edit after the custom panel code was given
Here's a snippet that works to show both button and label on a black image background, I removed that was not needed (listeners).
public static void main(String[] v) {
class StartImagePanel extends JPanel {
private Image image;
public StartImagePanel(Image image) {
this.image = image;
}
#Override
protected void paintComponent(Graphics g) {
g.drawImage(image, 0, 0, null);
}
}
class GameWindow extends JFrame{
public GameWindow() {
BufferedImage RollrackLogo;
RollrackLogo = new BufferedImage(400,200,BufferedImage.TYPE_INT_RGB);
final JButton JBRandom = new JButton();
final JLabel JLWelcome = new JLabel();
setDefaultCloseOperation(EXIT_ON_CLOSE);
StartImagePanel panel = new StartImagePanel(RollrackLogo);
setContentPane(panel);
setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
JLWelcome.setText("Welcome to Rollrack");
panel.add(JLWelcome);
JLWelcome.setVisible(true);
JBRandom.setText("Random");
panel.add(JBRandom);
JBRandom.setVisible(true);
}
}
GameWindow window = new GameWindow();
window.pack();
window.setVisible(true);
}
I rather use an instance of a JFrame, instead of extending it, as #Andrew Thompson suggested in another question.
However, if you're extending it, it might be a good practice to call super() in the constructor.
Additionally, we may need to know what is going on in your StartImagePanel.
It seems, to me, to be the problem.
Ensure both your GameWindow and StartImagePanel extend properly their superclasses (call super();).
Ensure your StartImagePanel has a proper Layout.
Add your components before you set your frame visible. This also means you won't need JLWelcome.setVisible(true);.
Ensure that your code is executed in the EDT (Event-Dispatch Thread).
Example:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class GameWindow extends JFrame{
BufferedImage rollrackLogo;
JButton jbRandom;
JLabel jlWelcome;
public GameWindow() {
super();
jbRandom = new JButton("Random");
jlWelcome = new JLabel("Welcome to Rollrack, " +
namewindow.name);
rollrackLogo = new BufferedImage(400, 200,
BufferedImage.TYPE_INT_RGB);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setContentPane(new StartImagePanel(rollrackLogo));
// Add your components.
add(jlWelcome);
add(jbRandom);
addKeyListener(new KeyListener() {
#SuppressWarnings("static-access")
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == e.VK_ESCAPE){
System.exit(7);
}
}
#Override
public void keyReleased(KeyEvent arg0) {}
#Override
public void keyTyped(KeyEvent arg0) {}
});
// Pack, or otherwise set fullscreen.
pack();
// Now, set frame visible.
setVisible(true);
}
}
Edit: Now that you've posted the code for your StartImagePanel, I see that you're extending JComponent. Follow my previous advice, (call super), set a Layout, and extend JPanel instead.
Contents
Overview
Example Code
Screenshots of Problem
1. Overview of problem
So I'm writing a GUI for a complicated program I'm developing, and I get tired of trying to get components to scale correctly when the window is resized.
At first I was using several layouts inside the jframe, and each jpanel to try and place the components correctly and scale them appropriately. Naturally, I got fed up with them, and I started trying to scale and set the x,y positions of the components dynamically (it's so much easier :D).
Basically I'm trying to divide the screen into three sections left margin (JSplitPane), center (JTabbedPane), and right margin (JSplitPane). I don't think the internal components matter at this point. The main problem is the right JSplitPane scales over the whole window despite my using setBounds() to place the x,y over on the right and set the size to 21% of the total width. It seems to interact weird with the other panels.
2. Example Code
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.Dimension;
#SuppressWarnings("deprecation")
public class test extends JFrame implements WindowListener {
/* Constants =========================================================================*/
private final double LEFT_SIZE = .21;
private final double CENTER_SIZE = .58;
private final double RIGHT_SIZE = .21;
private final int TOP_PADDING = 50;
private final int LEFT_PADDING = 4;
private final int RIGHT_PADDING = 4;
private final int BOTTOM_PADDING = 4;
private final int MIN_WIDTH = 640;
private final int MIN_HEIGHT = 480;
public static final String INIT_TITLE = "TestFrame v0.01";
/* End Constants =====================================================================*/
/* Instance Variables ================================================================*/
private int contentWidth;
private int contentHeight;
/* End Instance Variables ============================================================*/
/* Objects ===========================================================================*/
public static test window;
/* Begin Frame Design =========================================================== */
private JSplitPane left;
private JButton button1; private JButton button2;
private JTabbedPane center;
private JPanel panel1; private JPanel panel2;
private JSplitPane right;
private JButton button3; private JButton button4;
/* End Frame Design ============================================================= */
/* End Objects ====================================================================== */
/** Initializes and Places all GUI elements **/
public test ( String windowName ) {
super(windowName); //call parent constructor
this.addWindowListener(this); //adds window event functionality such as close
this.setExtendedState(this.getExtendedState() | JFrame.MAXIMIZED_BOTH); //Starts program maximized
this.setMinimumSize(new Dimension(MIN_WIDTH,MIN_HEIGHT));
this.setVisible(true);
this.setMaximumSize(this.getSize());
/* Begin Init JFrame this ------------------------------------------------------------ */
button1 = new JButton("button1");
button2 = new JButton("button2");
left = new JSplitPane(JSplitPane.VERTICAL_SPLIT, button1, button2);
left.setResizeWeight(1);
button3 = new JButton("button3");
button4 = new JButton("button4");
right = new JSplitPane(JSplitPane.VERTICAL_SPLIT, button3, button4);
right.setResizeWeight(.25);
panel1 = new JPanel();
panel2 = new JPanel();
center = new JTabbedPane();
center.addTab("Panel1", panel1);
center.addTab("Panel2", panel2);
this.add(left);
this.add(center);
this.add(right);
this.addComponentListener(new ComponentListener() {
#Override
public void componentResized (ComponentEvent e) {
window.contentWidth = window.getWidth() - window.LEFT_PADDING - window.RIGHT_PADDING;
window.contentHeight = window.getHeight() - window.TOP_PADDING - window.BOTTOM_PADDING;
window.left.setBounds ( 0, 0, (int)(window.contentWidth * window.LEFT_SIZE), window.contentHeight);
window.center.setBounds ( window.left.getWidth(), 0, (int)(window.contentWidth * window.CENTER_SIZE), window.contentHeight);
window.panel1.setBounds ( 0, 0, (int)(window.contentWidth * window.CENTER_SIZE), window.contentHeight);
window.panel2.setBounds ( 0, 0, (int)(window.contentWidth * window.CENTER_SIZE), window.contentHeight);
window.right.setBounds ( window.left.getWidth() + window.center.getWidth(), 0, (int)(window.contentWidth * window.RIGHT_SIZE), window.contentHeight);
}
public void componentHidden (ComponentEvent e) {}
public void componentMoved (ComponentEvent e) {}
public void componentShown (ComponentEvent e) {}
});
/* End Init JFrame this -------------------------------------------------------------- */
}
// window event abstracts
#Override
public void windowClosing (WindowEvent event) { window.dispose(); System.exit(0); }
public void windowClosed (WindowEvent event) {}
public void windowDeiconified (WindowEvent event) {}
public void windowIconified (WindowEvent event) {}
public void windowActivated (WindowEvent event) {}
public void windowDeactivated (WindowEvent event) {}
public void windowOpened (WindowEvent event) {}
public static void main(String[] args){
window = new test(INIT_TITLE);
window.setVisible(true);
}
}
3. Screenshots
I don't think the internal components matter at this point.
As discussed in Should I avoid the use of set[Preferred|Maximum|Minimum]Size methods in Java Swing?, nothing could be further from the truth. Correct use of layouts relies on a component's preferred size. That size is carefully calculated based on the contents. Second guessing, as shown in your example, is doomed to fail.
Instead, add components and pack() the frame. In the example below, the center panel returns an arbitrary result to show how pack() does its work.
Addendum: Two additional points helpfully adduced by #mKorbel:
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
See also this example that shows how to use setDividerLocation() in invokeLater().
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import java.awt.Dimension;
import java.awt.EventQueue;
public class Test extends JFrame {
public static final String INIT_TITLE = "TestFrame v0.02";
public static Test window;
private JSplitPane left;
private JTabbedPane center;
private JSplitPane right;
public Test(String windowName) {
super(windowName);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
left = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
new JButton("button1"), new JButton("button2"));
left.setResizeWeight(0.5);
right = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
new JButton("button3"), new JButton("button4"));
right.setResizeWeight(0.5);
center = new JTabbedPane();
center.addTab("Panel1", new MyPanel());
center.addTab("Panel2", new MyPanel());
this.add(left, BorderLayout.WEST);
this.add(center, BorderLayout.CENTER);
this.add(right, BorderLayout.EAST);
this.pack();
this.setLocationByPlatform(true);
this.setVisible(true);
}
private static class MyPanel extends JPanel {
private Dimension d = new Dimension(320, 240);
#Override
public Dimension getPreferredSize() {
return d;
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
window = new Test(INIT_TITLE);
window.setVisible(true);
}
});
}
}