First off, I'm new to Java, so please be gentle.
I have a JFrame which has two 'JPanels', one of which is a separate class (i've extended the JPanel). Ideally I'd like to 'dispatch and event' or notify the other JPanel object on the JFrame.
I have an array of JButtons in the custom JPanel class, which i'd like to add an event listener to. Upon clicking the JButton, i'd like to change something on the other JPanel.
I'm really not sure how to do this, so I moved the event handler into the JFrame class, and tried to do the following:
panel.buttonArray[i][j].addActionListener(this);
However, doing that didn't work at all. Annoyingly, Eclipse didn't complain either...
Any tips on how I can achieve this?
This was horribly explained, sorry.
Think of this not in terms of panels but in terms of objects. As long an object, lets say it has a name of object77, has a reference to the other object, call it object42, object77 can call methods on object42.
object77.methodInObject42();
panel77.methodInPanel42();
As for the event handler, then
buttonOnPanelXX.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
panel77.methodInPanel42();
}});
or even better...
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
panel77.methodInPanel42();
}});
}});
Related
Which way of implementing an ActionListener is more correct?
Is there any major performance differences?
Implementing an ActionListener to the class:
public class MainFrame implements ActionListener {
JButton exampleButton1 = new JButton();
JButton exampleButton2 = new JButton();
JButton exampleButton3 = new JButton();
public MainFrame(){
exampleButton1.addActionListener(this);
exampleButton2.addActionListener(this);
exampleButton3.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if(src.equals(exampleButton1)){
//Do something
}else if(src.equals(exampleButton2)){
//Do something
}else if(src.equals(exampleButton3)){
//Do something
}
}
}
Versus adding ActionListeners to each JButton:
public class MainFrame {
JButton exampleButton1 = new JButton();
JButton exampleButton2 = new JButton();
JButton exampleButton3 = new JButton();
public MainFrame(){
exampleButton1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Do something
}
});
exampleButton2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Do something
}
});
exampleButton3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Do something
}
});
}
}
Or perhaps even using Lambdas..?
I would prefer to use an individual Action as the listener for the button. An Action is a slightly more advanced listener that can be used anywhere an ActionListener can be used.
It provides additional functionality such as:
The same Action can be used by multiple components, such as a JButton, JMenuItem
You can disable the Action, which will disable all components that use the Action
It allows to assign mnemonics and accelerators to your components
See the Swing tutorial on How to Use Actions for more information and examples on this concept.
As you can spot, for single ActionListener-approach there are three more branches for each single if test, which button was pressed. There was nothing done yet, so no real action, just testing which button was pressed.
Now, if you want to achieve high quality work there are metrics like branch coverage. Firstly, If you go for the single ActionListener-approach each of your if is creating two branches. So you have to come up with 6 tests to just test if the base idea of your ActionListener is working correctly, so to find out which button was pressed and the correct if part was used. This is some overhead effort.
Secondly, there is the Single Responsibility Paradigm (SRP). It states that each class should be responsibly for one task only. Now, there are three things this single ActionListener is handling.
Thirdly, the reusage of the single ActionListener is very limited and highly depending on the buttons.
Fourthly, I also call this kind of single ActionListener-approach Manual written Object Orientation, because this would be an approach if there was no object orientation and you have to switch or if/else for calling different methods, like exampleButton1Pressed(), exampleButton2Pressed() etc. But, this can be achieved by three dedicated ActionListeners.
So go for dedicated ActionListeners.
if I have
ComboBox box = b;
b.addActionListener(this);
shouldn't I expect this.actionPerformed(event) to be called
when the combobox is operated?
I have a test frame with a few combo boxes, which seem to operate
normally, but no actionPerformed is ever called. Perhaps the frame
itself needs to be armed in some way?
Your question is not so clear and you didn't give it a proper title.
If you want to add ActionListener to a ComboBox, this is how you do it:
ComboBox box = new ComboBox();
box.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
}
});
From what I understand you just want to create a ComboBox from within a class that with be handling the action events. To do so I would suggest that the class inherits from ActionListener and override (use the #Override tag) the actionPerformed. Just Overriding the action perform is not enough if the class is not inheriting from ActionListener.
public class MyListener extends ActionListener {
#Override
public void actionPerformed (ActionEvent evt){
//code you want to execute when the event happens
}
public void methodCreatingComboBox(){
ComboBox b = new ComboBox();
b.addActionListener(this);
//other stuffs
}
}
that would work like a charm ! And you can use that same instance of MyListener for multiple events.
Here's the correct answer. I was using com.codename1.ui.Dialog as
the top level window. I switched to using com.codename1.ui.Form
and now the actions are firing as expected.
Something in the environment constructed by Dialog (which extends Form)
is interfering with the event mechanism. Perhaps by design.
I am planning to make a program that in the top of the contentPane has a menubar.
Under this menubar another JPanel, here is what I did (it works), but I don't know if this is the best way:
I made a lot of JPanels with different buttons, I want that a JMenuItem changes the screen(JPanel)
So what I did for each JMenuItem that set the specific JPanel(all panels are in the same position in the GridBagLayout, but all start with .setVisible(false);)
jemnuitem1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
jpanelItem1.setVisible(true);
jpanelItem2.setVisible(false);
jpanelItem3.setVisible(false);
}
});
jemnuitem2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
jpanelItem1.setVisible(false);
jpanelItem2.setVisible(true);
jpanelItem3.setVisible(false);
}
});
jemnuitem3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
jpanelItem1.setVisible(false);
jpanelItem2.setVisible(false);
jpanelItem3.setVisible(true);
}
});
This works, but I want to know if there is a way better to do this, or can I have a big problem doing this, because if this works, its fine for me work in this way, but I want the help of others that already made something similar.
You should use CardLayout. Then you can switch the visible panel instead of writing clumsy code like you have now.
I want my button to run a whole new class that will do different things inside. I don't know if that is even possible cause i'm really bad at java. My code looks like this at the moment:
public class MainMenu {
private class GardenActivities {
public GardenActivities() {
JFrame GardenAct = new JFrame();
GardenAct.setSize(400, 400);
GardenAct.setVisible(true);
}
}
public static void main(String[] args) {
JFrame choice = new JFrame();
choice.setSize(700, 500);
choice.setLocationRelativeTo(null);
choice.setTitle("Seeds");
choice.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 1));
JButton Labora = new JButton();
Labora.setText("Laboratory");
Labora.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ev) {
GardenActivities();
}
});
JButton Garden = new JButton();
Garden.setText("Garden");
Garden.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ev) {
}
});
choice.getContentPane().add(panel);
ButtonGroup group = new ButtonGroup();
group.add(Garden);
group.add(Labora);
panel.add(Garden);
panel.add(Labora);
choice.setVisible(true);
}
}
Just like I said. I need something to run my GardenActivities class just by pressing Garden button.
Your code doesn't compile, does it? When that happens, you need to post compilation errors with your question so that we can help you with them.
You need to add the key word new before the GardenActivities() statement.
#Override
public void actionPerformed(ActionEvent ev) {
new GardenActivities(); // here
}
Also, put the GardenActivities in its own file. There's no reason for making it a private inner class and many reasons not to do this.
Having said this, I recommend against having one JFrame create and display another JFrame since an application should have usually only one JFrame. Instead consider swapping JPanel "views" using a CardLayout, or if you must show a different window, consider showing the second dependent window as a modal or non-modal dialog.
Also more unsolicited advice: Your main method is doing way too much. Most of the code inside of the static main method should go inside the non-static main gui class, whatever that is, perhaps in its constructor or in an initGui() method that the constructor calls. The main method should just create an instance of the main gui class, make it visible, and that's about it.
And regarding:
I don't know if that is even possible cause i'm really bad at java.
Keep writing lots and lots of code, a ton of code, and keep reviewing tutorials and textbooks, and this will change.
I think that you just need to add:
new GardenActivities();
Into your JButton's actionPerformed() method.
Good Luck!
One way to do what you want, we make the GardenActivities class implement ActionListener itself.
Then your code would look something like this:
Garden.addActionListener(new GardenActivities());
Otherwise, your plan should work.
NOTE
See comments for opposing opinions about why one would want to leave the ActionListener in the anonymouse inner class and have it call into GardenActivities.
Thank you #HovercraftFullOfEels
As others have pointed out, this:
#Override
public void actionPerformed(ActionEvent ev)
{
GardenActivities();
}
Should look like:
#Override
public void actionPerformed(ActionEvent ev)
{
new GardenActivities();
}
There is no reason to create an inner class, and GardenActivities can be, and should be, its own class.
I'm currently building an application and it has a JFrame and a JDialog. The JFrame has a JList called:
JList lstMainVenuesEvents = new JList();
And I'm trying to get the value of lstMainVenuesEvents by using:
lstMainVenuesEvents.getSelectedIndex();
I can get the value perfectly fine on my JFrame, but how do I pass it to my JDialog? I thought about creating a setter method in one of my class files and then just getting that value from my JDialog file, but surely there's an easy way? Is it possible to just have a method of some sort that passes the data from the JFrame to the JDialog like a POST request in PHP?
Apologies if I've missed anything crucial out.
Update: here's the code for my JList and JDialog show.
JList lstMainVenuesEvents = new JList();
lstMainVenuesEvents
.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
// stop from firing twice
if (e.getValueIsAdjusting()) {
EventModify evtWindow = new EventModify();
evtWindow.setVisible(true);
}
}
});
I can't be confident it's "right" but an inversion of control sort of approach usually reduces passing values around.
Assuming the value lstMainVenuesEvents.getSelectedIndex() is used on a particular action/event in the JDialog you could set an ActionListener from the JFrame.
// some where in the JFrame
jDialog.setButtonPressed(new ActionListener() {
public void actionPerformed(ActionEvent evt)
{
// lstMainVenuesEvents.getSelectedIndex() is accessible in this block
// put code logic here where
}
});