documentFilter.insert never called - swing

I'm trying to set a documentFilter for my JTextArea. Having overriden the insert(...) method I admitted that it is never called. What's wrong? A piece of code:
package jaba;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
public class Main extends JFrame {
public Main() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(640, 480);
setLayout(new FlowLayout());
add(txt);
Document doc = txt.getDocument();
if (doc instanceof AbstractDocument) {
((AbstractDocument)doc).setDocumentFilter(new DocumentFilter() {
#Override
public void insertString(DocumentFilter.FilterBypass fb,
int offset, String string, AttributeSet att)
throws BadLocationException {
if (string.toLowerCase().contains("ass")) {
super.insertString(fb, offset, "###", att);
} else {
super.insertString(fb, offset, string, att);
}
}
});
} else {
txt.setText("error setting filter");
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main().setVisible(true);
}
});
}
private JTextArea txt = new JTextArea(40, 40);
}

Having overriden the insert(...) method I admitted that it is never called.
Changes to the text in Swing components ultimately invoke the replace(...) method of the DocumentFilter.
The insertString(...) method is only invoked when you update the Document directly by using code like:
textField.getDocument().insertString(...);
So you need to make sure that you also override the replace() method in the DocumentFilter.

Related

JavaFX - Object with Constructor

I'm working with JavaFX and my Idea was to have my own JavaFX Object which I can create like this:
public class Main {
public static void main(String[] args) throws Exception
TSS t = new TSS();
}
}
My JavaFX Main class looks like this:
public class TSS extends Application {
private Scene scene;
private Stage stage;
public void redrawGui() throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("tss.fxml"));
scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
this.stage = new Stage();
Parent root = FXMLLoader.load(getClass().getResource("tss.fxml"));
scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Normally the main method in TSS is called and its working but I want to create my own TSS-Object in its constructor, it creates the Gui.
Does anyone know how to do this?
In JavaFX, you should (typically) think of the Application subclass as the "main" class (i.e. the application entry point) and its start(...) method as the replacement for the main(...) method in a "traditional" Java Application.
If you want to factor your code out into a class that is separate from the Application subclass (which is generally a good idea), then you can do so, but you need to just reorganize things a little:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
TSS t = new TSS();
Scene scene = new Scene(t.getView());
primaryStage.setScene(scene);
primaryStage.show();
}
// not really needed in Java 8, but some IDEs need this to execute this class:
public static void main(String[] args) { launch(args);}
}
And then you can define your own class as follows:
public class TSS {
private Parent view ;
private TssController controller ; // controller class specified in FXML
public TSS() throws Exception {
load();
}
private void load() throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("tss.fxml"));
view = loader.load();
controller = loader.getController();
}
public Parent getView() {
return view ;
}
public void restartGui() throws Exception {
Scene scene = view.getScene();
Stage stage = null ;
if (scene != null) {
Window window = scene.getWindow();
if (window instanceof Stage) {
stage = (Stage) window ;
}
}
load();
if (stage != null) {
stage.setScene(new Scene(view));
}
}
public void doOtherStuff() {
controller.doSomething();
}
}
You could also consider implementing the TSS class above using the custom control pattern described in the FXML documentation. I marginally prefer the style I showed here, as it favors composition over inheritance, but it is a minimal difference.

LWJGL is ContextArribs Needed when making the display?

