By refreshing the items within a grid sometimes it happen that the grid shows completely crazy:
That's how I update the data every time. The instance of the Grid stays the same:
dataProvider = new ListDataProvider<>(newItems);
grid.setItems(dataProvider);
Does someone have an idea whether I do something wrong or there is a bug within Vaadin?
Complete code:
if (!columnsIntialized) {
for (Method method : gridProperties) {
Column<T> column = grid.addColumn(data -> {
Object value = method.invoke(data);
return getFormattedValue(value, method.getReturnType());
});
String resourceKey = method.getDeclaredAnnotation(GridProperties.class).resourceKey();
column.setKey(resourceKey);
column.setHeader(AppResources.getString(resourceKey));
int width = method.getDeclaredAnnotation(GridProperties.class).width();
if (width == -1) {
column.setAutoWidth(true);
} else {
column.setWidth(width + "px");
}
}
columnsIntialized = true;
}
dataProvider = new ListDataProvider<>(items);
grid.setItems(dataProvider);
grid.recalculateColumnWidths();
Vaadin 22.0.3 is scheduled to be released on Monday with the fix.
i want my joptionpane can combine with combobox,and the combobox data is in database, how i managed that.
i've tried change but the red code always show
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String wel = sdf.format(cal1.getDate());
String NamaFile = "/report/harianMasuk.jasper";
HashMap hash = new HashMap();
String tak = JOptionPane.showOptionDialog(null,id.getSelectedIndex()-1,"Laporan Supplier",JOptionPane.QUESTION_MESSAGE);
try {
hash.put("til", wel);
hash.put("rul", tak);
runReportDefault(NamaFile, hash);
} catch (Exception e) {
JOptionPane.showMessageDialog(rootPane, e);
}
Read the section from the Swing tutorial on Getting User Input From a Dialog.
It demonstrates how to display a combo box in a JOptionPane.
Not exactly sure what you are trying to accomplish but it appears to be that you want to utilize a JComboBox within a JOptionPane dialog window. This ComboBox would be filled with specific data from your database. The User is to select from this ComboBox and your application continues processing based on that selection. If this is the case then you might want to try something like this:
String selectedItem = "";
int selectedItemIndex = -1;
/* Ensure dialog never hides behind anything (use if
the keyword 'this' can not be used or there is no
object to reference as parent for the dialog). */
JFrame iframe = new JFrame();
iframe.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
iframe.setAlwaysOnTop(true);
// ---------------------------------------------------
int btns = JOptionPane.OK_CANCEL_OPTION;
String dialogMessage = "<html>Select the desired item from the Drop-Down "
+ "list<br>you want to work with:<br><br></html>";
String dialogTitle = "Your Fav Items";
/* Up to you to gather what you want placed into the
JComboBox that will be displayed within the JOptionPane. */
String[] comboBoxItems = {"Your", "DB", "Items", "You", "Want", "To",
"Add", "To", "ComboBox"};
BorderLayout layout = new BorderLayout();
JPanel topPanel = new JPanel(layout);
JLabel label = new JLabel(dialogMessage);
topPanel.add(label, BorderLayout.NORTH);
JPanel centerPanel = new JPanel(new BorderLayout(5, 5));
JComboBox cb = new JComboBox();
cb.setModel(new DefaultComboBoxModel<>(comboBoxItems));
cb.setSelectedIndex(-1);
centerPanel.add(cb, BorderLayout.CENTER);
topPanel.add(centerPanel);
// Ensure a selection or Cancel (or dialog close)
while (selectedItemIndex < 0) {
int res = JOptionPane.showConfirmDialog(iframe, topPanel, dialogTitle, btns);
if (res == 2) {
selectedItem = "Selection Option Was Canceled!";
break;
}
selectedItemIndex = cb.getSelectedIndex();
if (res == JOptionPane.OK_OPTION) {
if (selectedItemIndex == -1) {
JOptionPane.showMessageDialog(iframe, "<html>You <b>must</b> "
+ "select something or select <font color=red><b>Cancel</b></font>.",
"Invalid Selection...", JOptionPane.WARNING_MESSAGE);
}
else {
selectedItem = cb.getSelectedItem().toString();
}
}
iframe.dispose();
}
JOptionPane.showMessageDialog(iframe, "<html>You selected the ComboBox item:"
+ "<br><br><b><font color=blue><center>" + selectedItem + "</center>"
+ "</font></b><br></html>", "Selected Item", JOptionPane.INFORMATION_MESSAGE);
iframe.dispose();
With the above code, the Input dialog that will be displayed would look something like this:
It is up to you to find the means to fill the comboBoxItems String Array used within the code above.
I have been trying to figure out a way to hide this tooltip when it is triggered by a function and shown in the scene. This is my function.
private void ValidateRequired(TextField field){
Tooltip errorTip = null;
if(field.getText().equals("")){
field.getStyleClass().add("errorField");
errorTip = new Tooltip("This is required");
errorTip.getStyleClass().removeAll();
Scene scene = field.getScene();
scene.getStylesheets().add(this.getClass().getResource("../css/sale.css").toExternalForm());
errorTip.getStyleClass().add("errorTip");
Point2D p = field.localToScene(0.0, 0.0);
errorTip.show(field,p.getX()
+ field.getScene().getX() + field.getScene().getWindow().getX(), p.getY()
+ field.getScene().getY() + field.getScene().getWindow().getY()+field.getHeight()+2);
}
else{
errorTip.hide();
}
}
This function is called when Textfield lose focus. This function get called by the following listener.
currentField.focusedProperty().addListener((ov, oldV, newV) -> {
if (!newV) {
ValidateRequired(currentField);
}
else{
}
});
You are creating a new Tooltip every time the ValidateRequired method (BTW please use proper naming conventions) is called. So when the method is called with non-empty text, you are not hiding the same tooltip you previously showed (and so the previously-showed one remains shown).
Instead, create one tooltip and show/hide it:
private final Tooltip errorTip = new Tooltip();
// ...
private void ValidateRequired(TextField field){
if(field.getText().equals("")){
field.getStyleClass().add("errorField");
errorTip.setText("This is required");
errorTip.getStyleClass().removeAll();
Scene scene = field.getScene();
scene.getStylesheets().add(this.getClass().getResource("../css/sale.css").toExternalForm());
errorTip.getStyleClass().add("errorTip");
Point2D p = field.localToScene(0.0, 0.0);
errorTip.show(field,p.getX()
+ field.getScene().getX() + field.getScene().getWindow().getX(), p.getY()
+ field.getScene().getY() + field.getScene().getWindow().getY()+field.getHeight()+2);
}
else{
errorTip.setText("");
errorTip.hide();
}
}
My app features an InfiniteScrollAdapter populated with images through URLImage and URLImage.ImageAdapter.
In the simulator (Iphone3GS or Xoom or GoogleNexus7), and NPE is shown the first time the InfiniteScrollAdapter appears, although the file does exist on the server.
Please note : In this test there was only one entry in the database. So on the image below what you should see is the same row (image + text) duplicated 3 times.
Please note that the order in the undisplayed icon can differ
The code I used to download the image is :
Image tempPlaceholder = Image.createImage(
ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX,
ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX,
ParametresGeneraux.accentColor);
Graphics gr = tempPlaceholder.getGraphics();
gr.setAntiAliased(true);
gr.setColor(ParametresGeneraux.accentColor);
gr.fillArc(0, 0, ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX, ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX, 0, 360);
EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);
final Image reportImage = URLImage.createToStorage(
roundPlaceholder,
photoFilenameInStorage,
currentReport.getPhotoPath(),
ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
);
And here is the overridden imageAdapter method :
public final static URLImage.ImageAdapter RESIZE_SCALE_WITH_ROUND_MASK = new URLImage.ImageAdapter() {
#Override
public EncodedImage adaptImage(EncodedImage downloadedImage, EncodedImage placeholderImage) {
final Image[] tmp = new Image[1];
if (!Display.getInstance().isEdt()) {
// The image scaling has to be called from EDT
Display.getInstance().callSeriallyAndWait(() -> {
tmp[0] = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
if (tmp[0].getWidth() > placeholderImage.getWidth()) {
int diff = tmp[0].getWidth() - placeholderImage.getWidth();
int x = diff / 2;
tmp[0] = tmp[0].subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
} else if (tmp[0].getHeight() > placeholderImage.getHeight()) {
int diff = tmp[0].getHeight() - placeholderImage.getHeight();
int y = diff / 2;
tmp[0] = tmp[0].subImage(0, y, Math.min(placeholderImage.getWidth(), tmp[0].getWidth()),
Math.min(placeholderImage.getHeight(), tmp[0].getHeight()), true);
}
});
} else {
tmp[0] = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
if (tmp[0].getWidth() > placeholderImage.getWidth()) {
int diff = tmp[0].getWidth() - placeholderImage.getWidth();
int x = diff / 2;
tmp[0] = tmp[0].subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
} else if (tmp[0].getHeight() > placeholderImage.getHeight()) {
int diff = tmp[0].getHeight() - placeholderImage.getHeight();
int y = diff / 2;
tmp[0] = tmp[0].subImage(0, y, Math.min(placeholderImage.getWidth(), tmp[0].getWidth()),
Math.min(placeholderImage.getHeight(), tmp[0].getHeight()), true);
}
}
EncodedImage[] image2Return = new EncodedImage[1];
if (!Display.getInstance().isEdt()) {
// The image scaling has to be called from EDT
Display.getInstance().callSeriallyAndWait(() -> {
Image roundMask = Image.createImage(tmp[0].getWidth(), tmp[0].getHeight(), 0xff000000);
Graphics gr = roundMask.getGraphics();
gr.setColor(0xffffff);
gr.fillArc(0, 0, tmp[0].getWidth(), tmp[0].getHeight(), 0, 360);
Object mask = roundMask.createMask();
tmp[0] = tmp[0].applyMask(mask);
image2Return[0] = EncodedImage.createFromImage(tmp[0], false);
});
} else {
Image roundMask = Image.createImage(tmp[0].getWidth(), tmp[0].getHeight(), 0xff000000);
Graphics gr = roundMask.getGraphics();
gr.setColor(0xffffff);
gr.fillArc(0, 0, tmp[0].getWidth(), tmp[0].getHeight(), 0, 360);
Object mask = roundMask.createMask();
tmp[0] = tmp[0].applyMask(mask);
image2Return[0] = EncodedImage.createFromImage(tmp[0], false);
}
return image2Return[0];
}
In the stacktrace, the NPE seems to stem from the overridden URLImage.ImageAdapter :
java.lang.IllegalArgumentException: create image failed for the given
image data of length: 0 at
com.codename1.ui.Image.createImage(Image.java:654) at
com.codename1.ui.EncodedImage.getInternal(EncodedImage.java:365) at
com.codename1.ui.EncodedImage.getInternalImpl(EncodedImage.java:340)
at com.codename1.ui.EncodedImage.getHeight(EncodedImage.java:522) at
com.codename1.ui.Image.scaledLargerRatio(Image.java:899) at
com.my.application.ParametresGeneraux$1.lambda$adaptImage$0(ParametresGeneraux.java:564)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:95) at
com.codename1.ui.Display.processSerialCalls(Display.java:1154) at
com.codename1.ui.Display.edtLoopImpl(Display.java:1098) at
com.codename1.ui.Display.invokeAndBlock(Display.java:1207) at
com.codename1.ui.Display.invokeAndBlock(Display.java:1244) at
com.codename1.ui.URLImage$DownloadCompleted.actionPerformed(URLImage.java:233)
at com.codename1.ui.URLImage$4.onSucess(URLImage.java:301) at
com.codename1.ui.URLImage$4.onSucess(URLImage.java:297) at
com.codename1.util.CallbackDispatcher.run(CallbackDispatcher.java:53)
at com.codename1.ui.Display.processSerialCalls(Display.java:1154) at
com.codename1.ui.Display.edtLoopImpl(Display.java:1098) at
com.codename1.ui.Display.mainEDTLoop(Display.java:999) at
com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120) at
com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
[EDT] 0:0:0,1 - Codename One revisions:
e5c43877074c18b4b5c7748d000e5cfac75ab749 2318
[EDT] 0:0:0,1 - Exception: java.lang.NullPointerException - null
java.lang.NullPointerException at
com.codename1.impl.javase.JavaSEPort.scale(JavaSEPort.java:3996) at
com.codename1.ui.Image.scale(Image.java:1007) at
com.codename1.ui.Image.scaledImpl(Image.java:953) at
com.codename1.ui.Image.scaled(Image.java:918) at
com.codename1.impl.javase.JavaSEPort$71.save(JavaSEPort.java:7659) at
com.codename1.ui.EncodedImage.scaledEncoded(EncodedImage.java:626) at
com.codename1.ui.EncodedImage.scaled(EncodedImage.java:653) at
com.codename1.ui.Image.scaledLargerRatio(Image.java:904) at
com.my.application.ParametresGeneraux$1.lambda$adaptImage$0(ParametresGeneraux.java:564)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:95) at
com.codename1.ui.Display.processSerialCalls(Display.java:1154) at
com.codename1.ui.Display.edtLoopImpl(Display.java:1098) at
com.codename1.ui.Display.invokeAndBlock(Display.java:1207) at
com.codename1.ui.Display.invokeAndBlock(Display.java:1244) at
com.codename1.ui.URLImage$DownloadCompleted.actionPerformed(URLImage.java:233)
at com.codename1.ui.URLImage$4.onSucess(URLImage.java:301) at
com.codename1.ui.URLImage$4.onSucess(URLImage.java:297) at
com.codename1.util.CallbackDispatcher.run(CallbackDispatcher.java:53)
at com.codename1.ui.Display.processSerialCalls(Display.java:1154) at
com.codename1.ui.Display.edtLoopImpl(Display.java:1098) at
com.codename1.ui.Display.mainEDTLoop(Display.java:999) at
com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120) at
com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
Moreover, a glance in the .cn1 directory shows the URLImage storage file name with the suffix "ImageURLTMP" which does not appear when everything works without NPE.
Finally, if I come back to this form later, everything works as expected (images were shown, no NPE). I tried to test for downloadedImage nullness in imageAdapter but the EncodedImage is not null.
How can I avoid this NPE?
Edit March 1st 2017
Following the answers from #Diamond and #Shai, I believe the NPE occurs because the InfiniteScrollAdapter wants to fill in the screen with rows and consequently launches the download of the same image simultaneously (because it is not in cache). So a solution could be to prevent the InfiniteScrollAdapter to loop (so it becomes finite). How can I do that ?
Please also note that there is not 404 error, the Network monitor shows response code 200 as depicted below. However the image should not be downloaded 3 times, should it ?
Change your ImageAdapter to the following:
public static final URLImage.ImageAdapter RESIZE_SCALE_WITH_ROUND_MASK = new URLImage.ImageAdapter() {
#Override
public EncodedImage adaptImage(EncodedImage downloadedImage, EncodedImage placeholderImage) {
Image tmp = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
if (tmp.getWidth() > placeholderImage.getWidth()) {
int diff = tmp.getWidth() - placeholderImage.getWidth();
int x = diff / 2;
tmp = tmp.subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
} else if (tmp.getHeight() > placeholderImage.getHeight()) {
int diff = tmp.getHeight() - placeholderImage.getHeight();
int y = diff / 2;
tmp = tmp.subImage(0, y, Math.min(placeholderImage.getWidth(), tmp.getWidth()),
Math.min(placeholderImage.getHeight(), tmp.getHeight()), true);
}
Image roundMask = Image.createImage(tmp.getWidth(), tmp.getHeight(), 0xff000000);
Graphics gr = roundMask.getGraphics();
gr.setColor(0xffffff);
gr.fillArc(0, 0, tmp.getWidth(), tmp.getHeight(), 0, 360);
Object mask = roundMask.createMask();
tmp = tmp.applyMask(mask);
return EncodedImage.createFromImage(tmp, false);
}
#Override
public boolean isAsyncAdapter() {
return true;
}
};
No need to check EDT.
Make sure your tempPlaceholder image is applied to your component first and at the end of your logic, call your URLImage in a callSerially() method:
Image tempPlaceholder = Image.createImage(
ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX,
ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX,
ParametresGeneraux.accentColor);
Graphics gr = tempPlaceholder.getGraphics();
gr.setAntiAliased(true);
gr.setColor(ParametresGeneraux.accentColor);
gr.fillArc(0, 0, ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX, ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX, 0, 360);
myComponent.setIcon(tempPlaceholder);
...
//Then call this at the end of everything
Display.getInstance().callSerially(() -> {
EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);
final Image reportImage = URLImage.createToStorage(
roundPlaceholder,
photoFilenameInStorage,
currentReport.getPhotoPath(),
ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
);
myComponent.setIcon(reportImage);
myComponent.getComponentForm().repaint();
});
Edit:
Based on #Shai's answer, you could check if you are currently downloading the same image and prevent another one from being pulled. Because this usually causes a conflict:
//Declare this at the top of your class
final static private Map<String, Image> LOADED_URLS = new HashMap<>();
//Then change the URLImage image method to this
Display.getInstance().callSerially(() -> {
EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);
final Image reportImage = LOADED_URLS.containsKey(photoFilenameInStorage) ? LOADED_URLS.get(photoFilenameInStorage)
: URLImage.createToStorage(
roundPlaceholder,
photoFilenameInStorage,
currentReport.getPhotoPath(),
ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
);
LOADED_URLS.put(photoFilenameInStorage, reportImage);
myComponent.setIcon(reportImage);
myComponent.getComponentForm().repaint();
});
In your adapter check if downloadedImage.getData() is null. I assume it's not and it's a 404 error page or something similar to that.
In that case your adapter can catch the exception and just return a fallback that matches what you expect to see when no image exists.
This works the second time around since the system sees the tmp file and assumes a download is in progress so it doesn't invoke the download code again. The tmp file is later renamed to the final downloadable file.
Is there a way to get an mouse-click on an Header of a Table?
Why i need this?
I have a Table with many Columns. But only a specific witdth for the whole Table.
To avoid scrolling, i want to give each Column an specific width (50 or so), and just if you click on an header, this column will expand so you can read the content. If you click on another header, the previous one collapse.
Hopefully someone can help me:)
Unfortunately there isn't a nice way to do this. The only public API option is to replace the "graphic" of the column with your own label, and then add a mouse listener to that. For this to work you also need to clear any existing column text.
Note that columns by default have click listeners to implement sorting, it seems you don't want this behaviour, so you'll also need to call column.setSortable(false)
#Override
public void start(Stage primaryStage) throws Exception {
TableView<String> tableView = new TableView<>();
TableColumn<String, Object> x = new TableColumn<>("x");
tableView.getColumns().add(x);
TableColumn<String, Object> y = new TableColumn<>("");
tableView.getColumns().add(y);
x.setSortable(false);
y.setSortable(false);
makeHeader(x, "X", 0);
makeHeader(y, "Y", 1);
EventHandler<? super MouseEvent> handler = event -> {
System.out.println("Column clicked " + ((Node)event.getTarget()).getProperties().get("index"));
};
x.getGraphic().addEventFilter(MouseEvent.MOUSE_CLICKED, handler);
y.getGraphic().addEventFilter(MouseEvent.MOUSE_CLICKED, handler);
primaryStage.setScene(new Scene(tableView));
primaryStage.show();
}
private void makeHeader(TableColumn<?, ?> target, String name, int index) {
VBox vBox = new VBox(new Label(name));
vBox.setAlignment(Pos.CENTER);
vBox.getProperties().put("index", index);
target.setGraphic(vBox);
target.setText("");
}
// Step 0: call setOnShown(...).
stage.setOnShown(event -> {
setHeaderClickListeners(); // Call this method when the stage is shown.
});
And then you create a method setHeaderClickListeners(), as follows:
private void setHeaderClickListeners() {
// Step 1: Get the table header row.
TableHeaderRow headerRow = null;
for (Node n : ((TableViewSkin<?>) tableView.getSkin()).getChildren()) {
if (n instanceof TableHeaderRow) {
headerRow = (TableHeaderRow) n;
}
}
if (headerRow == null) {
return;
}
// Step 2: Get the list of the header columns.
NestedTableColumnHeader ntch = (NestedTableColumnHeader) headerRow.getChildren().get(1);
ObservableList<TableColumnHeader> headers = ntch.getColumnHeaders();
// Step 3: Add click listener to the header columns.
for (int i = 0; i < headers.size(); i++) {
TableColumnHeader header = headers.get(i);
final int index = i;
header.setOnMouseClicked(mouseEvent -> {
// Optional:
// Get the TableColumnBase (which is the object responsible
// for displaying the content of the column.)
TableColumnBase column = header.getTableColumn();
// Step 4: Handle double mouse click event.
if (mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.getClickCount() == 2) {
P.x("Header cell " + index + " clicked! " + column.getText());
}
});
}
}