I want to test that Alert showAndWait() method gets called. I mock Alert with Mockito and verify if showAndWait() was called. But the problem is Alert.showAndWait() ACTUALLY gets called, instead of mocked method. I assume this should NOT happen.
My code:
package drakonli.jcomponents.notificator;
import javafx.scene.control.Alert;
import junit_util.JavaFXThreadingRule;
import org.junit.Rule;
import org.junit.Test;
import static org.mockito.Mockito.mock;
public class AlertTest
{
#Rule public JavaFXThreadingRule javafxRule = new JavaFXThreadingRule();
#Test
public void success()
{
Alert alert = mock(Alert.class);
alert.showAndWait();
verify(alert, atLeastOnce()).showAndWait();
}
}
Exception:
java.lang.NullPointerException
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.control.Dialog.showAndWait(Dialog.java:331)
at drakonli.jcomponents.notificator.AlertNotificatorTest.success(AlertNotificatorTest.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at junit_util.JavaFXThreadingRule$OnJFXThreadStatement$1.run(JavaFXThreadingRule.java:65)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:748)
Mockito cannot mock Final methods or classes. Powermock can, but I do not recommended for any new functionality (it gets overused, or used incorrectly). I'd recommened looking for test harnesses for the framework or working around the limitations and acceptable that some stuff cannot be effectively tested.
Related
I want to build a javafx app where the fxml document and its controller both are stored in a database.
Thanks to jewelsea, I use this code to load the fxml document dynamically :
String fxmlDocument = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"\n" +
"<?import javafx.scene.control.Button?>\n" +
"<?import javafx.scene.layout.BorderPane?>\n" +
"\n" +
"\n" +
"<BorderPane maxHeight=\"-Infinity\" maxWidth=\"-Infinity\" minHeight=\"-Infinity\" minWidth=\"-Infinity\" prefHeight=\"400.0\" prefWidth=\"600.0\" xmlns=\"http://javafx.com/javafx/8.0.171\" xmlns:fx=\"http://javafx.com/fxml/1\" fx:controller=\"main.ControllerClass\">\n" +
" <center>\n" +
" <Button fx:id=\"button\" mnemonicParsing=\"false\" onAction=\"#onButtonClicked\" text=\"Button\" BorderPane.alignment=\"CENTER\" />\n" +
" </center>\n" +
"</BorderPane>";
FXMLLoader loader = new FXMLLoader();
BorderPane layout = (BorderPane) loader.load(
new ByteArrayInputStream(fxmlDocument.getBytes())
);
My controller was first stored in ControllerClass.java file
package main;
import javafx.scene.control.Button;
import javafx.event.ActionEvent;
public class ControllerClass {
public Button button;
public void onButtonClicked(ActionEvent event){
System.out.println("Button's clicked");
}
}
and it worked fine.
but now my controller is stored in a string so I used this link [inmemory]:https://github.com/trung/InMemoryJavaCompiler to compile and instantiate my controller like this:
StringBuilder fxmlController = new StringBuilder();
fxmlController.append("package main;\n");
fxmlController.append("import javafx.scene.control.Button;\n");
fxmlController.append("import javafx.event.ActionEvent;\n");
fxmlController.append("import java.util.ArrayList;\n");
fxmlController.append("import java.util.List;\n");
fxmlController.append("public class ControllerClass {\n");
fxmlController.append(" public Button button;\n");
fxmlController.append(" public void onButtonClicked(ActionEvent event){\n");
fxmlController.append(" System.out.println(\"ControllerClass called\");");
fxmlController.append(" }");
fxmlController.append(" public List<String> test() {");
fxmlController.append(" List<String> supplierNames = new ArrayList<String>();");
fxmlController.append(" supplierNames.add(\"sup1\");");
fxmlController.append(" supplierNames.add(\"sup2\");");
fxmlController.append(" supplierNames.add(\"sup3\");");
fxmlController.append(" supplierNames.add(\"sup4\");");
fxmlController.append(" System.out.println(supplierNames.get(3));");
fxmlController.append(" return supplierNames;");
fxmlController.append(" }");
fxmlController.append("}");
Class<?> controllerClass = InMemoryJavaCompiler.newInstance().ignoreWarnings().compile("main.ControllerClass", fxmlController.toString());
List<?> listSize = (List<?>) controllerClass.getMethod("test").invoke(controllerClass.newInstance());
System.out.println("listSize.size()=" + listSize.size());
When I run the code, the result is:
sup4
res.size()=4
That means, the controller is correctly compiled and instantiated BUT if I put the fxml documement and the controller dynamically compiled/instantiated/loaded together I got in error
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$154(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:748)
Caused by: javafx.fxml.LoadException:
unknown path:7
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:103)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:922)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2425)
at main.Main.start(Main.java:111)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
... 1 more
Caused by: java.lang.ClassNotFoundException: main.ControllerClass
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:920)
... 16 more
Exception running application main.Main
Process finished with exit code 1
The issue is :
Caused by: javafx.fxml.LoadException:
unknown path:7
Did I do something wrong as my controller is correctly compiled/instantiated but it's not recongnized by the FXMLLoader.
Can you help please ?
Thanks in advance.
I'm trying to have an ObservableList of some type User which will notify any listchangelistener if one of the items stored in it had any of its values changed.
Though the callback always throws the exception:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$1(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoClassDefFoundError: groovy/lang/GroovyObject
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at org.codehaus.groovy.runtime.ProxyGeneratorAdapter$InnerLoader.defineClass(ProxyGeneratorAdapter.java:926)
at org.codehaus.groovy.runtime.ProxyGeneratorAdapter.<init>(ProxyGeneratorAdapter.java:191)
at groovy.util.ProxyGenerator.createAdapter(ProxyGenerator.java:233)
at groovy.util.ProxyGenerator.instantiateDelegateWithBaseClass(ProxyGenerator.java:208)
at groovy.util.ProxyGenerator.instantiateDelegateWithBaseClass(ProxyGenerator.java:192)
at groovy.util.ProxyGenerator.instantiateDelegate(ProxyGenerator.java:184)
at groovy.util.ProxyGenerator.instantiateDelegate(ProxyGenerator.java:180)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.asType(DefaultGroovyMethods.java:15768)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.asType(DefaultGroovyMethods.java:10859)
at org.codehaus.groovy.runtime.dgm$53.doMethodInvoke(Unknown Source)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1225)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
at org.codehaus.groovy.runtime.InvokerHelper.invokePojoMethod(InvokerHelper.java:935)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:926)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:181)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.asType(ScriptBytecodeAdapter.java:604)
at sample.Main$1.call(Main.groovy:36)
at sample.Main$1.call(Main.groovy)
at com.sun.javafx.collections.ElementObserver.attachListener(ElementObserver.java:79)
at com.sun.javafx.collections.ObservableListWrapper.doAdd(ObservableListWrapper.java:100)
at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:151)
at java.util.AbstractList.add(AbstractList.java:108)
at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
at javafx.collections.ModifiableObservableListBase.addAll(ModifiableObservableListBase.java:99)
at javafx.collections.ObservableListBase.addAll(ObservableListBase.java:245)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSite.invoke(PojoMetaMethodSite.java:192)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:136)
at sample.Main.start(Main.groovy:39)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$5(GtkApplication.java:139)
... 1 more
Caused by: java.lang.ClassNotFoundException: groovy.lang.GroovyObject
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:702)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:812)
at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:800)
... 47 more
Exception running application sample.Main
I was able to reproduce the error with this example:
package sample
import javafx.application.Application
import javafx.beans.Observable
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.scene.Scene
import javafx.scene.control.ComboBox
import javafx.stage.Screen
import javafx.stage.Stage
import javafx.util.Callback
class Main extends Application {
static void main(String[] args) {
launch(Main.class, args)
}
class User {
String name
User(String t){
name = t
}
}
#Override
void start(Stage primaryStage) {
ObservableList<User> usersTest =
FXCollections.observableArrayList(new Callback<User, Observable[]>() {
#Override
Observable[] call(User o) {
return [o] as Observable
}
})
usersTest.addAll( new User("John"), new User("Jane"))
ComboBox<User> cb = new ComboBox<>()
cb.setItems(usersTest)
cb.value = cb.items.first()
def bounds = Screen.primary.bounds
Scene scene = new Scene(cb, bounds.width, bounds.height)
primaryStage.setScene(scene)
primaryStage.show()
}
}
I'm honestly a bit out of options as the error is as unhelpful as it gets.
It's my first time designing an API. I have a program with folder 'plugins'. I made a test plugin in that folder packaged in JAR. In the program I have a Groovy class 'Configuration', which is supposed to load the plugins.
Configuration.java:
static void processConfiguration()
{
File pluginDirectory=new File(PLUGINDIRECTORY)//it's 'plugins'
if(!pluginDirectory.exists()) pluginDirectory.mkdir()
File[] pluginfiles=pluginDirectory.listFiles()
for(File f:pluginfiles)
{
if(f.name.endsWith('.jar'))
{
JarFile jar=new JarFile(f)
for(JarEntry jarEntry:jar.entries())
{
if(jarEntry.getName().endsWith('.class'))
{
//try loading the class
}
}
}
}
}
So, I tried doing these at the //try loading the class block
Class cl=ClassLoader.getSystemClassLoader().loadClass(jarEntry.name)
Class cl=new GroovyClassLoader().loadClass(jarEntry.name)
Class cl=Configuration.classLoader.loadClass(jarEntry.name)
Class cl=Class.forName(jarEntry.getName())
also tried with replacing - jarEntry.name.replaceAll('/','.').replace('.class',''), but I think it's done automatically.
Getting Class not found exception:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassNotFoundException: jace/plugins/JavaPlugin.class
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java_lang_ClassLoader$loadClass.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at jace.Configuration.processConfiguration(Configuration.groovy:87)
at jace.Jace.start(Jace.java:56)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
After some searching and tinkering I finally resolved it.
First, need to create a list of proper URLs;
Second, make a list of classes from the jar;
Third, instantiate GroovyClassLoader and give him all URLs;
Fourth, load classes from list, check whether they implement plugin interfaces, then instantiate them.
static void processConfiguration()
{
File pluginDirectory=new File(PLUGINDIRECTORY)
if(!pluginDirectory.exists()) pluginDirectory.mkdir()
File[] pluginfiles=pluginDirectory.listFiles()
URL[] urls=[]
ArrayList<String> classes=new ArrayList<>()
for(File f:pluginfiles)
{
if(f.name.endsWith('.jar'))
{
JarFile jar=new JarFile(f)
URL url=new URL('jar:file:'+PLUGINDIRECTORY+'/'+f.name+'!/')
urls+=url
jar.entries().each {if(it.name.endsWith('.class'))classes.add(it.name) }
}
}
// println(gcl.loadedClasses)
GroovyClassLoader groovyClassLoader=new GroovyClassLoader()
urls.each {groovyClassLoader.addURL(it)}
// println(classes)
classes.each {
Class cl=groovyClassLoader.loadClass(it.replaceAll('/','.').replace('.class',''))
Class[] interfaces=cl.getInterfaces()
if(interfaces.contains(Plugin.class))
{
Object instance=cl.newInstance()
if(interfaces.contains(SuggestionPlugin.class))
{
SuggestionProcessor.suggestionPlugins.add(instance as SuggestionPlugin)
}
Constructor[] constructors=cl.getConstructors()
println("Loaded a plugin $cl.simpleName")
}
}
}
Hi I am learning JFX and trin to write a simple jtable example and I am getting a error when running the application
my code snippet error comes is
itemPrice.setCellValueFactory(new PropertyValueFactory<Item, Double>("itemPrice"));
itemPrice.setCellFactory(TextFieldTableCell.forTableColumn());
itemPrice.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Item, Double>>() {
#Override
public void handle(TableColumn.CellEditEvent<Item, Double> t) {
((Item) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setItemPrice(t.getNewValue());
}
Error is
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String
at javafx.util.converter.DefaultStringConverter.toString(DefaultStringConverter.java:34)
at javafx.scene.control.cell.CellUtils.getItemText(CellUtils.java:100)
at javafx.scene.control.cell.CellUtils.updateItem(CellUtils.java:201)
at javafx.scene.control.cell.TextFieldTableCell.updateItem(TextFieldTableCell.java:204)
at javafx.scene.control.TableCell.updateItem(TableCell.java:663)
at javafx.scene.control.TableCell.indexChanged(TableCell.java:468)
at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116)
at com.sun.javafx.scene.control.skin.TableRowSkinBase.updateCells(TableRowSkinBase.java:523)
at com.sun.javafx.scene.control.skin.TableRowSkinBase.init(TableRowSkinBase.java:147)
at com.sun.javafx.scene.control.skin.TableRowSkin.<init>(TableRowSkin.java:64)
at javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:212)
at javafx.scene.control.Control.impl_processCSS(Control.java:859)
at javafx.scene.Node.processCSS(Node.java:9035)
at javafx.scene.Node.applyCss(Node.java:9132)
at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1957)
at com.sun.javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1790)
at com.sun.javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1872)
at com.sun.javafx.scene.control.skin.VirtualFlow.computeViewportOffset(VirtualFlow.java:2511)
at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1189)
at javafx.scene.Parent.layout(Parent.java:1076)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Scene.doLayoutPass(Scene.java:552)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2397)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:314)
at com.sun.javafx.tk.Toolkit$$Lambda$216/252608964.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:313)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:340)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:525)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:505)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(QuantumToolkit.java:334)
at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$42/820829455.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda$38/1329190985.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
and I know this is due to casting issue in java but duno how edit handler works in JFX same code for string data type works how to fix, Help/Tip Please
Use
itemPrice.setCellFactory(TextFieldTableCell.forTableColumn(new DoubleStringConverter()));
I want to include checks for my combobox to restrict "access" to some of the values. I could just remove those unaccessible items from the list, yes, but I'd like the user to see the other options, even if he can't select them (yet).
Problem: Selecting another value inside a changelistener causes an IndexOutOfBoundsException, and I have no idea why.
Here is a SSCCE. It creates a ComboBox with Integer values, and the first one is selected on default. Then I tried to keep it very easy: Every change of the value is considered as "wrong" and I change the selection back to the first element. But still, IndexOutOfBounds:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.stage.Stage;
public class Tester extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
ComboBox<Integer> box = new ComboBox<Integer>();
ObservableList<Integer> vals= FXCollections.observableArrayList(0,1,2,3);
box.setItems(vals);
box.getSelectionModel().select(0);
/*box.valueProperty().addListener((observable, oldValue, newValue) -> {
box.getSelectionModel().select(0);
});*/
/*box.getSelectionModel().selectedItemProperty().addListener((observable,oldValue,newValue)->{
System.out.println(oldValue+","+newValue);
box.getSelectionModel().select(0);
});*/
box.getSelectionModel().selectedIndexProperty().addListener((observable,oldValue,newValue)->{
System.out.println(oldValue+","+newValue);
box.getSelectionModel().select(0);
});
Scene scene = new Scene(new Group(box),500,500);
stage.setScene(scene);
stage.show();
}
}
I tested it with valueProperty, selectedItemProperty and selectedIndexProperty, as well as all of these:
box.getSelectionModel().select(0);
box.getSelectionModel().selectFirst();
box.getSelectionModel().selectPrevious();
box.setValue(0);
if (oldValue.intValue() < newValue.intValue())
box.getSelectionModel().select(oldValue.intValue());
The only think that works is setting the value itself:
box.getSelectionModel().select(box.getSelectionModel().getSelectedIndex());
box.setValue(box.getValue));
Here is the exception:
Exception in thread "JavaFX Application Thread" java.lang.IndexOutOfBoundsException
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.subList(Unknown Source)
at javafx.collections.ListChangeListener$Change.getAddedSubList(Unknown Source)
at com.sun.javafx.scene.control.behavior.ListViewBehavior.lambda$new$178(Unknown Source)
at com.sun.javafx.scene.control.behavior.ListViewBehavior$$Lambda$126/644961012.onChanged(Unknown Source)
at javafx.collections.WeakListChangeListener.onChanged(Unknown Source)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(Unknown Source)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(Unknown Source)
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(Unknown Source)
at javafx.scene.control.MultipleSelectionModelBase.clearAndSelect(Unknown Source)
at javafx.scene.control.ListView$ListViewBitSetSelectionModel.clearAndSelect(Unknown Source)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.simpleSelect(Unknown Source)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.doSelect(Unknown Source)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mousePressed(Unknown Source)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(Unknown Source)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.access$1500(Unknown Source)
at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$350(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$172/2037973250.get(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.notifyMouse(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(Unknown Source)
at com.sun.glass.ui.win.WinApplication$$Lambda$36/2117255219.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
What am I doing wrong?
In JavaFX, you cannot change the contents of an ObservableList while a change is already in progress. What is happening here is that your listeners (any of the ones you try) are being fired as part of the box.getSelctionModel().getSelectedItems() ObservableList changing. So basically, you cannot change the selection while a selection change is being processed.
Your solution is a bit unwieldy anyway. If you had another listener on the selected item (or combo box value), even if your method worked it would temporarily see the combo box with an "illegal" selection. E.g in the example above, if the user tries to select "1", another listener would see the selection change to the disallowed value "1", then back to "0". Dealing with values that are not supposed to be allowed in this listener would likely make your program logic pretty complex.
A better approach, imho, is to prevent the user from selecting the disallowed values. You can do this with a cell factory that sets the disable property of the cell:
box.setCellFactory(lv -> new ListCell<Integer>() {
#Override
public void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
setText(item.toString());
setDisable(item.intValue() != 0);
}
}
});
Including the following in an external style sheet will give the user the usual visual hint that the items are not selectable:
.combo-box-popup .list-cell:disabled {
-fx-opacity: 0.4 ;
}
I know the thread is quite old but I had a similar problem and I worked it out in a different way. I tried to change ComboBox' selected item in its onAction method when the item wasn't available at that moment (for example because of the given condition). As #James_D said in his answer, the problem is setting the object that is being currently modified.
Just add your code inside the Platform.runLater() method:
Platform.runLater(() -> box.getSelectionModel().select(0));
In my case it worked, hope it will work in the others too.