JComboBox to display multiple lines of text - java

I'm currently writing a small tool for sending sql queries to a database and recieving the according data.
Now to my problem:
I want to allow the user to enter a new search query or select from a "latest" list, where the last few queries are saved.
For that, I planned on using an editable JComboBox, but I'm having trouble diplaying multiple lines of text in the box itself.
The reason I want to do that, is because sql queries can get quite long and since I want make the box editable and at the same time keep the frame clean.
I've found ways to display multiple lines in the dropdown menu, but nothing for the box itself.
Thank you in advance and please forgive me if I overlooked something simple ;)
Greetings
Zeus

Extended editing functionality is supplied by the ComboBoxEditor, this allows you to define the actual component which is used as the combobox's editor
Based on your requirements, you're going to need (at the very least) a JTextArea, to provide (optionally) word wrapping and multiple lines
A rough and ready example might look something like this...
public class TextAreaComboBoxEditor implements ComboBoxEditor {
private JTextArea ta = new JTextArea(4, 20);
private JScrollPane sp = new JScrollPane(ta);
public TextAreaComboBoxEditor() {
ta.setWrapStyleWord(true);
ta.setLineWrap(true);
}
#Override
public Component getEditorComponent() {
return sp;
}
#Override
public void setItem(Object anObject) {
if (anObject instanceof String) {
ta.setText((String) anObject);
} else {
ta.setText(null);
}
}
#Override
public Object getItem() {
return ta.getText();
}
#Override
public void selectAll() {
ta.selectAll();
}
#Override
public void addActionListener(ActionListener l) {
}
#Override
public void removeActionListener(ActionListener l) {
}
}
This doesn't support ActionListener, as JTextArea uses the Enter key for it's own purposes. If you wanted to, you could use the key bindings API to add your own Action that can trigger the ActionListeners, for that, you'd need to supply a List or other means for managing them so you can call them back

Related

How do I build a JMenu dynamically (and not merely run-time creation)?

To be clear, the several similar-appearing entries here DO NOT actually talk about building a menu dynamically since all their object name choices and such are already in their code as fixed strings already written in the source code; all they're doing is waiting until run-time to create their statically designed menu items. Here are two entries I found like that: One and Two. The concerns there merely had to do with the trivial (but vital) task of refreshing the display, NOT with anything like actual dynamic creation of content.
What I want to do, in sharp contrast, is to truly add dynamically: I want the user to be able to choose to add items to a sub-menu that they can then later select and have take action within the application.
Let's take the case of simply adding an integer value to a menu and then being able to select it later, similar to what can easily be done with a combo-box but instead done with a menu.
The problem isn't the syntax pertaining to defining, for example, a MenuListener that will point to a method that knows how to act, that's not the problem. Rather, I just don't know enough about the dynamic NAMING SPACE, and how to "de-reference" a String, for example, as an object name. Bluntly, how do I dynamically name my new objects that I didn't anticipate creating (not in kind but in number)? IOW, how do I take a cleverly constructed string that actually contains code I want run and then ask Java to run it? What's the Java syntax for that? Maybe the problem can be reduced to just object names; Say, the name comes as a string I can construct; how do use that in my JMenuItem declaration? ...I know how to do this in BASH, but how is this done in Java?
(I'm hoping I don't have to create it as a file, compile it, and somehow attach the class file(s) to my running program and then run it - DAMN that would be cumbersome!)
Thanks.
If I understand your overall intent, then I would recommend starting with the Actions API which be used to create independent units of work which are independent of how they are displayed.
This allows you to define re-usable (or in your case, dynamic) operations, which can be executed via menus, toolbars, buttons and even key bindings out of the box.
Because setting up a Action can be a little tedious, I might consider using a builder pattern, but you don't have to, you can build them manually if you wish ;)
public class ActionBuilder {
private ActioBuilderAction action;
public ActionBuilder() {
action = new ActionBuilder.ActioBuilderAction();
}
public ActionBuilder toolTip(String text) {
action.putValue(Action.SHORT_DESCRIPTION, text);
return this;
}
public ActionBuilder command(String text) {
action.putValue(Action.ACTION_COMMAND_KEY, text);
return this;
}
public ActionBuilder mnemonic(int key) {
action.putValue(Action.MNEMONIC_KEY, key);
return this;
}
public ActionBuilder displayedMnemonicIndex(int index) {
action.putValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY, index);
return this;
}
public ActionBuilder text(String text) {
action.putValue(Action.NAME, text);
return this;
}
public ActionBuilder smallIcon(Icon icon) {
action.putValue(Action.SMALL_ICON, icon);
return this;
}
public ActionBuilder largeIcon(Icon icon) {
action.putValue(Action.LARGE_ICON_KEY, icon);
return this;
}
public ActionBuilder acceleratorKey(KeyStroke ks) {
action.putValue(Action.ACCELERATOR_KEY, ks);
return this;
}
public ActionBuilder actionListener(ActionListener listener) {
action.setListener(listener);
}
public Action build() {
return action;
}
public class ActioBuilderAction extends AbstractAction {
private ActionListener listener;
public void setListener(ActionListener listener) {
this.listener = listener;
}
#Override
public void actionPerformed(ActionEvent e) {
if (listener != null) {
listener.actionPerformed(e);
}
}
}
}
Then, you could simply build a new menu something like...
Action action = new ActionBuilder().text("Super awesome command").actionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Super aweseom comand GO!");
}
}).build();
JMenuItem mi = new JMenuItem(action);
Now, I imagine, you might have a "command executor" class of some kind, which would. physically execute the command. I'd create a bridging class which implemented ActionListener and when it's called, would then execute the specified command
public class CommandListener implements ActionListener {
private String command;
public CommandListener(String command) {
this.command = command;
}
#Override
public void actionPerformed(ActionEvent e) {
CommandExecutor executor = new CommandExecutor();
executor.execute(command)
}
}
This could then be used in place of the ActionListener in the first example...
Action action = new ActionBuilder().text(commandName).actionListener(new CommandListener(command)).build();
As an overall idea

