using LayoutClickListener to terminary replace components - java

I have grid layout witch some fields added like that:
private Component userDetailsTab(final User user) {
final GridLayout details = new GridLayout(2, 1);
details.setMargin(true);
details.setSpacing(true);
details.addComponent(createDetailLabel(Messages.User_Name));
final Component username = createDetailValue(user.getName());
details.addComponent(username);
...
I have also Layout click listener which replace labels on text field, it looks like that:
final TextField tf = new TextField();
details.addListener(new LayoutClickListener() {
private static final long serialVersionUID = -7374243623325736476L;
#Override
public void layoutClick(LayoutClickEvent event) {
Component com = event.getChildComponent();
if (event.getChildComponent() instanceof Label) {
Label label = (Label)event.getChildComponent();
details.replaceComponent(com, tf);
tf.setValue(label.getValue());
}
}
});
In future I want to enable click on label, edit it and write changes to database after clicking somewhere else (on different label for example).
Now when I click on 1st label and then on 2nd label, effect is: 1st has value of 2nd and 2nd is text field witch value of 2nd. Why it's going that way? What should i do to after clicking on 1st and then 2nd get 1st label witch value of 1st?

You don't need to swap between Labels and TextFields, you can just use a TextField and style it look like a Label when it's not focused.

When I tried to create click-to-edit labels, it created a ton of extra work for me. I'd discourage it (and do as Patton suggests in the comments).
However, if you're going to insist on trying to create in-place editing, you will want to do the following:
Create a new class that extends a layout (e.g. HorizontalLayout), which can swap out a label for a text field
use LayoutClickListener to removeComponent(myLabel) and addComponent(myTextField)
use BlurListener to swap back to the label
use ValueChangeListener on the text field to copy its value to the label
This is a still a bad idea because:
Users cannot see affordances as easily (they can't tell what's editable)
Users cannot use the keyboard to tab to the field they want to edit
It adds unncessary complexity (maintenance time, etc).
I would recommend, if you want in-place editing, just show the text field, and save the new value with the BlurListener.

Related

Description tooltips for Vaadin Grid header cells

I'd like to define descriptions for Grid header cells, similarly to how AbstractComponent.setDescription(String description) works (i.e. tooltip shown on mouse hover). As the Grid doesn't support this in itself, I tried adding a Label component into the header cell, and then use setDescription() on the label. I can get the info tooltip working like this, but the downside is that clicking on the label component doesn't trigger sorting. If I want to sort the column, I need to click the header cell on the really narrow area that's left between the right edge of the label component and the column border, where the sorting indicator will be shown. If you look at the screenshot below, the highlighted area is the label component, and in order to trigger sorting, the user needs to click on the space on the right side of the component.
Is there a better way to apply descriptions to header cells than the one I described? And if not, is there a way to make the sorting work properly when the header cell contains a Component?
Based on the answer from kukis, I managed to come up with a simpler solution that doesn't require any JavaScript. Instead of adding a Label component into the header cell, I'm adding a div element manually with StaticCell.setHtml(), and setting the title attribute on it:
#Override
protected void init(VaadinRequest request) {
Grid grid = new Grid();
grid.addColumn("to");
grid.addColumn("the");
grid.addColumn("moon");
Grid.HeaderRow headerRow = grid.getDefaultHeaderRow();
headerRow.getCell("to").setHtml("<div title='Hello world'>to</div>");
headerRow.getCell("the").setHtml("<div title='Hello world 2'>the</div>");
headerRow.getCell("moon").setHtml("<div title='Hello world 3'>moon</div>");
grid.addRow("1","2","3");
grid.addRow("d","v","w");
grid.addRow("g","s","h");
setContent(new VerticalLayout(grid));
}
Feature added to Vaadin 8.4.0
Feature added to Grid in Vaadin 8.4.0.
Ticket:
https://github.com/vaadin/framework/pull/10489
Release notes:
https://vaadin.com/download/release/8.4/8.4.0/release-notes.html
Grid headers and footers now support tooltips.
Well, since Grid doesn't support it by itself you can always use JavaScript to achieve desired behaviour. SSCCE:
private final String SCRIPT;
{
StringBuilder b = new StringBuilder();
b.append("var grid = document.getElementById('mygrid');\n");
b.append("var child = grid.getElementsByClassName('v-grid-tablewrapper')[0];\n");
b.append("child = child.firstChild.firstChild.firstChild;\n");
b.append("child.childNodes[0].title='Hello world';\n");
b.append("child.childNodes[1].title='Hello world 2';\n");
b.append("child.childNodes[2].title='Hello world 3';\n");
SCRIPT = b.toString();
}
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
Grid grid = new Grid();
grid.addColumn("to");
grid.addColumn("the");
grid.addColumn("moon");
grid.addRow("1","2","3");
grid.addRow("d","v","w");
grid.addRow("g","s","h");
grid.setId("mygrid");
setContent(layout);
layout.addComponent(grid);
JavaScript.getCurrent().execute(SCRIPT);
}
Another possibility would be to develop your own Grid in GWT based on the Grid provided by Vaadin Team but it is a way higher cost approach.
Another solution would be to, as you have tried, put label in a column and propagate the label-clicked-event to the Grid.
I use my own utillity finction:
public static Grid setHeaderCellDescription(Grid grid, int rowIndex, String property, String description) {
Grid.HeaderCell cell;
String cellHeader = "<span title=\"%s\">%s</span>";
cell = grid.getHeaderRow(rowIndex).getCell(property);
cell.setHtml(String.format(cellHeader, description, cell.getText()));
return grid;
}
You may add some additional checks if need (existing of cell and row number).
Or other variant - instead setHtml use cetComponent.
Grid.HeaderCell cell = grid.getHeaderRow(rowIndex).getCell(property);
Label newLabel = new Label(cell.getText());
newLabel.setDescription(description);
cell.setComponent(newLabel);
Update for Vaadin 23: you can use your own Component as a column header with this method: com.vaadin.flow.component.grid.Grid.Column#setHeader(com.vaadin.flow.component.Component).
So you can use e.g. a Span with a title:
Span headerComponent = new Span();
headerComponent.setText("Your header text");
headerComponent.getElement().setProperty("title", "Your tooltip text");
column.setHeader(headerComponent);

