How to create clickable textcontainer - java

I have 16 JTextarea's placed on my panel (in gridlayout). I didn't use the design tools netbeans for this. The code generates them for me:
for (int i = 0; i < 16; i++) {
JTextArea vak = maakVak(gridLayoutPanel); //make new JTextArea and add them to gridlayout.
tekstvakken.add(vak); //save Jtextarea to ArrayList.
}
This is the method for generating a new JTextArea and adding them to the GUI.
public JTextArea maakVak(JPanel p) {
JTextArea vak = new JTextArea(80, 120);
vak.setEditable(false);
p.add(vak);
return vak; //return JTextarea to save in the ArrayList
}
I have an ArrayList that contains objects from a class that I made for the software. The Objects contain multiple Strings. I need to "print" all the strings from one object to one JTextArea, and I do that for the first 16 objects in my ArrayList (hence I've only 16 JTextArea's).
This works fine, I have 16 JTextArea's on my GUI and they contain the correct Strings.
Now I want to add more functionality to my software, and I need in some way to make these JTextArea's clickable (when this event occurs, a screen should pop-up where I can change/delete the object).
How is this possible (with minor changes)?

JTextArea is a java.awt.Component, so it has access to the addMouseListener method.
textArea.addMouseListener(new MouseListener(MouseEvent e) {
//implemented methods go here
});
This will create an anonymous inner class which implements MouseListener, and I found it to be the simplest way to do this.
Otherwise, you can just have your class implement MouseListener. This accomplishes the same thing as you still have to override the methods, but it affects the whole class rather than an anonymous class that is only used once.
If the Strings that will be placed in the JTextAreas aren't very lengthy, I would suggest using JButtons instead, so you could use the addActionListener method instead of having to also override four other methods that you won't use.

add a mouseListener to JTextArea in maakVak
public JTextArea maakVak(JPanel p) {
JTextArea vak = new JTextArea(80, 120);
vak.setEditable(false);
vak.addMouseListener(textAreaMouseListener());
p.add(vak);
return vak; //return JTextarea to save in the ArrayList
}
private MouseListener textAreaMouseListener() {
return new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
JTextArea vak = (JTextArea) e.getComponent();
//display popup to make changes
}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
};
}

Related

Drawing Swing components inside a Graphics object

is there any way I can make a Java Graphics object (g) draw a swing component?
like a button or JLabel
something like g.drawJLabel ?
I'm trying to add a clickable text (Link) inside my graphic object but it's not possible to add a mouse listener to the graphics objects
Your clickable text can be an JLabel with an mouselistener
JLabel hyperlink=new JLabel("Click me");
hyperlink.addMouseListener(new MouseAdapter()
{
#Override
public void mouseEntered(MouseEvent m)
{
hyperlink.setForeground(Color.blue);
}
#Override
public void mouseExited(MouseEvent m)
{
hyperlink.setForeground(Color.black);
}
#Override
public void mouseClicked(MouseEvent m)
{
if (Desktop.isDesktopSupported() &&
Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(new URI(hyperlink.getText())));
}
}
Make sure that your graphical object has some form of layout manager otherwise your text won't show up
Then inside your graphical objects which I assume all of them extends some form of JComponent you can add this text to your object and your text will still receive user input

What if we want to use mouseClick Method many times with different implementation

How we can use same method (same paramater and return type) with different implementation
in other word , in java Gui i want to use mouseClick method in many different way in one class , how this could be possible ?
You would implement different MouseListeners and add these to each component you want different mouseClick behavior in.
Edit: I added an example below.
public void example() {
JPanel panel1 = new JPanel();
panel1.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
/* your code here, what should happen when the mouse clicked the panel */
}
});
JTable table1 = new JTable();
table1.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
/* your code here, what should happen when the mouse clicked the table */
}
});
}
Here I used new MouseAdapter() more here instead of new MouseListener(), which implements MouseListener because this allows you to only implement a single method of the MouseListener interface.

Dynamically add swing component to gui on click?

Purely theoretically when adding new components like that
JButton buttonAdd= new JButton("Add More");
buttonAdd.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel.add(new JComboBox<String>(data);
panel.add(new JTextField();
}
});
Is there way to getSelectedIndex() or getText() when u don't declare it in normal way?
there are several ways to reach dynamicaly added components to swing tree:
1st approach:
panel.getComponent(n);
returns n'th component in the panel (Container). (n is the order, that component added to its parent (parent is panel here) ) (you need to know component's index) this way you can use ((JComboBox)panel.getComponent(3)).getSelectedIndex()
2nd approach
directly add some listeners when dynamically adding your components;
JButton b1 = new JButton("add");
b1.addActionListener(e -> {
JComboBox<String> color = new JComboBox<String>();
color.addActionListener(x -> { myFormBean.setColor(color.getSelectedItem();) });
panel.add(color);
JTextField name = new JTextField();
name.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent e) {
myFormBean.setName(name.getText());
}
#Override
public void insertUpdate(DocumentEvent e) {
myFormBean.setName(name.getText());
}
#Override
public void changedUpdate(DocumentEvent e) {
myFormBean.setName(name.getText());
}
});
panel.add(name);
panel.revalidate();
panel.repaint();
});
this way you do not need to reach your dynamically added components.
3rd approach may be using a framework for data binding,
4rd approach ...
Yes, you can add Swing components to the container this way. However you need to call revalidate on the panel, otherwise they may not appear instantly.
If you need to access these components after they are created, assign the value returned by constructor to the field of your object, declared inside your class. You cannot assign to the variable in the calling method as the constructors are called from the inner class.

Listen to the paste events JTextArea