How MVC work with java swing GUI

Lets say I have a swing GUI which has textfeild and button. When I click button I want to save that value in text in db and return joptionpane "success" message.
The way I used to do this is
Model : JDBC class
View : GUI : In that button's 'action performed' action I call save method with parameter.
Controller con = new Controller();
con.save(text1.getText());
Controller : Write a save method.
JDBC db = new
public void save(jTextfeild text){
text= text1.getText();
boolean b= db.putData("insert into .. values(text)");
if(b){
JOptionPane("Success");
}
}
This is how I started. But later I understood this is not how this should be and this is utterly unsafe and stupid.
I really want to learn how to do this in MVC properly. Please be kind enough to explain this to with a small example. Thank you for your time.
This is a difficult subject to grasp in something like Swing, which already uses a form of MVC, albeit more like VC-M, where the model is separated from the view and controller, but where the view and controller are combined.
Think about a JButton, you don't supply a controller to manage how it's triggered when a user presses a key or clicks on it with the mouse, this is done internally and you are notified about the actions when the occur.
With this in mind, you need to allow the view to be semi self managed. For instance, based on your requirements, the view would have a button and text field.
The view itself would manage the interactions between the user and the button itself (maintain a internal ActionListener for example), but would then provide notifications to the controller about any state changes that the controller might be interested in.
In a more pure sense of a MVC, the view and model won't know anything about each other and the controller would manage them. This is a little contradictive to how Swing works, as Swing allows you to pass the model directly to the view, see just about any Swing component.
This doesn't mean that you can't make things work, but you need to know where the concept can falter or needs to be "massaged" to work better.
Normally, when I approach these type of things, I take step back and look at much wider picture, for example.
You have a view which can accept text and produce text or changes to it
You have a model which can load and modify text, but provides little other events
You have a controller which wants to get text from the model and supply it to the view and monitor for changes to the text by the view and update them within the model
Now, MVC works REALLY well with the concept of "code to interfaces (not implementation)", to that extent, I tend to start with the contracts...
View contract...
public interface TextView {
public void setText(String text);
public String getText();
public void addTextViewObserver(TextViewObserver observer);
public void removeTextViewObserver(TextViewObserver observer);
}
public interface TextViewObserver {
public void textWasChanged(TextView view);
}
Now, one of the requirements of the view is to generate events when the text has changed in some meaningful way, to this end, I've used a simple observer pattern to implement. Now you could argue that the controller is the observer, but to my mind, the controller may have functionality that I don't want to expose to the view (like the model for instance)
Model contract...
Next comes the model...
public interface TextModel {
public String getText();
public void setText(String text);
}
pretty simple really. Now, you might consider adding some kind of Exception to these methods to allow the model the ability to fail for some reason, but the Exception should be as generic as you can make it (or even a custom Exception), so that you can replace the implementation should you need to
Controller contract...
And finally, the controller...
public interface TextViewController {
public TextView getTextView();
public TextModel getTextModel();
}
again, pretty simple. You might have a more complex requirement for your controller, but for this example, this is about all we really need.
Implementations...
View...
public class TextViewPane extends JPanel implements TextView {
private JTextField textField;
private JButton updateButton;
private List<TextViewObserver> observers;
public TextViewPane() {
observers = new ArrayList<>(25);
textField = new JTextField(25);
updateButton = new JButton("Update");
updateButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fireTextWasChanged();
}
});
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(textField, gbc);
add(updateButton, gbc);
}
#Override
public void setText(String text) {
textField.setText(text);
}
#Override
public String getText() {
return textField.getText();
}
#Override
public void addTextViewObserver(TextViewObserver observer) {
observers.add(observer);
}
#Override
public void removeTextViewObserver(TextViewObserver observer) {
observers.remove(observer);
}
protected void fireTextWasChanged() {
for (TextViewObserver observer : observers) {
observer.textWasChanged(this);
}
}
}
Model...
public class SimpleTextModel implements TextModel {
private String text = "This is some text";
#Override
public String getText() {
return text;
}
#Override
public void setText(String text) {
this.text = text;
}
}
Controller...
public class SimpleTextController implements TextViewController, TextViewObserver {
private TextView view;
private TextModel model;
public SimpleTextController(TextView view, TextModel model) {
this.view = Objects.requireNonNull(view, "TextView can not null");
this.model = Objects.requireNonNull(model, "TextModel can not be null");
view.addTextViewObserver(this);
}
#Override
public TextView getTextView() {
return view;
}
#Override
public TextModel getTextModel() {
return model;
}
#Override
public void textWasChanged(TextView view) {
getTextModel().setText(view.getText());
}
}
Putting it together...
TextViewPane view = new TextViewPane();
TextModel model = new SimpleTextModel();
TextViewController controller = new SimpleTextController(view, model);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(view);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Now, all this is just an example of one possible solution. You could have a controller implementation which has a particular implementation of the model or view or both, for example.
The point is, you just shouldn't care. The controller doesn't care how the view is implemented, it only cares that it will generate textWasChanged events. The model doesn't care about the view at all (and visa-versa) and the controller doesn't care about model, only that it will get and set some text.
For a more complex example, you can have a look at Java and GUI - Where do ActionListeners belong according to MVC pattern?
After thoughts
This is just ONE possible way to approach the problem. For example, you could limit the view to a single observer.
You should always be thinking "can I change any one part of the MVC and will it still work?" This makes you think about the possible issues that changing any one part of the implementation might have on the surrounding contracts. You should get to the point that it simply doesn't matter how each layer is implemented
A view may act as a controller for another sub-view (or act as a container for another controller of a sub-view). This can scare people sometimes, but it's possible for a view to act as parent container for one or more sub controllers/views, this allows you to develop complex UIs
Don't expose implementation details in your contracts, for example, the model shouldn't throw a SQLException, as another implementation might not be based on a SQL based solution. Don't expose UI elements, this means that ALL implementations would then need to implement those elements. What happens if I want a implementation of the view that presents a JComboBox to the user instead of JTextField? This is also the reason I don't use a ActionListener in the view contract, because I have no idea how a textWasChanged event might actually be generated by an implementation of the view