How to make a textarea filled with text (label) every time the button pressed?

I'm trying to make a text area record that every time the button is press, it means that it has been recorded and should be showing record1, record2, record3, etc. on it.
My goal is that, every button is pressed it will add text to the text area with different text label so that no redundancy.
I tried it with my own with this:
private void btnReqstRefreshActionPerformed(java.awt.event.ActionEvent evt) {
JLabel labelthis = new JLabel("record1");
label.setSize(label.getPreferredSize());
TextArea1.add(label);
TextArea1.revalidate();
TextArea1.repaint();
}
I know it is wrong, but is it possible?
text area is like a mini text editor - you add text to it not other components. Instead of adding labels - just add the text. Something like:
TextArea1.setText(TextArea1.getText() + "record1")
This should append record1 to the existing text in the text area.
According to my experience this is possible.
`private void btnReqstRefreshActionPerformed(java.awt.event.ActionEvent evt) {
i++;//i class level variable(static) to avoid redundancy
//labelThis initialized earlier should be accessible here
String oldText = labelThis.getText().toString();
oldText += "record "+i;
labelThis.setSize(labelThis.getPreferredSize());
TextArea1.add(labelThis);
TextArea1.revalidate();
TextArea1.repaint();
}`

JTextField show '...' when content is too long

I'm trying to make JTextField display dots when its content is longer then display area. I would like to have the same behaviour like in JTable, where when I resize column the text inside changes - when its to long only begining of it is displayed and then there are three dots (to see what I have in mind please run first example from this link and change column size - I'm not allowed to post images because I'm new here;) )
Is is possible? Only solution that I have in mind is extending JTextField with a class that will have additional field oryginalText and will behave like that (didn't test it, it's just a proposal, dimension of the JtextField will not change):
import javax.swing.JTextField;
public class MyTextField extends JTextField {
private String oryginalText;
private int length;
#Override
public void setText(String text) {
oryginalText = text;
if (oryginalText.length() > length)
super.setText(oryginalText.substring(0, length - 2) + "..");
else
super.setText(oryginalText);
}
}
any ideas?
Over your idea of extending JTextField and storing the original (non trimmed) value:
Show the textfield as disabled (or not editable) and with trimmed text. When the user clics the textfield make it enabled/editable and show the whole original text.
Then again when the user press enter or the focus exits of the textfield: disable/not editable and trimmed text.