I want to call a function when the user pastes text in my JTextArea. Is there any event generated when the text is pasted to the JTextArea and which listener can I use to trigger my function on this event?
One possible solution (and I hope some one has a better one) would be to replace the key binding Action responsible for actually performing the paste operation.
Now, before you do this, the default paste operation is not trivial, instead, I would replace the default paste Action with a proxy, which could call the original, but would allow you to intercept the operation, but not have to re-implement the functionality yourself, for example...
public class ProxyAction extends AbstractAction {
private Action action;
public ProxyAction(Action action) {
this.action = action;
}
#Override
public void actionPerformed(ActionEvent e) {
action.actionPerformed(e);
System.out.println("Paste Occured...");
}
}
Then you would simply need to look up the default Action and replace it...
JTextArea ta = new JTextArea(10, 10);
Action action = ta.getActionMap().get("paste-from-clipboard");
ta.getActionMap().put("paste-from-clipboard", new ProxyAction(action));
The problem here is, this won't tell you if the operation failed or succeeded or what was actually pasted. For that, you could use a DocumentListener, registered before you call the default Action which could record the changes to the document. Obviously, you'd want to deregister this after the default action ;)...
Now, equally, you could just override the paste method of the JTextArea, which equates to about the same thing, but, the first option would be more portable...
As an idea...
Take a look at How to Use Actions and How to Use Key Bindings for more details
you can have something like below, whenever you paste something in the textarea, then 'Pasted!' is printed out on your console. It prints only on paste !
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
public class TextAreaDemo extends JFrame {
JTextArea _resultArea = new JTextArea(6, 20);
public TextAreaDemo() {
_resultArea.setText("");
JScrollPane scrollingArea = new JScrollPane(_resultArea);
JPanel content = new JPanel();
content.setLayout(new BorderLayout());
content.add(scrollingArea, BorderLayout.CENTER);
this.setContentPane(content);
this.setTitle("TextAreaDemo B");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
_resultArea.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if ((e.getKeyCode() == KeyEvent.VK_V) && ((e.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
System.out.println("Pasted!");
}
}
#Override
public void keyReleased(KeyEvent e) {
}
});
}
public static void main(String[] args) {
JFrame win = new TextAreaDemo();
win.setVisible(true);
}
}
You can also check out Wrapping Actions which is basically the same suggestion as MadProgrammer except that the WrapperAction will delegate all the methods of the Action to the original Action. This will allow you to pick up the text and Icons associated with the original Action in case you ever want to add your custom Action to a JMenuItem or JButton.

How to make a JList "refresh" method in a JPanel class

I'm a beginner at java and want to make a JFrame with tabs containing a seperate JPanel. One panel has a list where it displays things that you select in a different panel, so I want this panel to always display a list of stuff that you have selected in a different panel (I hope that makes sense). To do this, I need to make a method to refresh the JList. This is the Farthest that I've gotten on that:
public class PanelClass extends JPanel {
private JList list;
private DefaultListModel listModel = new DefaultListModel();
private ArrayList<SomeOtherClass> objectArray = new ArrayList<SomeOtherClass>();
public PanelClass() {
list.setModel(listModel);
}
public void refresh() {
updateListModel();
list.setModel(listModel);
}
public void updateListModel() {
if (objectArray.isEmpty()) {
System.out.println("No Objects In Array!");
} else {
listModel.clear();
for (SomeOtherClass SOC : objectArray) {
// SOC.getName() just returns a string
listModel.addElement(SOC.getName());
}
}
}
public void addObjectToArray(SomeOtherClass SOC) {
objectArray.add(SOC);
}
}
Could someone please tell me how to make a "refresh" method to constantly keep the JList up to date?
The AWT/Swing event model is based upon the widgets being event sources (in the MVC paradigm, they are both view and controller). Different widgets source different event types.
Look at the java.awt.event (primarily), and javax.swing.event packages for the listener interfaces you'll need to implement and register in order to produce your desired effect.
Basically, you write a Listener implementation, and register it with Widget1. When Widget1 detects an event, it will notify you, and you can then use the information it provides to update Widget2.
For instance, if a button being clicked would add an object to your list, you might have something like below (I usually put this code in the encompassing JFrame class, and make it implement the listener interfaces; but you can choose to use inner classes or separate listener classes):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyFrame extends JFrame implements ActionListener {
private JButton button = new JButton("Click me!");
private DefaultListModel<String> listModel = new DefaultListModel<String>();
private JList<String> list = new JList<String>(listModel);
private int counter = 1;
public MyFrame() {
setTitle("Test Updates");
JTabbedPane tabs = new JTabbedPane();
add(tabs, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.add(list);
tabs.add("Selections", panel);
panel = new JPanel();
button.addActionListener(this);
panel.add(button);
tabs.add("Options", panel);
pack();
}
#Override
public void actionPerformed(final ActionEvent event) {
if (button.equals(event.getSource())) {
listModel.addElement("Item " + counter++);
}
}
/* Test it! */
public static void main(String[] args) {
final MyFrame frame = new MyFrame();
frame.addWindowListener(new WindowAdapter() {
#Override public void windowClosing(final WindowEvent e) {
frame.setVisible(false);
frame.dispose();
System.exit(0);
}
});
frame.setVisible(true);
}
}
This code sample is minimal, but it should give you an idea of how to go about implementing what you want.
You can do it in two way. First : Write it in infinite thread loop so that it will constantly update JList. Second : You can call refresh() method whenever new SOC objects are added in your ArrayList. It means you can call refresh() method from addObjectToArray() method which ultimately call the refresh method only when you have some change in your ArrayList.
FYI : I did it in my project and I went for second option.

Categories