I have a problem and I have looked every where, so I am going to ask it: Do you need ContextAttribs? I have this error when I run my program:
org.lwjgl.LWJGLException: Could not create context (WGL_ARB_create_context)
at org.lwjgl.opengl.WindowsContextImplementation.nCreate(Native Method)
at org.lwjgl.opengl.WindowsContextImplementation.create(WindowsContextImplementation.java:50)
at org.lwjgl.opengl.ContextGL.<init>(ContextGL.java:132)
at org.lwjgl.opengl.Display.create(Display.java:850)
at org.lwjgl.opengl.Display.create(Display.java:797)
at renderEngine.DisplayManager.createDisplay(DisplayManager.java:22)
at engineTester.MainGameLoop.main(MainGameLoop.java:10)
Exception in thread "main" java.lang.IllegalStateException: Cannot determine close requested state of uncreated window
at org.lwjgl.opengl.Display.isCloseRequested(Display.java:549)
at engineTester.MainGameLoop.main(MainGameLoop.java:12)
This is my code(Main class):
import org.lwjgl.opengl.Display;
import renderEngine.DisplayManager;
public class MainGameLoop {
public static void main(String[] args) {
DisplayManager.createDisplay();
if (Display.isCloseRequested())
DisplayManager.closeDisplay();
while (true)
{
DisplayManager.updateDisplay();
}
}
Display Class:
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;
import org.omg.CORBA.Context;
public class DisplayManager {
private static final int WIDTH = 1200;
private static final int HEIGHT = 650;
private static final int FPS_CAP = 60;
public static void createDisplay() {
ContextAttribs attribs = new ContextAttribs(3,2).withProfileCore(true).withForwardCompatible(true);
try {
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.create(new PixelFormat(), new ContextAttribs(3,2).withProfileCore(true).withForwardCompatible(true));
Display.setTitle("Knights of the Lord's Realm");
} catch (LWJGLException e) {
e.printStackTrace();
}
}
public static void updateDisplay() {
Display.sync(FPS_CAP);
}
public static void closeDisplay() {
Display.destroy();
}
}
Any ideas other than graphics card issue or even if I have to use "ContextAttribs"
Thanks!
ContextAttribs attribs = new ContextAttribs(3,2).withProfileCore(true).withForwardCompatible(true);
I'm assuming that you are follow "ThinMatrix" Youtube tutorial replace that line with
ContextAttribs attribs = new ContextAttribs(3,2);
attribs.withForwardCompatible(true);
attribs.withProfileCompatibility(true);

Moving JavaFX Nodes Between Stages

I'm rewriting a Swing application in JavaFX, where I allow users to present multiple workspaces as either windows or tabs. However, my FX code will not display the contents moved from more than one tab into a new stage; only the contents of the currently-selected tab appear in my new stages. I've distilled my code into a small example below. Can anyone clue me in as to what's gone wrong?
package scenes;
import java.util.ArrayList;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class StageSwapper extends Application {
static public void main(String[] args) {
launch(args);
}
private TabPane tabs = new TabPane();
public void start(Stage stage) {
stage.setTitle("Stage Swapper");
BorderPane p = new BorderPane();
p.setCenter(tabs);
tabs.getTabs().addAll(new Swapee("First").createTab(), new Swapee("Second").createTab());
Scene s = new Scene(p);
stage.setScene(s);
stage.show();
launchSwap();
}
private void launchSwap() {
new Thread() {
public void run() {
try {
sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
Platform.runLater(new Runnable() {
public void run() {
for (Swapee s : Swapee.list) {
createWindow(s);
}
}
});
}
}.start();
}
public void createWindow(Swapee s) {
Stage window = new Stage();
window.setTitle("New Window");
window.setY(200);
window.setX(200);
BorderPane p = new BorderPane();
p.setCenter(s);
window.setScene(new Scene(p));
window.show();
}
}
class Swapee extends Label {
static private int count;
static ArrayList<Swapee> list = new ArrayList<>();
String name;
Swapee(String name) {
super("Swappable Item " + ++count);
this.name = name;
list.add(this);
}
Tab createTab() {
Tab t = new Tab(name);
t.setContent(this);
return t;
}
}
You haven't specified the size of the windows that you're creating. Right now they have width and length equal to 0. You may use the following approach:
BorderPane p = new BorderPane();
p.setPrefSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
p.setCenter(s);
BorderPane will be resized according to its content and the window will be resized as well.

Basic JUnit test for JavaFX 8

I want to create basic JUnit test for JavaFX 8 application. I have this simple code sample:
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Tabs");
Group root = new Group();
Scene scene = new Scene(root, 400, 250, Color.WHITE);
TabPane tabPane = new TabPane();
BorderPane borderPane = new BorderPane();
for (int i = 0; i < 5; i++) {
Tab tab = new Tab();
tab.setText("Tab" + i);
HBox hbox = new HBox();
hbox.getChildren().add(new Label("Tab" + i));
hbox.setAlignment(Pos.CENTER);
tab.setContent(hbox);
tabPane.getTabs().add(tab);
}
// bind to take available space
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
borderPane.setCenter(tabPane);
root.getChildren().add(borderPane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I only have this code so far:
import javafx.application.Application;
import javafx.stage.Stage;
import org.junit.BeforeClass;
public class BasicStart extends Application {
#BeforeClass
public static void initJFX() {
Thread t = new Thread("JavaFX Init Thread") {
#Override
public void run() {
Application.launch(BasicStart.class, new String[0]);
}
};
t.setDaemon(true);
t.start();
}
#Override
public void start(Stage primaryStage) throws Exception {
// noop
}
}
Can you tell me how I can create JUnit test for the above code?
I use a Junit Rule to run unit tests on the JavaFX thread. The details are in this post. Just copy the class from that post and then add this field to your unit tests.
#Rule public JavaFXThreadingRule javafxRule = new JavaFXThreadingRule();
This code works for both JavaFX 2 and JavaFX 8.
The easiest aproach is the following:
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.stage.Stage;
import org.junit.Test;
public class BasicStart {
#Test
public void testA() throws InterruptedException {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
new JFXPanel(); // Initializes the JavaFx Platform
Platform.runLater(new Runnable() {
#Override
public void run() {
new Main().start(new Stage()); // Create and
// initialize
// your app.
}
});
}
});
thread.start();// Initialize the thread
Thread.sleep(10000); // Time to use the app, with out this, the thread
// will be killed before you can tell.
}
}
Hope it helps!
Based on Brian Blonski 's answer I created a JUnit-Testrunner, that does essentially the same thing, but is a bit simpler to use in my opinion.
Using it, your test would look like this:
#RunWith( JfxTestRunner.class )
public class MyUnitTest
{
#Test
public void testMyMethod()
{
//...
}
}

