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.
Related
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 am new to swing programming. I have created a Jtabbedpane and added 4 jpanel to it.
all the button and labels in the 4 jpanel are in the same java class and is starting to look cluttered. I am using Intellij. It would be nice if I can put all the items and events related to one panel in its own class so 4 classes for 4 panels and just a reference to those classes in the main frame. Not sure how to do this as most of the code is generated by the IDE.
If there is a way to do this or a tutorial that does this please let me know.
Yes you can break this up rather easily. Anywhere the code generates a new panel, probably as a "build" method, you can pull that out and make in a structure in another class. An example would look something like this:
// New class file named testPanel.java
public class testPanel extends JPanel{
// Constructor
public textPanel(){
// Add an example button
JButton btn_exit = new JButton("Exit");
btn_exit.addActionListener(new ExitButtonListener());
buttons.add(btn_exit);
}
// Private inner class which does event handling for our example button
private class ExitButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
// Add whatever other code you like here or above or anywhere else :)
}
Then to use that panel in your main JFrame, you can aggregate it like this:
private testPanel pnl_test = new textPanel();
// You can place this in the constructor
// for your JFrame without the "MyJFrame."
// But for demonstration purposes I will include it
MyJFrame.add(pnl_test);
// Or if you were placing a panel inside of another panel,
// you can use the same method associated with a JPanel object
MyJPanel.add(pnl_test);
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();*/
}
}
I have encountered a problem where if I use the main method in the same java file that contains the code for the JFrame which contains a JTable, and where I set the header color to yellow, when I run it , the header will be yellow. However, if I instantiate the JFRame by calling it from other classes, the header will not be yellow but will be the default color instead. Is there any way to ensure that the color stays the same even though I instantiate the JFrame and hence JTable from other classes? Thanks alot! I will be glad to clarify things if I have not explained clearly.
Hi I am sorry for not providing code beforehand. Here it is :
EquityFrame eq= new EquityFrame(file,"Apr2012");
this.dispose();// this code is in another class of a JFrame which will call the constructor of EquityFrame class
Code of EquityFrame class
public EquityFrame(File file, String nameTab){
createAndShowGUI( file, nameTab);
}
private void createAndShowGUI(File file, String nameTab){
//create frame
JTabbedPane tabPane= new JTabbedPane();
//pre-processing
init(file,nameTab);
//adding tabs
tabPane.addTab("Proposal", makeAdminPanel());
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame jf= new JFrame("CGH Equity Program");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLayout(new BorderLayout());
jf.add(tabPane,BorderLayout.CENTER);
int w = Toolkit.getDefaultToolkit().getScreenSize().width;
int h = Toolkit.getDefaultToolkit().getScreenSize().height;
jf.setSize(w, h);
jf.setVisible(true);
}
private JPanel makeAdminPanel(){
JPanel jp=new JPanel();
String[] column = {"Job Grade", "Job Title", "Min", "Midpoint", "Max",
"Lowest", "P10", "P25", "Median", "P65", "P75", "P90",
"Highest", "Average"};
String[][] data= getArrayOfValuesForEachJobGrade();
jp.setLayout(new BorderLayout());
JTable jt= new JTable(data,column);
JTableHeader th=jt.getTableHeader();
th.setBackground(java.awt.Color.pink);
th.setEnabled(false);
jt.setTableHeader(th);
jt.setEnabled(false);
jp.add(jt,BorderLayout.CENTER);
JScrollPane scrollPane = new JScrollPane(jt, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane.setEnabled(false);
jp.add(scrollPane, BorderLayout.CENTER);
return jp;
}
I will first run the first java file which will create an instance of EquityFrame that will display a tabbedPane with a JTable in it. However, the GUI I get from running the EquityFrame with its own main method is different from the GUI I get from creating an instance of it in another code. If i run it using its own main method, there will be a color change in the header of the table. However, the color remains the default if I run it from the other java class.
If I run it using its main method:
http://tinypic.com/r/2r5yjdj/6
If I run it using other class to call its constructor to generate the JFrame:
http://tinypic.com/r/3523yax/6
Thanks once again for any help rendered! Hope that this sheds more light on my problem.
Be certain to change the UI property before constructing anything that relies on the new value, preferablely before starting the event dispatch thread.
UIManager.put("TableHeader.background", Color.yellow);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Application();
}
});
Alternatively, you may be able to adapt the approach shown here in the method applyUI(); it can be invoked in the constructor, as shown, or when the system calls updateUI().
Addendum: Your first image shows a Look & Feel that supports the TableHeader.background UI property. The second image appears to be the Nimbus L&F, which does not support the property.
Is the code which set the color in the definition of your main method? If so, put it in the constructors for the JFrame or JTable instead.
I want to find out if a JPanel is on the screen or not. It doesn't mean that isVisible() method could be used for this situation. I mean I want to find out whether a component that has been initiated before, presently is one of components on my main panel or not.
Edit and more explanation: I have several panels initiated before in my program and use them on my form as needed. I want to know for example jpanel1 in now on any of panels that now are present on my form.
Example:
public class GUI extends JFrame() {
private JPanel1, jPanel2;
public static void main(String[] args) {
GUI gui = new GUI();
jPanel1 = new JPanel();
jPanel2 = new JPanel();
gui.setContentpane(jPanel1);
gui.setVisible(true);
}
}
now jPanel1 is visible on screen bu jPanel2 is not visible.
How can I find out this?
After investigation I find out this method represents that the component is displayed on screen or not:
isDisplayable()
in my Example:
jPanel1.isDisplayable() // returns true
jPanel2.isDisplayable() // returns false
as Simple as this!
jPanel1.isVisible()==true
jPanel1.isVisible()==false
for panel
jPanel1.isShowing() also works
If you're looking for children of a main panel, you could call getComponents() on the main panel to return an array of its Components, then iterate through them to check if any of them are the Panel you are looking for. You may need to call this recursively if the panel is not a direct child of the main panel.
Write your own panel class that extends JPanel. Add a new method to this class named isOnTheScreen() which return a boolean indicating whether the panel is added to the window or not.
public class MyPanel extends JPanel
{
boolean isAdded = false;
public boolean isOnTheScreen()
{
return isAdded;
}
public void setOnTheScreen(boolean isAdded)
{
this.isAdded = isAdded;
}
}
After creating your own panel objects, use the methods above to learn whether a panel is added to main panel/frame or not. Suppose you have added a panel to a frame:
JFrame frame = new JFrame()
MyPanel panel = new MyPanel();
frame.getContentPane().add(panel);
panel.setOnTheScreen(true);
As soon as you add it to the main screen, in this case a frame, call setOnTheScreen(true)
And similarly call setOnTheScreen(false) when you remove the panel.
After this design you can determine whether a panel is added to the main window or not by just invoking isOnTheScreen() anywhere else in your code. I hope this design helps you.