JTable Row filtering by JTextField value

I enter a name on my JTextfield , But my table don't filter any thing!
My code:
public class UserPage_Admin extends JFrame {
JTable table;
UserModel model;
public UserPage_Admin() {
model = new UserModel(...);
TableRowSorter sorter = new TableRowSorter<TableModel>(model);
table = new JTable(model);
table.setRowSorter(sorter);
add(new JScrollPane(table), BorderLayout.CENTER);
add(panelForm(), BorderLayout.PAGE_START);
RowFilter<UserModel, Object> rf = null;
try {
rf = RowFilter.regexFilter(filterTF.getText(), 0);
} catch (PatternSyntaxException pse) {
return;
}
sorter.setRowFilter(rf);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(850, 600);
setVisible(true);
}
you are calling RowFilter.regexFilter(filterTF.getText(), 0); in UserPage_Admin() constructor. How it supposed to read the text from the filterTF. I think you should call it from an Action Event Listener assigned to a JButton which will be called upon submitting(clicking) the text as follows:
submitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String text = filterText.getText();
if (text.length() == 0) {
sorter.setRowFilter(null);
} else {
sorter.setRowFilter(RowFilter.regexFilter(text, 0));
}
}
});
If you want to use Filtering upon user key type event, add key listener to the text field you are taking input filter-string.
filterTxtFeild.addKeyListener(new KeyAdapter() {
public void keykeyReleased(KeyEvent evt) {
// on each key type event filter.
// put your filter code as submit button
}
});
However, as it is suggested in the comments below, to work with Swing Text Component, one should have used the Document.addDocumentListener(DocumentListener). A Swing text component uses a Document to represent its content. Document events occur when the content of a document changes in any way. Add the document listener as follows:
filterTxtFeild.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
// put your filter code here upon data insertion
}
#Override
public void removeUpdate(DocumentEvent e)
{
//put your filter code here upon data removal
}
#Override
public void changedUpdate(DocumentEvent e) {}
});
Edit: Why DocumentListener is preferable ?
If we want validation of input in the data source, using KeyEvent while filtering the data you’ll find it does not reflect the user’s keystroke and input events are sent to the listeners before they are processed by the data source. suppose that when we want an user name to be entered, someone input a text like "$%^&". On such invalid input, KeyEvent will still be fired even though no valid changes has been made to data source. But, DocumentListeners are notified only when a valid changes has been made to the data source. Data entry components produce events in which a validator can listen for asynchronously, one should never modify the contents of a text component from within a DocumentListener. If we do so, the program will likely deadlock.
I enter a name on my JTextfield , But my table don't filter any thing!
there are two ways, you don't mentioned expected logics
filtering on KeyTyped from DocumentListener (your code talking about ???)
from ActionListener invoked from ENTER Key
both a.m. ways added to JTextField
then there are another two very important options
filtering in whole JTables, columns and rows (your code talking about ???)
in one (quite possible in two or more, never tried) columns
everything depends of your goal
everything by using standard methods implemented in API
You simply fail to use sorter after initializing it. You should call JTable.setRowSorter().

