I've been learning Java Swing GUI from YouTube videos, as I don't learn them till around the end of next semester in university, and I find it too interesting to wait. However, although the video maker has made it pretty easy to follow, and I've learned a lot, I can tell that he probably learned it himself as some of his coding practices are a bit different than how we learned in school. (For example, he doesn't care about encapsulation or camel-case.) This makes me worry that everything I'm learning will be useless.
All of the projects he does in his videos are all within one class using inner classes implementing ActionListener, MouseListener, etc. So I don't know how to connect what I learned from these videos with the GUI-less multiple classes projects I worked on during school.
I'll give a general example of how the projects are: (I just add the private because that's what I'm used to)
public class Something extends JFrame {
private JPanel topPanel;
private JPanel bottomPanel;
private JLabel label;
private JButton button;
public Something() {
Container pane = this.getContentPane(); //need help with this
topPanel = new JPanel();
topPanel.setLayout(new GridLayout(1,1));
label = new JLabel("x");
topPanel.add(label);
pane.add(topPanel);
bottomPanel = new JPanel();
bottomPanel.setLayout(new GridLayout(1,1));
button = new JButton("Button");
bottomPanel.add(button);
pane.add(bottomPanel);
Event e = new Event();
button.addActionListener(e);
}
public class Event implements ActionListener {
}
Also, I read another thread on here on why extending JFrame is a bad idea. If I had to accommodate, would I just create a JFrame frame, then do add(frame)? And then just make sure I add the next layer to the frame? What accommodations would I have to do?
In general, you should not extend JFrame. Instead, extend JPanel. e.g. your code might look like:
public class Something extends JPanel {
// very similar code to yours goes here
// though I'd set a specific LayoutManager
}
Now you have a lot more flexibility: you can add your wonderful GUI into a JFrame, a JDialog, or into yet another even more complex JPanel. e.g.
JDialog dialog = new JDialog();
JPanel reallyComplexPanel = new JPanel(new BorderLayout());
// add in stuff here, e.g buttons at the bottom
Something mySomething = new Something();
reallyComplexPanel .add(mySomething, BorderLayout.NORTH); // my stuff at the top
dialog.setContentPane(reallyComplexPanel);
Related
I have previously used Java's KeyListener, but as my programs are demanding more I have gotten the recommendation to switch over to KeyBinds.
First of all I have tried to add keybindings to JFrame which didn't work ( I don't understand what JComponent I need to use. ). Therefore I tried moving the program over to a JPanel and then adding it to a JFrame, however the Key bind do not react when the desired button is pressed (in this case it's the "1" button);
In the method call I have set the action to be Print "Hi". Here is the code:
public class Panel extends javax.swing.JPanel {
JPanel Panel = new JPanel();
/**
* Creates new form Panel
*/
public Panel() {
addKeyBinding(Panel, KeyEvent.VK_1, "1Button", (evt)->{
System.out.println("Hi");
});
initComponents();
}
.....
And here is the method
.....
public static void addKeyBinding(JComponent comp, int keyCode, String id, ActionListener actionListener){
InputMap im = comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap ap = comp.getActionMap();
im.put(KeyStroke.getKeyStroke(keyCode, 0, false),
id);
ap.put(id, new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e) {
actionListener.actionPerformed(e);
}
});
}
What am I doing wrong? Thanks!
The key bindings are for your form panel, right? I think you're misunderstanding a few concepts about classes and objects. Also it's hard to help without seeing the full code. But your error is very likely caused by this line:
addKeyBinding(Panel, KeyEvent.VK_1, "1Button", ...
which should be:
addKeyBinding(this, KeyEvent.VK_1, "1Button", ...
The variable Panel should be replaced with the keyword this thus referencing the actual form panel.
It also should be created wherever you're creating your window so this line can also be removed:
JPanel Panel = new JPanel();
There are many things wrong with your code. I can't imagine the code in the first snippet even compiles. You are trying to name a variable the same as your classname.
Your class has no reason to extend JPanel since it isn't a new type of JPanel. Simply remove your extends. Then change the first line to:
JPanel panel = new JPanel();
Then pass lower-case panel to the addKeyBinding method.
If for some strange reason you want to keep your class extending JPanel then pass this as the first parameter to addKeyBinding as /u/tiiv said and remove the JPanel Panel = new JPanel line since that isn't needed (as you have it written now your class is the JPanel).
As far as which component to use JFrame is a top-level container so that is usually your main application window. And then you put JPanel and other components in the JFrame. There are actually 4 top-level containers in swing (JFrame, JWindow, JDialog, and JApplet) but JFrame is generally the one you will use as your main app window.
I hope that helps.
I've been researching communication, event handling and listening across JPanels for a while. I'm going to try and describe my issue without code first, because I feel it's more a design pattern roadblock.
So I have three custom JPanels inside a custom JFrame, each with their own instance variables and Actionlisteners. The ActionListeners at the moment update variables whenever a change happens within them.
But the catch is, I want the ActionListener in one panel to pay attention to elements in other panels. So if I've a box in Panel B and I change its value, I want the label in Panel C to change too.
I've researched a lot on the topic, from stackoverflow answers to documentation on the topic. But I'm having a hard time putting it all together. Especially when I've divided my custom panels into different classes. Can anyone help sum up how it should look?
Ultimately what you need here is to register an ActionListener on Panel B's text box which updates Panel C's label. The fact that Panel B and Panel C are different classes is just a minor bump in the road. The code that sets up this ActionListener simply needs to be able to get hold of references to 1) the text field whose actions we are interested in observing, and 2) the label whose text we are interested in changing.
Now, if Panel B and Panel C weren't separate classes, we would probably just have references to the text field and label handily laying around in member variables of our JFrame window. But Panel B and Panel C are separate classes, so we'll need to ask for their help. Well, actually, not so much ask as demand by dint of a little reprogramming...
First, have Panel B expose the text field with a getter method:
public class PanelB extends JPanel {
// ...
private JTextField textBox;
// ...
public JTextField getTextBox(){
return textBox;
}
}
Then, expose Panel C's label with a getter method:
class PanelC extends JPanel {
// ...
private JLabel label;
// ...
public JLabel getLabel() {
return label;
}
}
Now you can set up an ActionListener in more or less the usual way:
class MyFrame extends JFrame {
PanelB panelB = new PanelB();
PanelC panelC = new PanelC();
public MyFrame()
{
// ...
final JTextField panelBtf = panelB.getTextBox();
final JLabel panelClabel = panelC.getLabel();
panelBtf.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent ae)
{
panelClabel.setText(panelBtf.getText());
}}
);
}
}
I have written a jframe with cardlayout as in the following code :
public class Gui extends JFrame {
private static CardLayout cardlayout = new CardLayout();
private static JPanel cards = new JPanel(cardlayout);
public Gui() {
cards.setLayout(cardlayout);
CasaPanel card =new CasaPanel();
cards.add(card,"casa");
InCash card_1 = new InCash();
cards.add(card_1,"in");
OutCash card_2 = new OutCash();
cards.add(card_2,"out");
setLayout(new BorderLayout());
add(cards, BorderLayout.CENTER);
}
public static void showCard(String name)
{
cardlayout.show(cards, name);
}
i'm trying to call method to change card (ShowCard) from one of the JPanel(CasaPanel) , which is itself a 'card'. I want change a 'card' after clicking a button in a JPanel(CasaPanel) which is in another class. How to do this?I mean i know how to add button and listener but i don't know if is it possible to call a method in JFrame from a Jpanel class belonging to that frame ? How to refer to method in JFrame from other classes? I looked at this question but i really don't want put all code in one class.
Your "card" is added to the panel which uses the CardLayout. If you want to change cards then you just need access to the layout mananger. So from your panel you can use the getParent() method to get the parent panel and then use the getLayout() method to get the CardLayout.
So the code in the ActionListener might be something like:
JPanel parent = (JPanel)getParent();
CardLayout layout = parent.getLayout();
layout.show(panel, "...");
Also, then general design on your class is wrong. You should NOT be using static methods. Read the section from the Swing tutorial on How to Use CardLayout for working examples and a better way to structure your code.
I am currently trying developing simple game, but having some trouble with making game menu. I use JPanel for each states in game menu such as instruction or option and have method in parent JFrame to shuffle them according to what item user click on the menu.
My code is like this (without some simple method like setSize() or setVisible() ).
public class Game extends JFrame{
private JPanel mainPanel = new MainPanel();
private JPanel helpPanel; = new HelpPanel();
private JPanel optionPanel = new OptionPanel();
private JPanel currentPanel = new JPanel();
public Game(){
add(currentPanel);
}
public void changePanel(int destination){
remove(currentPanel);
if(destination==MAIN_PANEL)
currentPanel = mainPanel;
else if(destination==HELP_PANEL)
currentPanel = helpPanel;
else if(destination==OPTION_PANEL)
currentPanel = optionPanel;
add(currentPanel);
}
Everything work perfectly except when I try to use changePanel method in mouselistener, it wasn't responded anything. Then I try some simple method like this.
....
public void mouseClicked(MouseEvent e) {
removeAll();
JOptionPane.showConfirmDialog(null, "Pop when click anywhere.");
}
....
I expected my JFrame would be cleared and the dialog poped. The dialog does pop but for JFrame. My question is how can I use those simple method from mouselistener.
Sorry for my terrible English. I am now learning both Java and English.
Don't use a MouseListener.
I can't tell exactly what you are doing but you should probably be using either a JMenuBar with menus or JButtons. In any case I suggest you start by reading the Swing tutorial to learn the basics of Swing. There are sections on:
How to Use Menus
How to Use Buttons
to get your started.
Also you should check out the section on Using a Card Layout. This is generally the better approach when you want to remove/add panels from a frame.
I'm working on large scale program. As you can see I have one main JFrame and about 20 menu items on that. Each menu item must pop up a new window. At the beginning I have created a JLayeredPanel and then I assigned each menu item to one JPanel which is inside JFrame.Then I put 25 panel in JLayeredPanel... Default all the panels are set to invisible like:
panel1.setVisible(false);
panel2.setVisible(false);
so on
When user click on one menu item, its JPanel will be visible and rest are invisible. It looks messy and I have 5000 lines code. I used InternalFrame and TabbedPane but I'm not happy with them. I want to split my code in different JPanel classes and assign them to the main JFrame. I mean when user clicked on each menu item it will call the external JPanel and render it on the JPanel on the main JFrame. I am using design mode in netbeans and it does everything for me but the simpled structure is like this and it is not working:
public class NewJPanel extends JPanel{
//I have added buttons and etc on this panel
......
}
public class frame extends JFrame(){
JPanel panel = new JPanel();
.....
Public frame(){
frame.add(panel);
}
......
//When use click on the any button on the panel
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//this is not working
NewJPanel fi = new NewJPanel ();
panel1.add(fi);
//or I tested this way separately but it did not work
panel1.remove();
panel1 = new NewJPanel();
add(panel);
invalidate();
}
}
please give me any suggestion how I can control this program in splited classes in professional way.
remove JPanel from JFrame.getContentPane.remove(myPanel)
add a new JPanel with constants, everyhing depends of used LayoutManager and its methods implemented in API
call JFrame.(re)validate() and JFrame.repaint() as last code lines, if everything is done, these notifiers correctly repaint available area
again to use CardLayout, there isn't signoficant performance or memory issue
Please give me any suggestion how I can control this program in splited classes in proressional way.
Ok.
You should put all of your JPanels in a JTabbedPane. The JTabbedPane would be added to the JFrame.
The JFrame, JTabbedPane, and each JPanel would be constructed in a separate class.
You use Swing components, rather than extending them. The only reason you extend a Swing component is if you override one of the component methods.
You should also create model classes for each of the JPanels, as well as a model class for the application.
Read this article to see how to put a Swing GUI together.
make's code better
public class NewJPanel extends JPanel{
//I have added buttons and etc on this panel
......
}
public class frame extends JFrame(){
JPanel panel = new JPanel();
.....
Public frame(){
//frame.add(panel); you dont need call frame because extends JFrame in frame class
add(panel);
......
//When use click on the any button on the panel
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//this is not working
NewJPanel fi = new NewJPanel();
add(fi);
//or I tested this way separately but it did not work
/*panel1.remove();
panel1 = new NewJPanel();
add(panel);
invalidate();you must define panel1 before use it,like :JPanel panel1 = new JPanel();*/
}
}