JTextField - Moving cursor using a button - java

I'm really struggling to find the functionality (if it even exists),
to move a JTextFields cursor by clicking a Button, instead of using the mouse.
For instance, I have my text field with a string added.
By clicking a back button, the cursor will move back through the string, 1 position at a time or forward depending on which button is pressed.
I can do it with the mouse, just click and type, but I actually need to have it button based so that the user can choose to use the keypad to enter a name or just click into the JTextArea and type away.
Is it possible? What methods should I look for if so.
Thank you.

These are sample buttons that are doing what you're asking for:
btnMoveLeft = new JButton("-");
btnMoveLeft.setFocusable(false);
btnMoveLeft.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
txtAbc.setCaretPosition(txtAbc.getCaretPosition() - 1); // move the carot one position to the left
}
});
// omitted jpanel stuff
btnmoveRight = new JButton("+");
btnmoveRight.setFocusable(false);
btnmoveRight.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
txtAbc.setCaretPosition(txtAbc.getCaretPosition() + 1); // move the carot one position to the right
}
});
// omitted jpanel stuff
They are moving the carot in the textfield txtAbc with 1 position per click. Notice, that you need to disable the focusable flag for both buttons, or the focus of your textfield will be gone if you click one of these buttons and you can't see the carot anymore.
To avoid exceptions if you're trying to move the carot out of the textfield boundaries (-1 or larger than the text length), you should check the new values (for example in dedicated methods):
private void moveLeft(int amount) {
int newPosition = txtAbc.getCaretPosition() - amount;
txtAbc.setCaretPosition(newPosition < 0 ? 0 : newPosition);
}
private void moveRight(int amount) {
int newPosition = txtAbc.getCaretPosition() + amount;
txtAbc.setCaretPosition(newPosition > txtAbc.getText().length() ? txtAbc.getText().length() : newPosition);
}

Related

Selecting a part of text in JSpinner on click

I have a JSpinner with SpinnerDateModel. I want when users click on any part of the editor (the date, month, or year), it will automatically select them. So I wrote this:
JSpinner dateSpn = new JSpinner();
dateSpn.setModel(new SpinnerDateModel());
JSpinner.DateEditor editor = new JSpinner.DateEditor(dateSpn, "dd-MM-yyyy");
dateSpn.setEditor(editor);
JFormattedTextField field = editor.getTextField();
field.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
int i = field.getCaretPosition();
if (i <= 2) {
field.select(0, 2);
} else if (i >= 3 && i <= 5) {
field.select(3, 5);
} else if (i >= 6){
field.select(6, 10);
}
}
});
But when the first time it clicked, nothing happened. Although when I click it again, it works perfectly. Where's wrong with my code?
From the documentation of MouseAdapter#mousePressed():
Invoked when a mouse button has been pressed on a component.
Which means this is executed when the mouse has only been pressed (not yet released mind you). So this is the first of the clicked / pressed / released methods to be invoked.
The issue you are having then is, that at this point in time, when mousePressed is invoked, your JFormattedTextFields caret position might not have been correctly updated yet. Hence the issue you are encountering.
The solution is to switch to mouseClicked() (or mouseReleased() as an alternative), because at that point, you can be sure that your JFormattedTextField has been updated correctly and the invoked method gets the correct value.

one jbutton doing different actions when clicked again

