Why are the keybindings not working with CardLayout? - java

In my question How do I draw on a JPanel from multiple outside classes? Frakcool gave me the advice to use key bindings, and one thing didn't work: When the JButton put another JPanel infront of the frame, the Keybinding didn't respond. This is the code:
private JFrame frame;
private JPanel[] statePanels;
private CardLayout layout;
private JPanel mainPanel;
private JButton button;
private String status;
void initAndShow()
{
//Init stuff
mainPanel = new JPanel(layout);
statePanels = new JPanel[2];
button = new JButton("Exit");
status = "Menu";
button.addActionListener(e -> {
status = status.equals("Menu") ? "World" : "Menu";
layout.show(mainPanel, status);
});
statePanels[0] = new OutWorldHandler();
statePanels[1] = new InWorldHandler();
mainPanel.add(statePanels[0], "Menu");
mainPanel.add(statePanels[1], "World");
mainPanel.getInputMap().put(KeyStroke.getKeyStroke('f'), "close");
mainPanel.getActionMap().put("close", this);
frame.add(mainPanel);
frame.add(button, BorderLayout.SOUTH);
}
#Override
public void actionPerformed(ActionEvent e)
{
System.out.println("hi");
}
The expected output was that when I allways pressed f the console would print out "hi", but it only did as long as I didn't press the button

Key bindings aren't particularly complex, but they can take a little bit of getting use to. To this end, it's useful to have How to Use Key Bindings and the JavaDocs for JComponent on hand, for reference.
One of the goals of the key bindings API is configurability, allowing us more control over determining when a key stroke should trigger an event.
The JComponent#getInputMap method returns a mapping which is bound to the "when has focused" context. This means that the component will need to have focus (and be focusable obviously) before a binding will be triggered.
If you want the binding to be triggered at a different level, then you need to use JComponent#getInputMap(int) and pass it one of the three available contexts:
JComponent.WHEN_IN_FOCUSED_WINDOW
JComponent.WHEN_FOCUSED
JComponent. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
Which you use will depend on your needs, but I'm generally lazy and go for JComponent.WHEN_IN_FOCUSED_WINDOW when I want a "global" state

The solution that worked for me: I simply added a statement to the button.addActionListener lambda that put the focus on mainPanel: mainPanel.grabFocus();.
The full code then looked something like this:
button.addActionListener(e -> {
status = status.equals("Menu") ? "World" : "Menu";
layout.show(mainPanel, status);
button.setText("Exit " + status);
mainPanel.grabFocus();
});

Related

How do I validate a textfield in java

public class Login extends JFrame{
JFrame frame; //frame
JTextField field; //to get username
JPasswordField p; //password field
JLabel l; //used for printing on frame
JButton b;
Login() {
frame = new JFrame("Login");
frame.setSize(350,200);
frame.setLocationRelativeTo(null);
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
l = new JLabel("Enter Username");
l.setLocation(10,10);
l.setSize(l.getPreferredSize());
frame.add(l);
field = new JTextField();
field.setColumns(15);
field.setSize(field.getPreferredSize());
field.setLocation(120,10);
frame.add(field);
l = new JLabel("Enter Password");
l.setLocation(10,40);
l.setSize(l.getPreferredSize());
frame.add(l);
p = new JPasswordField();
p.setColumns(15);
p.setSize(p.getPreferredSize());
p.setLocation(120,40);
frame.add(p);
b = new JButton("OK");
b.setSize(b.getPreferredSize());
b.setLocation(120, 80);
frame.add(b);
frame.setVisible(true);
}
private class b implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
String str;
str = field.getText();
if(str.equals("")) {
JOptionPane.showMessageDialog(null,"Please enter username");
field.requestFocusInWindow();
} else {
}
}
}
public static void main (String[] args) {
new Login();
}
}
the button won't functioning when I'm hit it
the button won't functioning when I'm hit it
You need to add the ActionListener to the button:
b = new JButton("OK");
b.addActionListener( new b() );
Make your class names more descriptive. "b" is not descriptive. Also, class names should start with an upper case character.
Don't use null layouts and setBounds(...). Swing was designed to be used with Layout Managers. Keep a link to the tutorial handy for Swing basics.
Take a look at How to Write an Action Listeners and How to Use Buttons, Check Boxes, and Radio Buttons.
Basically, you never register the ActionListener with your JButton
b.addActionListener(new b());
You code would be easier to read if you used meaningful variable names and followed the establishing coding conventions of the language. Have a look at Code Conventions for the Java TM Programming Language, for more details, it will make it easier for people to read your code and for you to read others
You may also want to have a read of You might want to have a read of Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?, but since you're discarded the layout manager, the use of setPreferredSize is completely pointless.
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify

Handle RadioButton events after button clicked

help,
my questions are:
why isn't itemStateChanges triggered, I tried to put it in the inner class ButtonHandler and also in RadioButtonHandler Im having trouble with it, what is the right way to do it?
I want to trigger and check the marked JRadioButtons after the user click the "check" button.
What is the right way to check which button was clicked, I feel like comparing the strings is bad programming practise. Maybe using an ID ?
How should I make a "reset" button(start over), I want to uncheck all radio buttons and run the constructor once again.
Thank you for your help !
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class ExamFrame extends JFrame {
static ArrayList<Question> qArrList;
JRadioButton a1,a2,a3,a4;
public ExamFrame() {
super("Quiz");
setLayout(new GridLayout(0, 1));
GridBagConstraints gbc = new GridBagConstraints();
Exam exam = new Exam();
qArrList = exam.getExam();
int count=0;
for(Question q : qArrList){
count++;
JLabel questionLabel = new JLabel(count+". "+q.getQustion()); //swing constant ?
ArrayList<String> ansRand = q.getAllRandomAns();
a1 = new JRadioButton(ansRand.get(0));
a2 = new JRadioButton(ansRand.get(1));
a3 = new JRadioButton(ansRand.get(2));
a4 = new JRadioButton(ansRand.get(3));
add(questionLabel);
add(a1);add(a2,gbc);add(a3);add(a4);
ButtonGroup radioGroup = new ButtonGroup(); //logical relationship
radioGroup.add(a1);radioGroup.add(a2);radioGroup.add(a3);radioGroup.add(a4);
}
//buttons:
JButton checkMe = new JButton("Check Exam");
JButton refresh = new JButton("Start Over");
ButtonHandler handler = new ButtonHandler();
checkMe.addActionListener(handler);
refresh.addActionListener(handler);
add(checkMe);
add(refresh);
}
/** Listens to the radio buttons. */
public class ButtonHandler implements ActionListener
{
public void actionPerformed (ActionEvent e) {
if(e.getActionCommand().equals("Start Over")){ //id?
//how to do this?
}
else{
RadioButtonHandler handler = new RadioButtonHandler();
a1.addItemListener(handler);
System.out.println("success?");
}
JOptionPane.showMessageDialog(ExamFrame.this, String.format("You pressed: %s", e.getActionCommand()));
}
public void itemStateChanged(ItemEvent e) //can i add it here?
{
JOptionPane.showMessageDialog(ExamFrame.this, String.format("yes?"));
System.out.println("success!");
}
}
public class RadioButtonHandler implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{
JOptionPane.showMessageDialog(ExamFrame.this, String.format("radio state changed"));
}
}
}
why "itemStateChanges" isn't triggered, i tried to put it in the inner
class "ButtonHandler" and also in "RadioButtonHandler" Im having
troubles with it, what is the right way to do it? I want to trigger
and check the marked JRadioButtons after the user click the "check"
button.
ButtonHandler is implemented with ActionListener only:
public class ButtonHandler implements ActionListener{}
The itemStateChanged(ItemEvent) function belongs to ItemListener. This function is triggered if state of a source component to which this listener is registered gets changed. So implement the ItemListener. However, one more thing to note, that JButton doesn't respond to ItemListener but JRadioButton will. Because this Item events are fired by components that implement the ItemSelectable interface. Some example of such components are: check boxes, check menu items, toggle buttons and combo boxes including Radio Buttons as mentioned above.
What is the right way to check which button was clicked, i feel like
comparing the strings is wrong programming. Maybe using an ID
Well using the event source function: e.getSource(), check whither the type of the source is your expected type and cast it to appropriate type. And then you can use getName(String) function and check the name you were expecting. Of-course you should assign the name using setName(String) after initialization of component. Or using the component reference directly if it is declared in the Class context and you have direct access to the component.
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getSource() instanceof JCheckBox)
{
JCheckBox checkBox = (JCheckBox)e.getSource();
if(checkBox.getName().equals("expectedName"))
; // do my thing
}
}
How should i make a "reset" button(start over), i want to uncheck all
radio buttons and run the constructor once again.
Well you are working with ButtonGroup. And ButtonGroup has a nice function: clearSelection() to help with whatever(I could not understand the part: run the constructor part) you want.
Edit: As you wanted me to see an ItemListener implemented class, Yes i can see that But:
i can not see that you have actually registered an instance of that class(a1.addItemListener(handler);) to any component before performing any action on the component to which ButtonHandler is registered to: checkMe, refresh
In addition to that, in this action performed function, you are checking with
action command, which you haven't even set with JButton.setActionCommand(String) function. You should not assign a (Item)listener depending on event-occurrence of another (Action)listener.
Tutorial:
How to Write an ItemListener
How to Write an ActionListener
How to Use the ButtonGroup Component

