I need some help to figure out how can i make one text field observable to many frames .. it's like a messaging app all frames can send to that text field and all of them must get updates when it changes
I would follow the JavaFX approach, as a JTextField does not have a model (as JTextPane does). (Adding listeners to a view component is not entirely MVC.)
Instead of updating the JTextField have a model: a StringProperty and update that. Have one Observable listener to update the JTextField, and all others to update all the frames, using addListener.
A JTextField has an underlying document that is a kind of model. To observe the text, you would do:
jTextField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
}
#Override
public void removeUpdate(DocumentEvent e) {
}
#Override
public void changedUpdate(DocumentEvent e) {
}
});
Try this as a test and you will see you just need to set the same model on all the text fields that need to have the same information.
JTextField t1 = new JTextField();
JTextField t2 = new JTextField();
PlainDocument doc = new PlainDocument();
t1.setDocument(doc);
t2.setDocument(doc);
setLayout(new GridLayout(0, 1));
add(t1);
add(t2);
Related
I have a JPanel holding a JButton and JScrollPane (in turn holding a JTable) and am currently running into two issues which I believe are related:
The JButton listener's actionPerformed() method is not invoked upon click. The only way in which I can get it to be invoked is by calling doClick() on the JButton. The JButton color changes upon hover but no click animation is shown when the mouse is pressed.
Secondly, if a cell is clicked within the JTable, the cell located 2 rows down in the same column registers the click instead. This offset does not occur when clicking in the column headers (i.e. to adjust cell widths), only when within the cell area.
Left-hand panel. Click position circled
public class InventoryPanel extends JPanel {
// Parent Business object reference for communication and JFrame
private Business parent;
private AddItemPanel addItemPanel;
// Inventory table items
private DefaultTableModel inventoryModel;
private JTable inventoryTable;
private JScrollPane inventoryScrollPane;
private JLabel updateLbl;
private JButton addItemBtn;
// Columns for inventory table
private static final String[] INVENTORY_COLUMNS = {"Item","Stock","Restocking Level","Edit"};
public InventoryPanel(Business parent) {
this.parent = parent;
initGUI();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
//doStuff
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace(new PrintStream(System.out));
}
}
}
}).start();
}
// INITIALISES GUI
public void initGUI() {
this.setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
JLabel titleLabel = new JLabel("<html><B>Inventory</B></html>");
this.add(titleLabel);
// Create empty inventory table
inventoryModel = new DefaultTableModel(new Object[3][4],INVENTORY_COLUMNS);
inventoryTable = new JTable(inventoryModel);
inventoryScrollPane = new JScrollPane(inventoryTable);
// Create button to allow items to be added
addItemBtn = new JButton("Add item");
addItemBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("ADD ITEM PRESSED");
}
});
updateLbl = new JLabel("Loading inventory...");
this.add(addItemBtn);
this.add(inventoryScrollPane);
this.add(updateLbl);
}
I've tried removing the table from the panel to see if that solves the JButton issue and visa-versa, but no luck. I've also tried changing the project JDK but no luck there either.
There are other JPanels adjacent to the troublesome one in a JFrame which work perfectly fine. Any ideas?
Edit: I can create a working instance of the InventoryPanel alone in a frame in another project, as mentioned in the comments. However the exact same code (no calls being made to other objects/methods) in the current project now produces ClassCastExceptions. After some googling this seems to be due to non-EDT threads updating the GUI.
However there is no use of the Business class, and all GUI operations are performed using the SwingUtilities.invokeLater() method like so:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("test");
frame.add(new InventoryPanel());
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
Note: the no-argument constructor InventoryPanel() just calls initGUI().
Thanks for the help so far...still very confused by this.
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.
I've just taken up playing with GUIs, and I'm experimenting with getting text input from the user, and assigning it to a variable for later use.
Easy, I thought. Wrong, I was.
I wanted my frame to look something like:
public class firstFrame extends JFrame {
JTextField f1 = new JTextField();
String text;
public firstFrame(String title) {
super(title);
setLayout(new BorderLayout());
Container c = getContentPane();
c.add(f1);
text = f1.getText();
System.out.println(text);
}
}
Where the variable text would get whatever text the user typed in, then print it out to the console. Simple.
I've got a feeling I'm missing something pretty fundamental here, and would appreciate it if anyone could fill me in on what that something is.
The variable won't be updated until an event occurs on the component. For this a DocumentListener or ActionListener can be used
f1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String text = f1.getText();
...
}
});
getText() only get the text that is in the JTextArea at the time it is called.
You are calling it in the constructor. So when you instantiate new firstFrame, there is no initiital text.
One thing to keep in mind is that GUIs are event driven, meaning you need an event handler to capture and process events.
One option is to add an ActionListener to the JTextField so when you press Enter after entering text, the text will print.
f1.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
String text = f1.getText();
System.out.println(text);
}
});
See more at how to Create GUI with Swing and Writing Event Listeners
I have successfully integrated the FCKEditor in swing application.
Now I am trying to achieve that:
1>When the user click in the editing area, an event is to be fired, taking its id.(might use javascript but donot know how to configure in swing).
2>Then that id is to be shown in a jlabel. So, i want to communicate the native editor with swing application.
I tried a lot but without any major success.
special vote of thanks for any help.
As i understand your editor is JPanel.
You can try to add MouseListener to your FCKEditor for the next way:
public class Example extends JFrame {
private JLabel yourLabel;
public Example() {
yourLabel = new JLabel("test");
JPanel component = new JPanel();
component.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
String id = getIDMethod();
//if your editor contains id you can use next code
//String id = ((JPanel)e.getSource()).getIDMethod();
yourLabel.setText(id);
}
});
getContentPane().add(component,BorderLayout.SOUTH);
getContentPane().add(yourLabel,BorderLayout.NORTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public static void main(String...strings ){
Example e = new Example();
}
protected String getIDMethod() {
return "1";
}
}
Here component - it's your editor. You add MouseListener for that. Next in method mouseReleased you get ID and set it to the label(here yourLabel your target label).
Try this code, I think it's help you
I have a screen in which one of its components is made invisible depending on a boolean value. If the boolean changes after the screen has been created, how do I refresh the screen to take this into account?
I think revalidate() is more appropriate here if you are dealing with JComponents.
From the JavaDoc:
Supports deferred automatic layout.
Calls invalidate and then adds this component's validateRoot to a list of components that need to be validated. Validation will occur after all currently pending events have been dispatched. In other words after this method is called, the first validateRoot (if any) found when walking up the containment hierarchy of this component will be validated. By default, JRootPane, JScrollPane, and JTextField return true from isValidateRoot.
This method will automatically be called on this component when a property value changes such that size, location, or internal layout of this component has been affected. This automatic updating differs from the AWT because programs generally no longer need to invoke validate to get the contents of the GUI to update.
Call the validate() method on the container that needs to be laid out -- probably your window's content pane.
Try calling repaint() which in turn will call paintComponent().
I thought that (with Java 6?) you need not do anything... This should happen automatically - no?
With the following example, it does happen automatically...
public class TT extends JFrame
{
public TT()
{
setLayout(new FlowLayout());
JLabel label = new JLabel();
label.setText("Label:");
add(label);
final JTextField textField = new JTextField();
add(textField);
JButton button = new JButton();
button.setText("Button");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if (textField.isVisible())
{
textField.setVisible(false);
}
else
{
textField.setVisible(true);
}
}
});
add(button);
setSize(100,100);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
TT frame = new TT();
frame.setDefaultCloseOperation(TT.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
[Add] And using a layout manager like GridBagLayout would also solve the problem of "Re-Laying out" the page.