I need the same JButton to perform a different actions once it's clicked again. Like the first time I click the button, a text will appear in the first row of my JTextField, then the second time I click it, a text will appear in the second row if text field. How should I do it?
Here is my code BTW:
private void addActionPerformed(java.awt.event.ActionEvent evt) {
String items1 =(String)list.getSelectedItem();
String qty1 = qty.getText();
String price1 = price.getText();
int qty2 = Integer.parseInt(qty1);
int price2 = Integer.parseInt(price1);
if(evt.getSource() == add){
order1.setText(Integer.toString(qty2));
order2.setText(Integer.toString(price2));
order3.setText(items1);
}
I literally have no idea what to do next.
Here is the pic for the design GUI: http://prntscr.com/pfh96z
Take a Boolean isClickedOnce and change its state upon clicking on your button
private Boolean isClickedOnce = false;
//..
private void addActionPerformed(java.awt.event.ActionEvent evt) {
if(!isClickedOnce) {
//first click
//..
} else {
//second click
//..
}
isClickedOnce = !isClickedOnce;
}
Note: it'll consider every odd number click as first click and every even number of click as second click. it will toggle through your first and second row.
If your case is different lets say you have n number of rows, above procedure won't work and you might wanna do something similar with a list.

Adding a new button after an event

Writing a program to increment a counter when a +1 button is pressed, then when the counter reaches a certain number, remove the +1 button and replace it with a +2 button and so on. I create both buttons at first but just set btnCount1 to setVisible(false). When the certain number passes, I make btnCount invisible and btnCount1 visible and increment by two from there. When it reaches 10 clicks, the btnCount disappears, but btnCount1 does not appear.
I have tried making an if(arg0.equals(btnCount1)), and incrementing by two from there. I tried putting the add(btnCount1) inside the else if statement to create it after the elseif condition is true.
public class AWTCounter extends Frame implements ActionListener
private Label lblCount;
private TextField tfCount;
private Button btnCount;
private Button btnCount1;
private int count = 0;
public AWTCounter() {
setLayout(new FlowLayout());
lblCount = new Label("Counter");
add(lblCount);
tfCount = new TextField(count + "",10);
tfCount.setEditable(false);
add(tfCount);
btnCount = new Button("Add 1");
btnCount1 = new Button("Add 2");
add(btnCount);
add(btnCount1);
btnCount1.setVisible(false);
btnCount.addActionListener(this);
btnCount1.addActionListener(this);
setTitle("AWT Counter");
setSize(500,500);
}
public static void main(String[]args) {
AWTCounter app = new AWTCounter();
}
public void actionPerformed(ActionEvent arg0) {
if(count <= 10) {
++count; //Increase the counter value
tfCount.setText(count + "");
}else if(count > 10) {
btnCount.setVisible(false);
btnCount1.setVisible(true);
count += 2;
tfCount.setText(count + "");
}
}
The better solution here is to just have one button object and a separate variable for the current increment amount. When you hit the required count, increase the increment amount and change the button's label to the new value.
There are also a few other things you could do better here.
Use String.valueOf() instead of int + "" for String representations of integers if you're not adding words before or after the integer.
Don't add obvious comments for code. (e.g. 'increment variable x', 'set textString to the new value')
Use descriptive names for method parameters and variables.
Use Labels instead of TextFields for text that doesn't need to be editable or selectable like counter displays.
I'd personally change the name of lblCount to something like lblTitle as well, since changing your tfCount to a Label would logically take up that name and lblTitle makes more sense.
Here's a better way to implement actionPerformed:
private int increment = 1;
private Label lblCount;
...
public void actionPerformed(ActionEvent ignore) {
if(count == 10) {
btnCount.setLabel("Add " + (++increment));
}
lblCount.setText(String.valueOf(count += increment));
}

Clear button only makes counter JLabel blank but does not reset it.

I have made this application:
For example when I click on the clear button when the counter JLabel (pointsAvailable) is 19 then the counter JLabel goes blank as expected, however when I start adding points again it starts from 19 not 40 as set on the start. I would like to make it to reset back to 40 instead of just making it blank
Code for the clear button
private void JButtonActionPerformed(java.awt.event.ActionEvent evt) {
speedPoints.setText("");
attackPoints.setText("");
defencePoints.setText("");
powerPoints.setText("");
agilityPoints.setText("");
focusPoints.setText("");
availablePoints.setText("");
}
Code for Jlabel counter
public class addingPointsUI extends javax.swing.JFrame {
int pointsAvailable=40;
int speed=0;
int power=0;
int focus=0;
int agility=0;
int defence=0;
int attack=0;
Code for buttons +/-: to allow me to add or decrease value "example power - button"
private void powerMinusActionPerformed(java.awt.event.ActionEvent evt) {
if (power > 0 ){
if (pointsAvailable <= 0) {
JOptionPane.showMessageDialog(null, "You are out of available points");
return;
}
power = power - 1;
pointsAvailable = pointsAvailable +1;
availablePoints.setText(String.valueOf(pointsAvailable));
powerPoints.setText(String.valueOf(power));
}else {
JOptionPane.showMessageDialog(null,"You cannot take anymore points from Power");
}
}
Thank your for your kind replies.
Use a JSpinner with SpinnerNumberModel. Change the value of the model. The component will update and further changes will act on the current value of the model.
I can quickly think of two solutions:
1. In the event handler of your clear button include the following:
private void JButtonActionPerformed(ActionEvent evt){
...
pointsAvailable=40;
speed=0;
power=0;
focus=0;
agility=0;
defence=0;
attack=0;
}
This will reset all of your stats.
2. Or you can add an if statement to the listeners of every button that adds or subtracts a stat that will check if the specific statistic is empty. For example, for the speed buttons the code would look like so:
if (speedPoints.getText() == ""){
pointsAvailable += speed;
speed = 0;
}
Found my own solution on google:
private void ClearActionPerformed(java.awt.event.ActionEvent evt) {
speedPoints.setText(String.valueOf(0));
powerPoints.setText(String.valueOf(0));
agilityPoints.setText(String.valueOf(0));
defencePoints.setText(String.valueOf(0));
focusPoints.setText(String.valueOf(0));
attackPoints.setText(String.valueOf(0));
availablePoints.setText(String.valueOf(40));
}
Works perfectly

MouseEvents inside JList objects

I am a bit confused regarding a situation I have. I created a ListModel extending DefaultListModel and ListRenderer implementing ListCellRenderer for displaying a custom cell in a JList. The cells are some objects created from a class extending JPanel, that contain a JLabel and a JButton.
My issue is related to the mouse events: I want to trigger a certain event when clicking on the JButton inside a cell of the JList, yet I can not figure out how to match the mouse source point to that of the JButton from the respective index. More exactly, I added a mouse listener to the list, but I want it to trigger something if the mouse point is located inside the bounds of the JButton, and another action if it's on the data item. I added some prints to find out the cause of this, but before that some code to highlight the structure:
public WifiGuiHandler(JButton reference) {
btnReference = reference;
wifiListener = new WifiListener();
wifiPopupContainer = new JScrollPopupMenu("Connections.");
wifiPopupContainer.setMaximumVisibleRows(7);
connectionsHolder = new ArrayList<>();
listOfConnections = new JList();
listOfConnectionsModel = new ListModel(connectionsHolder);
listOfConnectionsRenderer = new ListRenderer();
listOfConnections.setModel(listOfConnectionsModel);
listOfConnections.setCellRenderer(listOfConnectionsRenderer);
wifiPopupContainer.add(listOfConnections);
wifiPopupContainer.pack();
initializeTestVariables();
initializeListeners();
}
Here, the constructor for the class that takes a JButton and adds a mouse listener to it, that triggers the appearance of a JPopupMenu, which has only one component, the JList that hold the entire data. Also, links the ArrayList with the data items to the ListModel.
public void initializeTestVariables() {
for (int i = 0; i <= 10; i++) {
WifiItem item = new WifiItem("Connection number " + i + ".", i);
connectionsHolder.add(item);
}
}
Setting up the data items.
public void initializeListeners() {
listOfConnections.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int index = listOfConnections.locationToIndex(e.getPoint());
if (index >= 0) {
WifiItem item = (WifiItem) ((ListModel) listOfConnections.getModel()).getElementAt(index);
System.out.println("Button of " + item.getConnectionName() + " is at location :" + item.getButton().getLocation());
System.out.println("Button has the bounds : " + item.getButton().getBounds());
System.out.println("MouseEvent detected on : " + e.getPoint().getLocation());
if (item.getButton().getBounds().contains(e.getPoint())) {
item.connectHere();
}
if (item.getButton().isVisible()) {
System.out.println("Set expanded on : " + item.getConnectionName());
item.setExpandedState(false);
listOfConnectionsModel.fireContentsChanged(item, index, index);
updateGui(false);
} else {
System.out.println("Set expanded on : " + item.getConnectionName());
listOfConnectionsModel.fireContentsChanged(item, index, index);
item.setExpandedState(true);
updateGui(false);
}
}
}
});
btnReference.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
updateGui(true);
}
});
}
And this is where the confusion arises. I correctly get the data item( WifiItem) from the mouse event location/point, but when I click on the JButton of the WifiItem, it doesn't trigger that method, like it doesn't seem to detect that the JButton actually is there. I also set up the prints, and what is strange, the Point for the JButton is always the same, even though it actually is different, and this seems to be the problem. More exactly, from the output of the program:
Button of Connection number 2. is at location :java.awt.Point[x=137,y=33]
Button has the bounds : java.awt.Rectangle[x=137,y=33,width=90,height=26]
MouseEvent detected on : java.awt.Point[x=172,y=125]
Button of Connection number 3. is at location :java.awt.Point[x=137,y=33]
Button has the bounds : java.awt.Rectangle[x=137,y=33,width=90,height=26]
MouseEvent detected on : java.awt.Point[x=172,y=125]
The above mouse events points were actually located on the JButton itself, only it didn't get that. As another strange fact, only if I click the JButton of the FIRST element of the list does it trigger the required mouse action.
Another print revealed that all the JButtons have the same Point and Rectangle, and I don't get it. There are 10 items in the JList, each displayed properly, how can all their JButtons have the same location? I must be missing some key element here. I looked at other posts and tried other recommendations: converting the point with SwingUtilities, removing all the mouse listeners from the JList and adding them to the data items.
To sum it up,the issue is that the list triggers the events for the correct data item in it(meaning, I do get the correct index for the item located there), but if the mouse event happens on the JButton of any data item inside the list, it doesn't trigger the required effect (the point is not withing the bounds of the button, even though it should be).
More exactly, I added a mouse listener for the list, but I want it to trigger something if the mouse point is located inside the bounds of the JButton, and another action if it's on the data item.
An easier solution would be to use a JTable. The data is separated into columns and the JTable has an API to let you know which row/column was selected.
You can use the Table Button Column as your renderer/editor for the button.
Edit:
only if I click the JButton of the FIRST element of the list does it trigger the required mouse action
Sounds like your conversion of the mouse point is off.
, how can all their JButtons have the same location?
Again, the button location is releative to the renderer panel. The panel itself is relative to the row in the JList. So I would guess you need to need the row index and add the height of each of the previous rows to your calculation.

Categories