So I am attempting to use MVC(model, view, controller) to format my code and when attempting to add the view to the actual application I get an error that says that "java.lang.IllegalArgumentException: adding a window to a container
at java.awt.Container.checkNotAWindow
at java.awt.Container.addImpl
at java.awt.Container.add"
While I know what the error is I have no idea what I should do(not use MVC or find some sort of work-around) and would appreciate any help. Below I will have the code of the two classes.
Here is where the application is run from:
import javax.swing.*;
import java.awt.*;
/**
* Write a description of class FencingApplication here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class Application
{
public static void main(String[] args){
InputView view = new InputView();
InputModel model = new InputModel();
InputController ctrl = new InputController(view, model);
JFrame window = new JFrame("");
window.setSize(500, 600);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = new Container();
c.setLayout(new BorderLayout());
c.add( view, BorderLayout.CENTER );
JButton btList = new JButton( "List" );
JButton btPools = new JButton("Pools");
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 2));
buttonPanel.add(btList);
buttonPanel.add(btPools);
c.add( buttonPanel, BorderLayout.NORTH );
btList.addActionListener( ctrl );//where is the action performed method defined
btPools.addActionListener( ctrl );
window.setVisible( true );
}
}
And here is the view class:
import javax.swing.*; //Jframe/JButton/JLabel/etc
import java.awt.*; //container
import java.util.*;
/**
* Write a description of class InputView here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class InputView extends JFrame implements Observer
{
JLabel lbPaste = new JLabel("Please paste the seeding here.");
JTextArea taPaste = new JTextArea();
JButton btPools = new JButton("Pools");
JLabel lbNum = new JLabel("Please input the number of pools you want to have.");
JTextField tfNum = new JTextField();
public InputView()
{
JPanel numPanel = new JPanel();
numPanel.setLayout(new BorderLayout());
numPanel.add(lbNum, BorderLayout.NORTH);
numPanel.add(tfNum, BorderLayout.CENTER);
JPanel pastePanel = new JPanel();
pastePanel.setLayout(new BorderLayout());
pastePanel.add(lbPaste, BorderLayout.NORTH);
pastePanel.add(new JScrollPane(taPaste), BorderLayout.CENTER);
Container c = getContentPane();
c.setLayout(new GridLayout(2, 1));
c.add(numPanel);
c.add(pastePanel);
setTitle( "Pools" );
setSize( 350, 500 );//width then height
setVisible(true);
setResizable(false);
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
public void update( Observable obs, Object obj )
{
}
}
Thanks in advance for any help!
Container is the superclass of e.g. Panel, JPanel, Window, JFrame, etc.
JFrame is a window, so you shouldn't (and in fact can't, as you found out here) add it to another component. JFrame is a top-level container.
Actually, it's probably the case that you shouldn't be using new Container() directly at all. For example, if you want a panel, you should use JPanel. It's kind of hard for me to tell exactly what you intended, since adding a JFrame to another component is an error. I see you adding stuff to c but I don't see you doing anything else with it.
So:
JFrame is a window.
JFrame has a content pane, which is the panel inside the window. (The default content pane is actually a JPanel, even though getContentPane() returns it as a Container.)
If you want to put stuff in a JFrame, you add the stuff to the content pane.
You don't need to add a JFrame to anything, just create it with new and call setVisible(true).
Those are the basics of how to use a JFrame correctly.
I also highly recommend the Swing tutorials if you haven't read them. They are really pretty good.
Related
I have two components ready to add to frame:
class Lamina extends JPanel{
public Lamina(){
setLayout(new BorderLayout(50,50));
JPasswordField user_password = new JPasswordField();
add(user_password, BorderLayout.SOUTH);
}
}
class DOMHeader extends JPanel
{
public DOMHeader()
{
setLayout(new BorderLayout());
JLabel title = new JLabel("Sign in");
add(title, BorderLayout.NORTH);
}
}
This is my class UI:
public class UI {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Frame frame = new Frame();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.setTitle("Metin2");
}
}
Frame class:
class Frame extends JFrame {
public Frame() {
Toolkit screen = Toolkit.getDefaultToolkit();
Dimension screenSize = screen.getScreenSize();
int widthScreen = screenSize.width;
int heightScreen = screenSize.height;
setBounds((widthScreen/4/2),(heightScreen/4/2),(widthScreen/2/2), (heightScreen/2/2));
Image icon = screen.getImage("icon.jpeg");
setIconImage(icon);
/* Add to Components to frame*/
add(new DOMHeader());
add(new Lamina());
}
}
In my class Frame I'm adding the components shown earlier, but it "put on top of" a component another component.
According to the API:
public Component add(Component comp,int index)
Adds the specified component to this container at the given position
(index).
I run the main method:
As you can see it only show the Component DOMHeader class: add(new DOMHeader())
And what happened with add(new Lamina())
What number or Constant I should give it ?
This line:
class Frame extends JFrame {
is incorrect for the following reasons:
It's confusing because of AWT Frame class
It extends JFrame but you never change the behavior of the JFrame later, so no need to extend JFrame but create it inside of class
Now, we must head to JFrame class in which says:
The default content pane will have a BorderLayout manager set on it.
Now, if we go to the visual guide for layout managers in the BorderLayout section we can see the following image:
Which shows us that we can only add our components to 5 locations:
PAGE_START (or NORTH)
LINE_START (or WEST)
CENTER
LINE_END (or EAST)
PAGE_END (or SOUTH)
To answer your question:
According to the API:
public Component add(Component comp,int index)
Adds the specified component to this container at the given position (index).
What number or Constant I should give it ?
Well you need to add it as follows:
JFrame frame = new JFrame("Write your title here"); //Follow first advice
frame.add(new DOMHeader(), BorderLayout.NORTH); //These are the constants.
frame.add(new Lamina(), BorderLayout.SOUTH);
You confused yourself by adding the items in their locations in their own JPanels not on the JFrame itself.
Side note: Why are you doing these weird calculations?
setBounds((widthScreen/4/2),(heightScreen/4/2),(widthScreen/2/2), (heightScreen/2/2));
Wouldn't it be clearer if you called: widthScreen / 8?
As per #camickr comment:
There is no need for the DOMHeader and Lamina classes. You don't need to extend JPanel just to add a component to the frame. The "content pane" of a JFrame is a JPanel, so you can just add the label and text field to the frame as shown above.
You can also have your code improved in this way:
JFrame frame = new JFrame("Your title here");
JLabel title = new JLabel("Sign in");
JPasswordField userPassword = new JPasswordField(); //changed variable name to userPassword instead of user_password to follow Java naming conventions
frame.add(title, BorderLayout.NORTH);
frame.add(userPassword, BorderLayout.SOUTH);
frame.setVisible(true); //This line should be the last one or you'll find yourself with strange "bugs" when your application starts until you move it or resize it
No need to create a whole new JPanel for each component.
JScrollPane works perfectly when I give it a JPanel and then add the JScrollPane directly on to a JFrame with frame.getContentPane.add(). However, it doesn't work when I add the JScrollPane to a JPanel and then add the JPanel to the JFrame. I need to use the second method because I'm going to add multiple things inside the JPanel and JFrame and I need to keep it organized. Here is my code.
import java.awt.*;
import javax.swing.*;
public class Main {
/**
* #param inpanel asks if the JScrollPane should
* be inside of a JPanel (so other things can also be added)
*/
public static void testScroll(boolean inpanel) {
JFrame f = new JFrame();
f.setLayout(new BorderLayout());
f.setResizable(true);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createLineBorder(Color.red));
//panel.setLayout(new BoxLayout(panel, 1));
panel.setLayout(new GridLayout(0,1));
for (int i = 0; i < 100; i++) {
JLabel l = new JLabel("hey"+i,SwingConstants.CENTER);
l.setBorder(BorderFactory.createLineBorder(Color.green));
l.setPreferredSize(new Dimension(200,200));
panel.add(l);
}
JScrollPane scrollPane = new JScrollPane(panel);
scrollPane.setBorder(BorderFactory.createLineBorder(Color.blue));
//**********THIS DOES NOT WORK HOW I WANT IT TO************
if(inpanel){
JPanel holder = new JPanel();
holder.add(scrollPane);
f.getContentPane().add(holder);
}
//************THIS DOES WORK HOW I WANT IT TO****************
else{
f.getContentPane().add(scrollPane);
}
f.pack();
f.setSize(500, 500);
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
f.setVisible(true);
JScrollBar bar = scrollPane.getVerticalScrollBar();
bar.setValue(bar.getMaximum());
bar.setUnitIncrement(50);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
testScroll(false); //OR TRUE
}
};
SwingUtilities.invokeLater(r);
}
}
In the main method, if I pass false, it works like I mentioned before, but when I pass true it shows up without a scroll bar.
Picture when passing false
Picture when passing true
I need a way to add the JScrollPane to a JPanel and still have it work.
Thanks in advance!
Your problem is the holder JPanel's layout. By default it is FlowLayout which will not re-size its child components when need be. Make it a BorderLayout instead, and your scrollpane will resize when needed. If you need something more complex, check out the layout manager tutorials.
I want to implement a Scrollbar onto my Tab. However nothing is showing and there are no exceptions.
I think I need a:
scrollPane.setViewportView(scrollPanel);
But it didn't work as well.
I am wondering when adding a Jscrollpane onto a JTab how do you set it visible without using an explicit frame. If I use a frame and add it on the frame it creates a new window.
However how I got this program the Frame looks built I assume and this complicates everything.
import java.awt.*;
import javax.swing.*;
public class Test extends JFrame {
private JTabbedPane tabbedPane;
private JPanel panel; // Page where I want JScrollPane intisialized
public Test()
{
setTitle( "Program" );
setSize( 400, 200 ); // I want the JScrollPane to extend to 400 vertically
JPanel topPanel = new JPanel();
topPanel.setLayout( new BorderLayout() );
getContentPane().add( topPanel );
// Create the tab pages
createPage1();
tabbedPane = new JTabbedPane();
tabbedPane.addTab( "Welcome", panel );
topPanel.add( tabbedPane, BorderLayout.CENTER );
}
public void createPage1()
{
panel = new JPanel();
panel.setLayout( null ); // sets layout to null
////////////////////////
JPanel scrollPanel = new JPanel();
scrollPanel.setLayout(null);
scrollPanel.setPreferredSize(new Dimension(400,400));
///////////////////////
panel.add(scrollPanel);
scrollPanel.setVisible (true);
}
public static void main( String args[] )
{
// Create an instance of the test application
Test mainFrame = new Test();
mainFrame.setVisible( true );
}
}
If you have any questions don't hesitate to ask.
What you want is to use a JScrollPane. Change the createPage1() method to something like this:
public void createPage1()
{
panel = new JPanel();
panel.setLayout( new BorderLayout() );
////////////////////////
JScrollPane scrollPanel = new JScrollPane();
scrollPanel.setViewportView(new JLabel("hellossssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"));
scrollPanel.setPreferredSize(new Dimension(400,400));
///////////////////////
panel.add(scrollPanel,BorderLayout.CENTER);
}
And you will see a scrollbar. Note this change encompasses four things:
replace the null layout call with a BorderLayout
make a JScrollPane instead of a JPanel
add something to the pane for demo purposes
remove the unnecessary setVisible(true) call.
I want to make an object I can add to my java swing application.
The object when instantiated would contain an image and 2 labels - is there a way to do this using java swing?
If there is - can you point me at an example.
I.e i want
Myobj icon = new MyObj(pic, label , label);
window.addComponent(icon);
Cheers
Andy
Create a class MyObj and let it extend JPanel. In the constructor of MyObj you call setLayout(new BorderLayout()) or whatever layout you prefer. Then do for instance add(pic, BorderLayout.NORTH); add(label1, BorderLayout.WEST); add(label2, BorderLayout.EAST);.
Then you should be able to do window.add(new MyObj(pic, label1, label2)).
import java.awt.*;
class MyObj extends JPanel {
public MyComponent(ImageIcon pic, String label1, String label2) {
setLayout(new BorderLayout());
add(new JLabel(label1), BorderLayout.NORTH);
add(new JLabel(pic), BorderLayout.CENTER);
add(new JLabel(label2), BorderLayout.SOUTH);
}
}
public class FrameTest {
public static void main(String[] args) {
JFrame jf = new JFrame("Demo");
jf.add(new MyObj(new ImageIcon("duke.jpg"), "Label 1", "Label 2"));
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.pack();
jf.setVisible(true);
}
}
Produces
This would typically be done by sublcassing JPanel and, in the constructor creating 3 labels (1 for the image) and adding them to the panel using a suitable layout manager.
Something like this ?
image with two labels http://img297.imageshack.us/img297/5223/capturadepantalla201005i.png
I created a subclass of JPanel and in its constructor I layout the components so it can be used exactly as you thought:
ImageAndLabels demo = new ImageAndLabels("image.png", "labelOne", "labelTwo");
window.add( demo );
Here's the complete source code for this window. May help you to get started.
import javax.swing.*;
import java.awt.Font;
public class ImageAndLabels extends JPanel {
public static void main( String [] args ) {
JFrame frame = new JFrame("image and labels");
frame.add( new ImageAndLabels("./logo.png", // logo
"Grouping swing objects", // label 1
"<html>Hey.<br>" // label 2
+"I want to make an object I can add to my java swing application.<br>"
+"The object when instantiated would contain an image and 2 labels - "
+"is there a way to do this using java swing?</html>") );
frame.pack();
frame.setVisible( true );
}
public ImageAndLabels( String imageURL, String textOne, String textTwo ) {
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add( new JLabel( new ImageIcon(imageURL )));
add( new JLabel( textOne ){{
setFont( new Font("Arial", Font.BOLD, 20));
}});
add( new JLabel( textTwo ));
}
}
You can add multiple Swing components to some container component - usually JPanel:
JPanel panel = new JPanel(new SomeLayoutYouLike());
panel.add(..);
panel.add(..);
Read the section from the Swing tutorial on Using Layout Managers. Use the appropriate layout manager to layout the components as you wish. Then add the compnents to a JPanel.
well, the main point of swing is to avoid instantiate your objects with parameters...
for example: (rather not do that unless this vars are imperative to the creation of the object)
MyFrame(Object o1, Object o2...)
for serialization purposes, you would rather use an empty constructor, and to set the external values form out side of the frame(in this case), this way you would never get things mixed up... and avoid much NullPointerException debugging, later on if you would use serialization.
if you want to design components, you should use NetBeans, very simple, very user friendly, allows you to align and locate you labels, as for the ImagePanel.. I had one but I converted it to a scaling image panel.. with scaled layers over it.
If you need, I'll post it here.
Hope this helps,
Adam.
I want to maximize a JPanel inside a JFrame when the user clicks a button.What is the best way to achieve this.The view and the data model should be in sync in both the panels,that is the panel which in the JFrame and the maximized one.Please suggest me some solution.
my requirement is: i have a JFrame with 4 JPanels named as
JPanelA,JPanelB,JPanelC,JPanelD
Here the JPanelD contains a JList and
a button below it say "MAXIMIZE
PANEL" button . JList has a JTree
with in it . Sometimes the JList may
have huge set of data and it is not
visible to the user clearly.
So he need to maximize this JPanelD alone to see the contents of the JList clearly.For that he clicks "MAXIMIZE PANEL" button.After the click action ,the JPanelD in the JFrame remains there,also a new JPanel with the same JList data(ie.,the replica of the JPanelD say JPanelDMaximized)should be popped up.This is what i want to do ..
Of course you could do this yourself, but you should really look at JInternalFrame and consider using that for your panel. It will save a bunch of headache.
Edit: Sun's tutorial should get you what you need.
Follow-up to your clarification of the problem:
Take my code, and remove:
maximizedFrame.setUndecorated( true );
and size the frame bigger before you make it visible. That should satisfy the maximize-like behaviour you need.
Your other problem is that you cannot add JPanelD to the two JFrames. The pop-up frame must have its own unique JPanel object (let's call it JPanelE). So you need to:
Initialize and lay out JPanelE like you do JPanelD. That means giving JPanelE its own JList (and JTree, and so on).
Share the ListModel from JPanelD's JList with JPanelE's JList, and so on. The feasibility and details of executing this successfully depends on the specifics of your implementation, and is beyond the scope of your original problem.
Create a JWindow (or an undecorated JFrame) with a JPanel. Leave the JWindow invisible, initially. (The wiring of this new JPanel to the same data model used by the original JPanel is left as an exercise.)
When your maximize-panel button's ActionListener executes, it must:
2.1. Update the (invisible) JWindow's location and size to match the (visible) JFrame's.
2.2. Make your JFrame invisible.
2.3. Make your JWindow visible.
When your unmaximize-panel button's ActionListener executes, it must:
3.1. Update the (invisible) JFrame's location and size to match the (visible) JWindow's.
3.2. Make your JWindow invisible.
3.3. Make your JFrame visible
Example:
package stackoverflow;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MaximizingPanelApp extends JFrame {
private JPanel framePanel;
private JPanel windowPanel;
private JFrame maximizedFrame;
public static void main(String[] args) {
JFrame appFrame = new MaximizingPanelApp();
appFrame.setVisible( true );
}
public MaximizingPanelApp() throws HeadlessException {
super( "Application" );
setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
initialize();
}
private void initialize() {
// JFrame
{
Container container = getContentPane();
container.setLayout( new BorderLayout() );
framePanel = new JPanel();
framePanel.setBackground( Color.ORANGE );
container.add( framePanel, BorderLayout.CENTER );
JButton button = new JButton( new MaximizeAction() );
container.add( button, BorderLayout.SOUTH );
setSize( 400, 300 );
}
// JWindow
{
maximizedFrame = new JFrame();
Container container = maximizedFrame.getContentPane();
container.setLayout( new BorderLayout() );
windowPanel = new JPanel();
windowPanel.setBackground( Color.ORANGE );
container.add( windowPanel, BorderLayout.CENTER );
JButton button = new JButton( new UnMaximizeAction() );
container.add( button, BorderLayout.SOUTH );
maximizedFrame.setSize( getSize() );
maximizedFrame.setUndecorated( true );
}
}
private class MaximizeAction extends AbstractAction {
private MaximizeAction() {
super( "Maximize" );
}
public void actionPerformed(ActionEvent e) {
maximizedFrame.setSize( getSize() );
maximizedFrame.setLocation( getLocation() );
setVisible( false );
maximizedFrame.setVisible( true );
}
}
private class UnMaximizeAction extends AbstractAction {
private UnMaximizeAction() {
super( "Un-Maximize" );
}
public void actionPerformed(ActionEvent e) {
setLocation( maximizedFrame.getLocation() );
setSize( maximizedFrame.getSize() );
maximizedFrame.setVisible( false );
maximizedFrame.dispose();
setVisible( true );
}
}
}
This depends on the layout manager you use. If you add a JPanel to a JFrame using the default layout manager, and the JFrame only contains the JPanel and nothing else, you'll achieve what you describe.
Here's an example. The JPanel is green; notice how it resizes as you resize the JFrame.
import javax.swing.*;
import java.awt.*;
public class ScratchSpace {
public static void main(String[] args) {
JFrame frame = new JFrame("Stretchy panel demo");
final JPanel panel = new JPanel();
panel.setOpaque(true);
panel.setBackground(Color.GREEN);
panel.setPreferredSize(new Dimension(600, 400));
final JComponent contentPane = (JComponent) frame.getContentPane();
contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}