I have a quick question. I don't get it...
I've got a JFrame where I add a JComboBox:
JComboBox<String> Team_ComboBox = new JComboBox<>();
Team_ComboBox_Handler ComboBox_Listener = new Team_ComboBox_Handler();
Team_ComboBox.addActionListener(ComboBox_Listener);
Team_ComboBox.addItem("Test 1");
Team_ComboBox.addItem("Test 2");
On this Frame I have a button which opens another JFrame.
Play = new JButton();
Play.setText("Play");
Play.setPreferredSize(dimension);
Play.addActionListener(menuhandler);
private class main_menuhandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==Play){
teams Team = new teams();
Team.teams();
disposeMainMenue();
}
if(e.getSource()==Close) {
System.exit(DO_NOTHING_ON_CLOSE);
}
}
}
Anyway, I would like to transfer the Selected value of the Combobox to a method of the other class. I know how I can get the itemvalue of the combobox in the method itself (with getselecteditem) But how can I do that in the ActionPerformed Method as I can't access the combobox in the ActionPerformed method.... I created another ActionListener (comboBox_Listener) but I haven't put any code into it...
Any idea? Thanks a lot in advance
Several issues appear to me:
Your main question:
But how can I do that in the ActionPerformed Method as I can't access the combobox in the ActionPerformed method
Your likely best solution is to change your code and variable declaration placement so that you can access the JComboBox fromt he actionPerformed method. If you're declaring the combobox from within a method or constructor, change this so that it is a proper instance field of the class.
Other problems:
You should not be creating multiple JFrames. If you need a dependent window, then one should be a JDialog. If not, then consider swapping views with a CardLayout.
Learn and follow Java naming conventnions so others can better understand your code. Class names begin with capital letters and methods and variable names don't for instance.
I am not sure why you're doing this: System.exit(DO_NOTHING_ON_CLOSE);. Why pass that constant into the exit method?
Use a constructor for your action listener class:
private class main_menuhandler implements ActionListener {
private JComboBox<String> Team_ComboBox;
public main_menuhandler(JComboBox<String> Team_ComboBox){
this.Team_ComboBox = Team_ComboBox;
}
}
Now you can create the class main_menuhandlervia the constructor and add the combobox to it.
In your Overriden action you have access to it.
Try playing around with this as your code snippet isn't broad enough to actually provide proper code. But this should answer your question
Related
I need a way to create an ActionListener that when a JButton is pressed, it updates the content of 7 different JLabels to display the information in the form of text.
The data is retrieved from methods called from an external JAR file. The methods return ArrayList. I attempted to convert the ArrayList into a String, and tried to change the JLabel content with setText().
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import api.anAPI.THEAPINAME;
public class Controller implements ActionListener {
private MainGUI maingui;
private SubPanel subpanel;
private static THEAPINAME anAPI =new THEAPINAME("XyP0D75oRCGrLE78","x47ka5jmOGaJ2zvw");
static ArrayList<String> nameList =new ArrayList<String>();
private String names;
public Controller(MainGUI maingui,SubPanel subpanel){
this.maingui = maingui;
this.SubPanel = subpanel;
MainGUI.getSearchBtn().addActionListener(this);
nameList.addAll(anAPI.getNames());
for (String s: nameList){
names+= s+"\t";
}
}
public void actionPerformed(ActionEvent e) {
SubPanel.label1.setText(names);
//6 more Labels.
}
}
An additional, because I have 7 JLabels, would I need to do 7 getLabel methods? Or is there a way to get them all with just 1 method.
I am not entirely sure what I am doing incorrectly, it could be that the getMethods I used returned the wrong widget in question as the code for the GUI was not done by me but by a teammate and he had done a really poor job of making it clear for us.
UPDATE:
Fixed up the GUI to make it clearer, so I think that is no longer the problem. Now I think the problem might be that I did not convert the contents of the ArrayList into a String in the way I thought.
The desired function of the code is when the JButton is clicked on, the JLabels in question are all updated to their relevant data.
addController method
public void addController(Controller controller){
control = controller;
jb1.addActionListener(control);
}
You didn't really describe what the problem is of your current code.
You can add a method say getLabels() in SubPanel class to return all of its labels, or you can add a method setLabelText(String text) to set text for all of its labels by extending or directly modifying SubPanel class.
UPDATE
You have several very confusing parts in your code.
In your constructor, it should be this.subpanel = subpanel and then it should be maingui.getSearchBtn().addActionListener(this), also in method actionPerformed it should be subpanel.label1.setText(names). These might not be your problems though since you didn't say it's the code you're actually running.
Looks like that you haven't created any instance of class Controller thus the code in it never gets executed.
You need to have some code outside of you Controller class like this:
MainGUI maingui;
SubPanel subpanel;
// they're somehow initialized
Controller controller = new Controller(maingui, subpanel);
I currently have all my action listeners declared under my constructor, but I'm starting to get a lot of them building up. Is it possible to create a new classes (via the default package window) and have them all there separately?
This seems obvious to me, I have tried this and I get no errors, but my application wont load when I do, it says its open but theres nothing there.
Here is a link to my code that is compilable.. I have commented out anything that uses other classes (there isn't much), if I have missed any just comment them out.
https://shrib.com/Tum8kjgH?v=nc
Thanks!
The most simple solution is to declare your listeners each in their own class. For example, for some button:
public class SomeButtonActionListener implements ActionListener{
private InternalFrame iFrame;
public SomeActionListener(InternalFrame iFrame){
this.iFrame = iFrame;
}
public void actionPerformed(ActionEvent ae) {
//TODO
//Example: iFrame.getSomeButton().doSomething();
}
}
Note that in this way, you need to expose getter methods for all swing components you need to access from your listeners (an alternative is to send the specific components needed as arguments to the listener when constructor is called).
In your InternalFrame you can add the listeners as:
someButton.addActionListener(new SomeButtonActionListener(this));
Also you can put all your listeners in a specific package like yourapp.listeners.
EDIT
A more specific example:
public class AddRoomListener implements ActionListener{
private InternalFrame iFrame;
public AddRoomListener(InternalFrame iFrame){
this.iFrame = iFrame;
}
public void actionPerformed(ActionEvent event) {
iFrame.getIntFrame2().setVisible(true);
iFrame.getIntFrame2().toFront();
}
}
In this case you need to declare the getIntFrame2() getter in the InternalFrame class.
So i just stumbled upon this problem while coding my program using MVC.
I have a private JButton in the View class. I wrote the method to add the listener to all respective buttons. However, when i'm trying to code the ActionPerformed() part it throws an error about JButton not being visible.
Setting JButton to public solves the problem completly, but is it the right thing to do? Is there another way of setting the ActionListener without making the JButton public?
public class learningView extends JFrame {
private JButton viewButton = new JButton("View Resources");
public void addButtonListener(ActionListener listenerForButtons) {
viewButton.addActionListener(listenerForButtons);
saveButton.addActionListener(listenerForButtons);
addButton.addActionListener(listenerForButtons);
}
}
public class learningController {
private learningModel theModel;
private learningView theView;
public learningController(learningModel theModel, learningView theView) {
this.theModel = theModel;
this.theView = theView;
this.theView.addButtonListener(new buttonListener());
}
class buttonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == theView.viewButton) {// This is where problem arises
}
}
}
}
Hastebin for view and controller classes (without model) for the convienience.
http://www.hastebin.com/ecawolusal.avrasm
Since viewButton has private access to LearningVew, it will simply be inaccessible out of that classes context.
Now, before you change the access level, you might consider changing your approach.
Rather then adding an ActionListener to each button which notifies an external source, it might be simpler to have the view to monitor the buttons itself.
Before you get up in arms over how this would break the MVC, the idea would be to then have the view raise a simpler, more dedicated event for the button in question, for example, viewButton could raise viewWasActivated or something, to which the controller would then respond.
This would require you to define a interface contract for both the view and the controller so they knew what information they were capable of passing to each other and what events might be triggered. This protects the view controls and means you don't need to expose the unnecessarily.
Which is demonstrated in more detail here.
The other choice would be to use the actionCommand property of the buttons instead of comparing references of the buttons to the event source, but you would first need to check that the source of the action event was a button ... and I personally don't like "bulk" ActionListeners, they get messy real quickly...
I am cleaning my code. I read that I putting the ActionListener is another class is better. So that's what I did.
But in my ActionListener, everything works except at some point in the code, I got a setSize(xx,xx). I worked before because it was in the same class. But not anymore. I've tried multiple solutions but I couldn't figure it out.
ActionListener:
public class ActionFrame implements ActionListener{
public void actionPerformed(ActionEvent e){
Object src = e.getSource();
if(src == Frame.Console_Bouton){
System.out.println("Bouton console");
if(getSize().getWidth() >= 750){
/** If True (Retirer) */
for(int i = 1090; i > 689; i--){
setSize(i, 490);
System.out.println("Rétractation du Frame");
}
}else{
/** If False (Etirer) */
for(int i = 689; i < 1090; i++){
setSize(i, 490);
System.out.println("Etirage du Frame");
}
}
}
...
As for errors, there are none, it will just freeze the program.
Guessing: possibly this is a case where extracting the ActionListener is not a great idea, since it uses a private method of your object.
Classes with generic/reusable functionality deserve to be on their own. As long as they are intended for specific usage, it's not bad practice (at all!) to only put them as close as possible to the spot where they're used. I can imagine that your setSize method is not part of your class' public interface, so the ActionListener is merely 'glue' to couple an event to your specific class.
In this case, you would create a 'tiny' line of glue:
abstract class ActionAdapter implements ActionListener {
}
...
frame.Console_Bouton.addActionListener(
new ActionAdapter(){ // anonymous inner class
void actionPerformed(ActionEvent e){
... // (no need to check source!)
}
});
Create a new class as:
ButtonAction implements actionListner
{
//put the code above here
}
A Good way of doing this is use Callback mechanism.
I have posted an answer in the same context here
JFrame in separate class, what about the ActionListener?
-- EDIT--
Get the source from ActionEvent then find its parent (get parent of parent if needed until you get the desired component that needs to be re sized) and call setSize() on it.
Create an instance of the View in the controller
Change the access modifier of setSize(xx,yy)method from private to public.
replace setSize in actionPerformed() with to view.setSize(xx,yy).
I have a JFrame that contains a "display" JPanel with JTextField and a "control" JPanel with buttons that should access the contents of the display JPanel. I think my problem is related on how to use the observer pattern, which in principle I understand. You need to place listeners and update messages, but I don't have a clue where to put these, how to get access from one panel to the other and maybe if necessary to introduce a "datamodel" class. For example, I want to access the contents of the JTextField from the control panel and I use an anonymous action listener as follows:
JButton openfile = new JButton("Convert file");
openfile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openButtonPressed();
}
});
You need to reduce the coupling between these objects.
You can have a master object, that owns all the text fields and the button ( the panels are irrelevant )
Then a separete actionlistener within that master object ( I call it mediator see mediator pattern )
That action listener performs a method on the mediator which in turn take the values from the textfields and create perhaps a transfer object.
This way you reduce the coupling between the panels, textfields etc. and let the control in one place ( the mediator ) that is, you don't let them know each other.
You can take a look at the code in this question:
https://stackoverflow.com/questions/324554/#324559
It shows these concepts in running code.
BTW the observer pattern is already implemented in the JTextField, JButton, ActionListener etc. You just need to add the hooks.
I hope this helps.
EDIT Joined two answers into one.
This is the code.
class App { // this is the mediator
// GUI components.
private JFrame frame;
private JTextField name;
private JTextField count;
private JTextField date;
// Result is displayed here.
private JTextArea textArea;
// Fired by this button.
private JButton go;
private ActionListener actionListener;
public App(){
actionListener = new ActionListener(){
public void actionPerformed( ActionEvent e ){
okButtonPressed();
}
};
}
private void okButtonPressed(){
// template is an object irrelevant to this code.
template.setData( getData() );
textArea.setText( template.getTransformedData() );
}
public void initialize(){
frame = new JFrame("Code challenge v0.1");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
name = new JTextField();
count = new JTextField();
date = new JTextField();
textArea = new JTextArea();
go = new JButton("Go");
go.addActionListener( actionListener ); // prepare the button.
layoutComponents(); // a lot of panels are created here. Irrelevant.
}
}
Complete and running code can be retrieved here:
It is important to favor composition over inheritance when possible.
It does make the code cleaner if you create the models in one layer and add a layer or two above to create the components and layout. Certainly do not extend the likes of JFrame and JPanel.
Do not feel the need to make the composition hierarchy in the model layer exactly match the display. Then it's just a matter of taking the text from the Document and performing the relevant operation.
Okay, perhpas not that simple. Swing models are a little bit messy. In particular ButtonModel is brain damaged, and the controller area of code might not be entirely pure.
We have so called builders, which will build the parent panel out of the children. In this builder you will have access to all the subcomponents you need to listen to and can thus can implement any logic there.
Finally the builder will then return the parent panel with the complete logic.
Once you've got the parent panel it's really a mess getting to the child components and have them do anything.
thanks. I added a datamodel layer which handles somehow the communication between the panels.
I also found this link on Listeners on JTextField usefull:
link text