Document not updating for combo box Java

I am writing Bing/Google instant search kind of feature in combo box, so this combo box provides suggestions to the user based on what he has typed. The program works like a charm but their is one bug that I am unable to figure out how to solve. The problem is, the first character typed is recognised once the second the character has been typed, same goes for other position of characters too.
Here is the code:
public MyClass extends JFrame
{
private Document doc;
public MyCode()
{
comboxBox= new JComboBox();
Handler handle = new Handler();
JTextComponent comp = (JTextComponent) comboBox.getEditor().getEditorComponent();
doc = comp.getDocument().addDocumentListener(handle);
comboBox.addKeyListener(handle);
}
private class Handler implements DocumentListener,KeyListener
{
String dataTobeSearched= "";
#Override
public void changedUpdate(DocumentEvent event) {
try
{
dataTobeSearched = doc.getText(0, doc.getLength());
System.out.println("Data to be searched "+dataTobeSearched);
}
catch(Exception e)
{
e.printStackTrace();
}
}
#Override
public void keyPressed(KeyEvent event) {
changedUpdate(null);
}
}
What am I doing wrong?
I added the keyListener to the combobox editor because the DocumentListener wasn't getting invoked when something was being typed in the combobox? If there is an other easy alternative to this, then please share it.
How can I solve the above stated problem?
Wrap the call inside changedUpdate() in SwingUtilities.invokeLater()
According to the Java tutorial on Oracle website, changedUpdate() method will not work for plain text documents. If this is your case, use insertUpdate() and/or removeUpdate().
The recommendation of using SwingUtilities inside the method is still valid.

How do I access the source of an ActionEvent when the ActionListener is located in a different class?

I can't get my head round this one. I've tried to adhere to the MVC pattern for the first time and now have difficulties accessing the source of an ActionEvent because the ActionListener is located in a different class. But let the code do the talking...
In the "view":
// ControlForms.java
...
private JPanel createSearchPanel() throws SQLException {
...
comboBoxCode = new JComboBox(); // Field comboBoxCode -> JComboBox()
SwingUtilities.invokeLater(new Runnable() {
public void run() {
AutoCompleteSupport<Object> support = AutoCompleteSupport.install(
comboBoxCode, GlazedLists.eventListOf(jnlCodeArray));
}
}); // Auto-Complete comboBox from GlazedLists
...
public void setComboListener(ComboListener comboListener) {
comboBoxCode.addActionListener(comboListener);
}
...
}
Then, in what I term the controller, I have two different classes:
// Controller.java
public MyController() throws SQLException {
...
addListeners();
}
...
private void addListeners(){
View view = getView();
getView().getControlForm().setComboListener(new ComboListener());
}
and
public class ComboListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("ComboBox listened to! e = " + e.toString());
}
}
Now, e obviously doesn't give the name of the variable (which at the moment I wish it would), so I cannot if test for e.getSource().
My question is thus: is there either a) a way to query (via if for example) the source of e, or b) a less complicated way to get to the variable name?
Many, many thanks in advance for your insights and tips!
Why do you need the name of the variable? Why can't you do the event handling like this
public class ComboListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
JComboBox source = (JComboBox)e.getSource();
//do processing here
}
}
I'd think that if you need to do processing according the variable name, obviously you need different listeners for different combo boxes.
Generally, there are only two situations in which you should use a listener like that: a) you're going to handle a certain event the same way for a bunch of objects, or b) you're only going to use the listener for one object. In the latter case, I'd prefer handling the event locally anyway.
That said, the direct answer to your question is: you shouldn't have to check inside your ActionListener implementation to see whether the appropriate object is the source of the event; you should simply only add the ActionListener to that one object.
One final note: without knowing the specifics of your architecture... generally, MVC will treat all event handling as part of the View (it reduces coupling) and the View will pass commands or method calls or your own events (i.e., not Swing's) to the Controller.

Categories