Example text in JTextField

I am looking for a way to put example text into a swing JTextField and have it grayed out. The example text should then disappear as soon as any thing is entered into that text field. Some what similar to what stackoverflow does when a user is posting a question with the title field.
I would like it if it was already a extended implementation of JTextField so that I can just drop it in as a simple replacement. Anything from swingx would work. I guess if there is not an easy way to do this my option will probably be to override the paint method of JTextField do something that way maybe.
Thanks
The Text Prompt class provides the required functionality without using a custom JTextField.
It allows you to specify a prompt that is displayed when the text field is empty. As soon as you type text the prompt is removed.
The prompt is actually a JLabel so you can customize the font, style, colour, transparency etc..:
JTextField tf7 = new JTextField(10);
TextPrompt tp7 = new TextPrompt("First Name", tf7);
tp7.setForeground( Color.RED );
Some examples of customizing the look of the prompt:
If you can use external librairies, the Swing components from Jide software have what you are looking for; it's called LabeledTextField (javadoc) and it's part of the JIDE Common Layer (Open Source Project) - which is free. It's doing what mklhmnn suggested.
How about initialize the text field with default text and give it a focus listener such that when focus is gained, if the text .equals the default text, call selectAll() on the JTextField.
Rather than overriding, put a value in the field and add a KeyListener that would remove the value when a key stroke is registered. Maybe also have it change the foreground.
You could wrap this up into your own custom JTextField class that would take the default text in a constructor.
private JLabel l;
JPromptTextField(String prompt) {
l = new JLabel(prompt, SwingConstants.CENTER);
l.setForeground(Color.GRAY);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (this.getText().length() == 0) {
// Reshape the label if needed, then paint
final Rectangle mine = this.getBounds();
final Rectangle its = l.getBounds();
boolean resized = (mine.width != its.width) || (mine.height != its.height);
boolean moved = (mine.x != its.x) || (mine.y != its.y);
if (resized || moved)
l.setBounds(mine);
l.paint(g);
}
}
You can't do that with a plain text field, but you can put a disabled JLabel on top of the JTextField and hide it if the text field gets the focus.
Do it like this:
Define the string with the initial text you like and set up your TextField:
String initialText = "Enter your initial text here";
jTextField1.setText(initialText);
Add a Focus Listener to your TextField, which selects the entire contents of the TextField if it still has the initial value. Anything you may type in will replace the entire contents, since it is selected.
jTextField1.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
if (jTextField1.getText().equals(initialText)) {
jTextField1.selectAll();
}
}
});

How do I use requestFocus in a Java JFrame GUI?

I am given an assignment but I am totally new to Java (I have been programming in C++ and Python for two years).
So we are doing GUI and basically we extended JFrame and added a couple fields.
Say we have a field named "Text 1" and "Text 2". When user presses enter with the cursor in Text 1, move the focus to Text 2. I tried to add
private JTextField textfield1() {
textfield1 = new JTextField();
textfield1.setPreferredSize(new Dimension(200, 20));
textfield1.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
textfield1text = textfield1.getText().trim();
textfield1.setText(textfield1text);
System.out.println(textfield1text);
textfield1.requestFocus();
}
});
return textfield1;
}
But that doesn't work at all.
I noticed that requestFocus is not recommended, and instead one should use requestFocusWindows. But I tried that too. Upon some readings it seems like I have to do keyboard action and listener? But my teacher said it only requires 1 line...
Well, you have textfield1.requestFocus(), but your description would imply you need textfield2.requestFocus(). (that's 2).
Another option might be to use:
textField1.transferFocus();
This way you don't need to know the name of the next component on the form.

Categories