How to link a hotkey to a button in java?

I have four radio buttons and they're all part of a radioGroup. How can I link hotkeys to each of the buttons? What I want to do is link the keys '1', '2', '3' and '4' to each corresponding radiobutton.
buttonGroup1 = new javax.swing.ButtonGroup();
quizBut1 = new javax.swing.JRadioButton();
quizBut2 = new javax.swing.JRadioButton();
quizBut4 = new javax.swing.JRadioButton();
quizBut3 = new javax.swing.JRadioButton();
Use a KeyListener - you can attach them to just about any component in Swing.
What you'll probably do is attach a KeyListener to the primary JFrame in your application to capture all keypresses, and depending on which key was pressed, you will then trigger changes in the UI accordingly (e.g the selecting of a given radio button).
It's important that you attach the KeyListener to a container that will have keybaord focus pretty much all the time. You cannot, in this case, attach the KeyListener to the radio buttons themselves because the KeyListeners only see events for which they have focus. When a KeyEvent isn't absorbed by a given object, the KeyEvent is then passed on to its parent component to see if it wants to do anything with the event, and on and on all the way up to the application's window. If no KeyListener does anything with the event and you've gone all the way to the root of the component hierarchy, then nothing happens in response to the keypress and the event is essentially discarded.
as well, you could use ActionMap and KeyStroke. Some rough snippet, modify it:
class KeyAction extends AbstractAction {
JRadioButton b;
KeyAction(JRadioButton b) {
super();
this.b = b;
}
#Override
public void actionPerformed(ActionEvent e) {
b.setSelected(true);
}
}
b1.setAction(new KeyAction(b1));
b2.setAction(new KeyAction(b2));
b3.setAction(new KeyAction(b3));
bindHotkey('1', "1", b1.getAction());
bindHotkey('2', "2", b2.getAction());
bindHotkey('3', "3", b3.getAction());
..............
void bindHotkey(char keyChar, String name, Action action) {
KeyStroke ks = KeyStroke.getKeyStroke(keyChar);
container.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, name);
container.getActionMap().put(name, action);
}
You can use this also http://pastebin.com/UvkjD0g5

Swing GUI Factory Method Pattern