Swing JTextfield DnD replace the existing text with the imported text

I have two text fields and I can drag and drop the text between them. What I want is that every time I drag the text it will replace the existing text data with the text which was dragged and dropped.
import java.awt.Container;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class DragDropText extends JFrame {
public static void main(String[] args) {
new DragDropText().setVisible(true);
}
public DragDropText() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextField field1 = new JTextField("Life's a drag", 20);
JTextField field2 = new JTextField("and then you drop", 20);
field1.setDragEnabled(true);
field2.setDragEnabled(true);
Container content = getContentPane();
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
content.add(field1);
content.add(field2);
pack();
}
}
You can achieve the effect by creating and setting a subclass of TransferHandler.
This is an example that will work for any subclass of JTextComponent. You'll have to add the appropriate checks to make it robust.
You can find more info here: http://download.oracle.com/javase/tutorial/uiswing/dnd/transferhandler.html.
import java.io.*;
import java.awt.*;
import java.awt.datatransfer.*;
import javax.swing.*;
import javax.swing.text.*;
public class DragDropText extends JFrame {
public static void main(String[] args) {
new DragDropText().setVisible(true);
}
public DragDropText() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextField field1 = new JTextField("Life's a drag", 20);
JTextField field2 = new JTextField("and then you drop", 20);
field1.setDragEnabled(true);
field2.setDragEnabled(true);
field1.setTransferHandler(new CustomTransferHandler());
field2.setTransferHandler(new CustomTransferHandler());
Container content = getContentPane();
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
content.add(field1);
content.add(field2);
pack();
}
}
class CustomTransferHandler extends TransferHandler {
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
public Transferable createTransferable(JComponent c) {
return new StringSelection(((JTextComponent) c).getSelectedText());
}
public void exportDone(JComponent c, Transferable t, int action) {
if(action == MOVE)
((JTextComponent) c).replaceSelection("");
}
public boolean canImport(TransferSupport ts) {
return ts.getComponent() instanceof JTextComponent;
}
public boolean importData(TransferSupport ts) {
try {
((JTextComponent) ts.getComponent())
.setText((String) ts
.getTransferable()
.getTransferData(DataFlavor.stringFlavor));
return true;
} catch(UnsupportedFlavorException e) {
return false;
} catch(IOException e) {
return false;
}
}
}