My issue is that I have two objects that have a "public void paint(Graphics pane)" class, and I want to add them both to a frame. I have the code in place to do so, but only the last die I add actually shows up. Any solutions / additional info you need to see?
The Add code:
public void addDice(Die userDie, Die computerDie) {
gameFrame.add(userDie);
gameFrame.add(computerDie);
}
And yes, the method is called and receives the two dice objects, and the object's class does extend "Component".
gameFrame is a Frame made with
Frame gameFrame = new Frame();
This is an AWT application, not Swing.
Thanks!
Is this a Swing application (JFrame) or an AWT application? Or something else? You may need to change your "Frame's" layout to GridLayout so that it can show both components. You will want to read up on use of the layout managers here
Related
So I'm having a class called Menu which extends JLabel and has a constructor which adds 3 JButtons to itself.
public Menu() {
this.add(jbutton1);
this.add(jbutton2);
this.add(jbutton3);
}
I have another class called GUI which extends JFrame and adds the JLabel to its contentPane.
public GUI() {
Menu menu = new Menu();
getContentPane().add(menu);
setSize(300,200);
setVisible(true);
}
The main method of GUI just looks like this:
public static void main(String[] args) {
GUI gui = new GUI();
}
So what I wanted is a JFrame with 3 JButtons in it (going to do more stuff later one). Instead I just got a blank JFrame. Why don't I see the JLabel with the 3 JButtons in it I added?
You're forgetting layout managers which are key to controlling how components are added to and sized by containers. JLabels are not used to being used as a container and holding other components and so come by default with a null layout -- no layout at all, making you the programmer responsible for sizing and positioning any added component.
Solutions:
Set your JButton's sizes and positions yourself -- a very bad solution since it leads to GUI's that only work well on one platform and that are difficult to debug and maintain
Or give the container (here the JLabel) a decent layout manager.
Or use another container, such as a JPanel, one that already has a layout manager, as the contentPanel. There are ways of getting a JPanel to display an image including overriding its paintComponent method.
You can find the layout manager tutorial here: Layout Manager Tutorial, and you can find links to the Swing tutorials and to other Swing resources here: Swing Info.
Here's my JPanel. The first button is always visible, but the secound is visible only when you place a cursour on it. Where the problem can be?
P.S. Please use simple english, if u can, because I don't speak english well
public class GamePanel extends JPanel implements KeyListener{
GamePanel(){
setLayout(null);
}
public void paint(Graphics g){
JButton buttonShip1 = new JButton();
buttonShip1.setLocation(10, 45);
buttonShip1.setSize(40, 40);
buttonShip1.setVisible(true);
add(buttonShip1);
JButton buttonShip2 = new JButton();
buttonShip2.setLocation(110, 145);
buttonShip2.setSize(440, 440);
buttonShip2.setVisible(true);
add(buttonShip2);
}
}
If you want to avoid problems and learn Java Swing correctly, go check out their tutorials here.
There are too many problems to discuss here, so I'll try to keep it simple.
You're using a null layout. null layouts are avoided for the most part because there is usually a layout that does exactly what you want. It takes some time to get it working, but there are some defaults in this tutorial that are fairly simple to use. There are some nice pictures there that show you what you can do with each layout, too. If you use a layout manager, you generally don't need to use setLocation, setSize or setVisible on most components like JButtons.
You're calling the paint method in a Swing application. You want to call paintComponent because you're using Swing and not Awt. You also need to call the super.paintComponent(g) method on the first line of the paintComponent method in order to correctly override the other paintComponent method.
The paint/paintComponent related methods are called very often. You don't want to create/initialize objects in them. The paint/paintComponent methods aren't a one time method like they may sound. They're continuously called and you should design your GUI around this. Design your paint-related methods to be event-driven rather than sequential. In other words, program the paintComponent method with the mindset that your GUI is reacting to things continuously rather than running in sequential order like a normal program. That's a very basic approach to it and hopefully doesn't confuse you, but if you go check out that tutorial you'll see what I mean eventually.
There are two basic types of GUIs in Java. One is Swing and the
other is Awt. Check out this answer on stackoverflow for a
nice description of the two.
Here is an example of what two buttons on a JPanel look like.
public class Test
{
public static void main(String[] args)
{
JFrame jframe = new JFrame();
GamePanel gp = new GamePanel();
jframe.setContentPane(gp);
jframe.setVisible(true);
jframe.setSize(500,500);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static class GamePanel extends JPanel{
GamePanel() {
JButton buttonShip1 = new JButton("Button number 1");
JButton buttonShip2 = new JButton("Button number 2");
add(buttonShip1);
add(buttonShip2);
//setLayout(null);
//if you don't use a layout manager and don't set it to null
//it will automatically set it to a FlowLayout.
}
public void paintComponent(Graphics g){
super.paintComponent(g);
// ... add stuff here later
// when you've read more about Swing and
// painting in Swing applications
}
}
}
Don't use a null layout
Don't create components in a painting method. The paint() method is for custom painting only. There is no need for you to override the paint() method.
Read the section from the Swing tutorial How to Use FlowLayout for a simple example that uses buttons and a layout manager.
I generate a bunch of JPanels and then pass them into a class that extends JFrame. How do I add an indefinite number of JPanels to this JFrame. I was also reading about JScrollPane should I incorporate this somehow into the design?
Example Code:
class foo extends JPanel
{
//generate JPanels
}
class bar extends JFrame
{
//grab some amount of foo classes and put them into this JFrame and show it
}
Also is there anything I need to watch out for when showing this JFrame?
Thanks
How do I add an indefinite number of JPanels to this JFrame?
CardLayout, JDesktopPane/JInternalFrame, JTabbedPane, JScrollPane - there are a number of options.
Also is there anything I need to watch out for when showing this JFrame?
(shrugs)
Construct and show GUI components on the EDT.
pack() the GUI before setting the position and calling setVisible(true).
Don't rely on the default layouts of content panes.
Don't implement custom painting in a top level container.
..
JFrame -> JScrollPane -> fathers JPanel then you'll decide which of LayoutManager will lay your bunch of JPanels, by defalut FlowLayout, don't forget to play with PreferedSize for childsPanels
I am learning java and building one project to test basics.
I have one menu item FILE and then sub menu item like
1)Front
2)Admin
3)Booking
I have separate gui made in separate files but i want that they should be visible in one area , with click on submenus
I am using swing , JmenuBar . Also the other guis are using Jframe
I have separate gui made in separate files but i want that they should be visible in one area
Most applications should only ever have a single JFrame, which indeed is your requirement since you want the separate GUI to be visible in the same area.
Therefore your other GUI, should not extend JFrame but instead should extend JPanel. Then you can just use a CardLayout on your real GUI to swap the panels in/out depending on which panel is selected from your menu. All these basic are covered in the Swing tutorial. I guess you would start with the section on:
How to Use Card Layout
How to Use Menus
Other people have already talked about ActionListeners and stuff, so that's half of the problem. The other half is how to actually deal with the multiple windows. I would probably not use one JFrame per different GUI, given that the spirit of the JFrame suggests you should only have one instance of it per application. Instead, I would look at using either JDialog or JInternalFrame. I'm not sure what you mean by
...should be visible in one area...
but JInternalFrame will allow you to implement something like a multiple document interface, where all the sub-GUIs would be contained within the frame of the main UI. JDialog would be give you independent windows like JFrame does.
If with "they should be visible in one area" you mean modal, then you should change all your JFrames to JDialogs and leave only the JFrame that contains your main-menu.
To do this, you need an ActionListener for each of the menu items. Then have each listener pass the instance of the JFrame you want to a method that controls where you want to position the window and show it.
//Make menu items
JMenuItem font = new JMenuItem();
font.addActionListener(new ActionListener() {
showWindow(new FontFrame());
});
JMenuItem admin = new JMenuItem();
admin.addActionListener(new ActionListener() {
showWindow(new AdminFrame());
});
...
//define frame handling method
void showWindow(JFrame f) {
...
f.setVistible(true);
}
My question boils down to this: is it standard structure in Swing programming to give listeners control over new components (e.g a new JPanel) for display and input, and to give that new component's listeners control over new components for display and input, and so on to infinity? Or does Java need to revert back to some sort of unifying class that ties all Swing components together in a procedural order?
At present, in my application that uses one JFrame only, in my listeners, my initial JFrame object is being passed as a parameter to all my JPanels so their listeners can call removeall() to clear the frame for a new JPanel. For example, short code as follows
public class MainFrame {
JFrame jfrm;
public MainFrame() {
jfrm = new JFrame("Main Frame");
JPanel mainPanel = new MainPanel(jfrm);
}
}
public class MainPanel extends JPanel {
public MainPanel(final JFrame mainFrame) {
JButton example = new JButton("Example");
example.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent le) {
mainFrame.removeall();
JPanel 2ndPanel = new 2ndPanel(mainFrame);
mainFrame.add(2ndPanel);
mainFrame.validate();
}
});
}
}
Is this the right structure - where it's the listeners that generate the new panels and not some unifying class? But if that's the case, how does Java's compiler ever get to mainFrame.validate() if there's a cascading infinity of listeners? I'm an old-school procedural programmer trying to program a Swing application in Java, and I reckon I might not have grasped the basic concepts of Swing programming. Look forward to any helpful answers, and thanks in advance!
I wouldn't do it like that. The Observer pattern is used in Swing to send notifications, usually as a result of an user action.
Take your example: The user 'clicks' on the button because he wants a new panel in MainFrame. But the button doesn't know what to do with a click. All he can do is notify event listeners, that it has been selected.
So we need some component that is interested in notifications. This component can register a listener with the button and receive notifications. The listener is this other components 'ear' (or it's 'eye'). But an ear (or eye) will not take action. It is just the other components sensor.
Which takes us back to the main question: who wants to be informed, if the button is clicked and who has to take action. This is a major design question. It's definitly not the listener that creates and adds a panel to main frame. It could be the main frames role to create and add sub panels or the role of a third component, which is responsible of creating a frame with sub panels.
But the listner is a bad place for this code.
Instead of destroying and creating panels you might want to look at hiding/showing them. There is a CardLayout layout manager that can do this: http://journals.ecs.soton.ac.uk/java/tutorial/ui/layout/card.html
Basically the idea is build and add all your panels at the start of your prog, then use the layout manager to flip between views.
As said by others, you might want to add some sort of model to your design, which is responsible for maintaining the state of the system.
First of all you shouldn't let the listener manipulate the frame directly, use a nested JPanel or it's ContentPane.
Your question depends on where your listener is located. You should only add components to a JFrame from the class itself. In your case it's OK, since the logic is confined to the class itself.
I don't think there is an infinity of listeners. They are in a list and are executed sequentially. Your listener should use SwingUtilities.invokeLater for manipulating the main frame.
I find the passing of the JFrame as an argument a little redundant. Why not create the listener from outside the constructor?
final JPanel mainPanel = new MainPanel();
JButton example = new JButton("Example");
example.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent le) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MainFrame.this.removeAll();
MainFrame.this.add(mainPanel);
}
});;
}
});
add(example);
It's not the best of examples, but I am note sure what you are trying to do.
The bottom line is you should create the components outside the listener, and then add it using the listener.
There is some confusion by the, not unusual, way you have organised your code. As a general rule of Java, don't subclass where you have no reason to. It rarely makes sense to subclass JPanel or JFrame.
It also rarely makes sense to assign components to fields in the class that creates them. In fact, do less in constructors.
Also do less in anonymous inner classes. Detangle the event data and call a method that makes sense for the enclosing class to have as an operation.