I am looking to use the Factory Method Pattern in order to make the development of my Swing UI quicker and more manageable.
In general, its an MDI application using JInternalFrames. I have a lot of settings, types as I call them, in the system (Eg. userTypes, accountTypes, etc.) I have a fixed UI which I've decided to use. Thing is, there are over 50 of these types in the system, so the factory method pattern seems to be the most manageable solution. Below are two screenshots of a working app.
I was looking at [this example][3] but since I wont be able to estimate the number of tabs I would require to store all info in a record, I would need to be able to add multiple tabs and controls (labels, textboxes, tables, comboboxes, etc.) within these tabs.
Based on the example, is it possible to create a JTabbedPane in the abstract class and modify and add to it in the subclasses? I tried the following and am a bit lost:
public AbstractTypeInternalFrame(String title) {
setBounds(100, 100, 808, 589);
JToolBar toolBar = new JToolBar();
getContentPane().add(toolBar, BorderLayout.NORTH);
JButton btnAdd = new JButton("Add");
toolBar.add(btnAdd);
JButton btnSave = new JButton("Save");
btnSave.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
toolBar.add(btnSave);
JButton btnDelete = new JButton("Delete");
toolBar.add(btnDelete);
JButton btnCancel = new JButton("Cancel");
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
toolBar.add(btnCancel);
JTabbedPane recordTabs = new JTabbedPane(makeRecordTabPane());
getContentPane().add(recordTabs, BorderLayout.NORTH);
JSeparator recordSearchSeparator = new JSeparator();
getContentPane().add(recordSearchSeparator, BorderLayout.NORTH);
}
protected abstract int makeRecordTabPane();
with the method makeRecordTabPane() require to return an int.
As you can see, I'm a little lost and just need some direction as to how to proceed with such a pattern. If any has any advice or even examples/links, it would be much appreciated.
I realize my question is vague, so if any clarification is required on my side, please feel free to ask.
Best regards.
Here is the question in more detail.
So, I am looking to build a simple JInternalFrame for CRUD operations on records on the system. Records such as users, usertypes, accounts, accountypes, etc. There are more than 50 of these types in the system, so I figure using the factory method pattern would make all these JInternalFrames more manageable.
Here is an example of a user record:
Link1
Link2
The top half constitutes of the details of a record, which are split into tabs depending on the contents of the record. Some records may have just one tab, while other larger ones will have multiple. Therefore, the contents of the JTabbedPane should be instantiated at the subclass level and per this example.
The bottom part is where we would search for records of that type. Say for example, in the links posted, the User Manager JInternalFrame is opened. We then would search for users according to username and/or userID. Results are displayed in the table below and on double-clicking a search result, the record is displayed above in the JTabbedPane.
Add, Save, Delete and Cancel buttons are then used to perform CRUD operations on whatever is entered into the record.
From this, we can say that the aspects of the design than need to be instantiated by subclasses are:
1) Size of the JInternaFrame
2) All contents of the JTabbedPane: no of tabes, tables, labels, textboxes, etc.
3) The number of columns in the search result JTable: which we can change by instantiating the JTable Header.
As a start, I was trying to just create an Abstract class with a JTabbedPane, and add components to the JTabbedPane to see how I could go about it. This is the code I posted earlier. This file was generated using WindowBuilder, which I later then modified:
package zm.co.freight.fpsManagementGUI.view;
import java.awt.EventQueue;
public abstract class AbstractTypeInternalFrame extends JInternalFrame {
/**
* Launch the application.
*/
// public static void main(String[] args) {
// EventQueue.invokeLater(new Runnable() {
// public void run() {
// try {
// AbstractTypeInternalFrame frame = new AbstractTypeInternalFrame();
// frame.setVisible(true);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// });
// }
/**
* Create the frame.
*/
public AbstractTypeInternalFrame(String title) {
setBounds(100, 100, 808, 589);
JToolBar toolBar = new JToolBar();
getContentPane().add(toolBar, BorderLayout.NORTH);
JButton btnAdd = new JButton("Add");
toolBar.add(btnAdd);
JButton btnSave = new JButton("Save");
btnSave.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
toolBar.add(btnSave);
JButton btnDelete = new JButton("Delete");
toolBar.add(btnDelete);
JButton btnCancel = new JButton("Cancel");
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
toolBar.add(btnCancel);
JTabbedPane recordTabs = new JTabbedPane(makeRecordTabPane());
getContentPane().add(recordTabs, BorderLayout.NORTH);
JSeparator recordSearchSeparator = new JSeparator();
getContentPane().add(recordSearchSeparator, BorderLayout.NORTH);
}
protected abstract int makeRecordTabPane();
}
The question is, am I on the right track? How should I approach it using the factory method pattern as I don't seem to grasp it very well. I've seen simpler examples, with shapes and drawings, but am a bit lost with Swing interfaces. Is there a good example you could direct me to or a simple example just to point me in the right direction ... thats all I was asking for. Sorry if it was vague ...

using java swing

I need to put a value in to my class from UI (Swing) and then start my method by clicking a button. What should I do?
Getting started with swing
Here's a super simple example of a text field and a button that, when clicked, will get the text value then you can all the method you'd like to pass that value to.
public class ButtonExample extends JPanel
{
private JTextField _text;
public ButtonExample()
{
_text = new JTextField();
setLayout( new BorderLayout() );
add( _text, BorderLayout.NORTH );
add( new JButton( new CaptureTextAction() ), BorderLayout.SOUTH );
}
private class CaptureTextAction extends AbstractAction
{
private CaptureTextAction()
{
super( "Click Me" );
}
#Override
public void actionPerformed( ActionEvent ae )
{
String textToCapture = _text.getText();
// do something interesting with the text
}
}
}
Swing is just the user interface you provide to to your app.
it works like this....
you have buttons, panels and all the stuff you need for providing a proper interface, which means if you need to take text input you'll put textfield or textArea in your UI
swing applications are based on events, thats the basic difference between console based and window based applications, a console based application is sequential it compiles and then executes code sequentially it has no regard of how you interact with it.
a swing application on the other hand is event based, until any event is fired and caught it won't do anything, in java you just handle the event, which means what happens after an event occurs is decided by the programmer.
suppose there is a button click event fires and there is a listener attached to the element then the actionPerformed function gets called and it is executed
suppose you want to get the user name from the app
JButton btnSubmit = new JButton("Submit");
JTextField txtName = new JTextField("", 4);
btnSubmit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
String name = txtName.getText();//see below for explanation
printInfo();//write the function call statements here if you want them to be executed when button is clicked
}
});
whenever button is clicked or more generally any event occurs on the button then it creates a string object in the string pool and assigns to it the value of the text field at the time when the button was clicked

Categories

Resources