I'm trying to dispose my JFrame by clicking a button, located on a JPanel that is placed on the JFrame that I want to close.
I tried to make a static method on the JFrame class, but ofcourse my IDE told me that wasn't going to happen.
Anyone thinking of a solution?
Thanks!
Try this:
public class DisposeJFrame extends JFrame{
JPanel panel = new JPanel();
JButton button = new JButton("Dispose JFrame");
public DisposeJFrame(){
super();
setTitle("Hi");
panel.add(button);
add(panel);
pack();
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
dispose();
}
});
}
public static void main(String args[]){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
DisposeJFrame jf = new DisposeJFrame();
jf.setVisible(true);
}
});
}
}
Do something like this:
JButton closeFrameButton = new JButton("Close");
closeFrameButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
((Window) getRootPane().getParent()).dispose();
}
});
Related
I am writing a program, where I'd like to open a class by the press of a button. I have two buttons on a window, the first one works perfectly, but I can't seem to be able to move the second one (called "Teacher"). Here is the code. I am desperately looking for the solution. Thanks!
class MyHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
System.exit(0);
}
}
class MyFrame extends JFrame {
private int size;
private String font;
MyFrame (String name){
super (name);
setBounds(500,500,600,400);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
//log in text
JLabel lbl = new JLabel("Log in");
lbl.setBounds(250, 60, 600, 50);
size = 40;
font = "Arial";
lbl.setFont(new Font(name,Font.PLAIN,size));
add(lbl);
//adding button
JButton btn = new JButton("Student");
btn.setBounds(150, 260, 60, 40);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dispose();
new Frame("StudentLogIn");
}
});
add(btn);
//adding second button
JButton teach = new JButton("Teacher");
teach.setBounds(100,260,60,40);
teach.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dispose();
new FrameTeach("TeacherLogIn");
}
});
add(teach);
setVisible(true);
}
}
public class StartingWindow {
public static void main(String[] args) {
new MyFrame("Starting Window");
}
}
i am customizing JavaFX TableView's header.
therefore i add a Graphic to the Label. By clicking the Label of the header i toggle my custom header(two lined). all this is working fine.
The header gets automatically resized so the custom headerfits in.
BUT, when i hide my custom headerthe headerstays large.
What am i missing so the headershrinks again?
i created a MCVE to demonstrate my problem:
public class TableViewHeaderMCVE extends Application {
private final TableView<Person> table = new TableView<>();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
final VBox root = new VBox();
Scene scene = new Scene(root);
stage.setWidth(218);
stage.setHeight(216);
TableColumn colName = new TableColumn("name");
colName.setMinWidth(100);
colName.setSortable(false);
TableColumn colProfession = new TableColumn("profession");
colProfession.setMinWidth(100);
colProfession.setSortable(false);
table.getColumns().addAll(colName, colProfession);
root.getChildren().addAll(table);
stage.setScene(scene);
stage.show();
// apply this after show!
TableViewHeader.installMod(table);
}
public static class TableViewHeader {
public static void installMod(TableView table) {
for (Node n : table.lookupAll(".column-header > .label")) {
if (n instanceof Label) {
new CustomHeaderLabel((Label) n);
}
}
}
}
public static class CustomHeaderLabel extends BorderPane {
protected Label customNode = null;
BooleanProperty expanded = new SimpleBooleanProperty(this, "expanded", false);
public CustomHeaderLabel(final Label parent) {
Label label = new Label(parent.getText());
// custom MenuButton
Button btn = new Button();
btn.setGraphic(new Label("\u2261"));
btn.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent ae) {
System.out.println("Hello World");
}
});
TextField filterTextField = new TextField();
filterTextField.promptTextProperty().set("type here to filter");
setCenter(label);
setRight(btn);
setBottom(filterTextField);
EventHandler<MouseEvent> toggleHeader = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent me) {
expanded.set(!expanded.get());
}
};
parent.setOnMouseClicked(toggleHeader);
expanded.addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> obs, Boolean oldValue, Boolean value) {
showCustomHeader(value);
}
});
label.textProperty().bind(parent.textProperty());
parent.setGraphic(this);
customNode = parent;
showCustomHeader(expanded.get());
}
protected void showCustomHeader(Boolean value) {
if (value) {
customNode.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
customNode.setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
public static class Person {
private final SimpleStringProperty name;
private final SimpleStringProperty profession;
private Person(String name, String profession) {
this.name = new SimpleStringProperty(name);
this.profession = new SimpleStringProperty(profession);
}
public String getName() {
return name.get();
}
public String getProfession() {
return profession.get();
}
}
}
thanks to #James_D for his reply.
after his reply i tested the code on another computer
works on:
JDK 1.8.0_161 on Windows 10
JDK 9.0.4 and JDK 10 on Mac OS X
fails on:
JDK 1.8.0_66-b18 on Windows 7
I'm trying to show a context menu only when there is something selected in the list view.
So I called hide in its on showing event. However, this is not working. The context menu still shows up. Is this a bug, or not its intended use? Because JavaFX api seems to suggest hide() is suppose to do this.
Anyway this is the code.
ContextMenu menu = new ContextMenu();
menu.setOnShowing(new EventHandler<WindowEvent>() {
#Override
public void handle(final WindowEvent event) {
menu.hide();
}
});
It will probably work if you do
public void handle(final WindowEvent event) {
Platform.runLater(new Runnable() {
#Override
public void run() {
menu.hide();
}
});
}
but that really seems like a horrible hack.
Why not just set the context menu only if something is selected?
final ListView<T> listView = ... ;
final ContextMenu menu = new ContextMenu();
listView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<T>() {
#Override
public void changed(ObservableValue<? extends T> obs, T oldValue, T newValue) {
if (newValue == null) {
listView.setContextMenu(null);
} else {
listView.setContextMenu(menu);
}
}
});
(obviously replace T with whatever type your ListView is displaying).
private ContextMenu menu; private MenuItem deleteItem;
table.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
#Override
public void handle(ContextMenuEvent event) {
if (table.getSelectionModel().getSelectedIndex() != -1) {
deleteItem.setVisible(true);
deleteItem.setText("delete: " + table.getSelectionModel().getSelectedItem().getName());
contextMenu.show(table, event.getScreenX(), event.getScreenY());
} else {
deleteItem.setVisible(false);
}
event.consume();
}
});
primaryStage.getScene().addEventHandler(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) { menu.hide(); }});
I'm using a GridPane, where I'm loading my data from a DB to the Pane, creating rows and columns dynamically. It works fine, but sometimes, if there is a lot of stuff (about 30 rows and 30 columns, and every cell has a EventListener) to load, it takes more than a second to see the loaded stuff.
So, I thought, that it will be great to add a ProgressBar or a ProgressIndicator. I tried that, but I realized that it does not depend on the loops, which are filling and creating the dynamic GridPane, but on the fact that the "loading and applying" takes a lot of time. My ProgressIndicator jumps from 0 to 100 and that's not what I want.
Do you have some ideas how to solve that problem? I read some articles about Preloaders, and I'm looking for a similar functionality, but I can't use Preloaders for that problem.
Best regards,
Edit: Now I got a solution, which works, but I don't think that someone else would write such code :S.
I created a class called LoaderDienstplan:
public class LoaderDienstplan extends Task {
//Some member variables for starting call() method
#Override
protected Object[] call() throws Exception{
// calling DB and service
updateProgress(1,1);
return; // Returning an ObjectArray with Lists,Data and a reference to my Controllerclass
}
#Override
public void run(){
final Object[] b = call();
Platform.runLater(new Runnable(){
#Override
public void run(){
//Updating GridPane
}
});
}
}
public class LoaderDienstplan extends Task {
MyInterface listener;
//Some member variables for starting call() method
#Override
protected Object[] call() throws Exception{
// calling DB and service
updateProgress(1,1);
return; // Returning an ObjectArray with Lists,Data and a reference to my Controllerclass
}
public void setListener(MyInterface listener) {
this.listener = listener;
}
#Override
public void run() {
final Object[] b = call();
Platform.runLater(new Runnable(){
#Override
public void run() {
//Updating GridPane
listener.updateGUI(something);
}
});
}
}
And the interface:
public interface MyInterface {
void updateGUI(Something something);
void loadingFinished();
}
And from your Controller class, must implements MyInterface:
LoaderDienstplan load = new LoaderDienstplan(...);
load.setListener(this);
Make this class:
public class Loader implements Runnable {
private final MyController listener;
private final List<File> stuff;
public DoubleProperty progressProperty;
public Loader(MyController listener, List<File> stuffToLoad) {
this.stuff = stuffToLoad;
progressProperty = new SimpleDoubleProperty();
this.listener = listener;
}
private void updateProgress(double value, double max) {
progressProperty.set(value / max);
}
public DoubleProperty progressProperty() {
return progressProperty;
}
#Override
public void run() {
Platform.runLater(new Runnable() {
public void run() {
//load the stuffs
}
});
//each time you load another stuff, do:
updateProgress(index, totalAmountOfStuffs);
//when finished, do:
listener.finished();
}
}
Put a veil and an indicator around the GridPane, like this (i made the veil (Region) and indicator (ProgressIndicator) from the JavaFX SceneBuilder):
//lets say your progress indicator is called progressIndicator and the shaded `Region` is called veil
progressIndicator.setMaxSize(150, 150);
veil.setStyle("-fx-background-color: rgba(0, 0, 0, 0.4)");
And run the Loader class from another thread like this:
private void startLoading() {
progressIndicator.setVisible(true);
veil.setVisible(true);
Loader loader = new Loader(this, stuffToLoad);
progressIndicator.progressProperty().bind(loader.progressProperty());
new Thread(loader).start();
}
#Override
public void finished() {
progressIndicator.setVisible(false);
veil.setVisible(false);
}
What it looks like for me:
I have a static BorderPane with ContextMenu insight Task
Task task = new Task()
{
#Override
protected Void call() throws Exception
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
try
{
contextMenu = new ContextMenu();
MenuItem item1 = new MenuItem("About");
item1.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
System.out.println("About");
}
});
MenuItem item2 = new MenuItem("Preferences");
item2.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
System.out.println("Preferences");
}
});
MenuItem item3 = new MenuItem("Close");
item3.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
}
});
contextMenu.getItems().addAll(item1, item2, item3);
bp.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>()
{
#Override
public void handle(ContextMenuEvent event)
{
contextMenu.show(bp, event.getScreenX(), event.getScreenY());
event.consume();
}
});
bp.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent event)
{
contextMenu.hide();
}
});
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
}
}
});
return null;
}
};
new Thread(task).start();
I noticed that when I close the component which holds the BorderPane the Java Threads are not disposed they are still initialized into the memory. I'm not sure is this caused by the static BorderPane. After the Task is completed the Java Thread should be disposed. Any idea why is this happening?
The problem is not a Task, but the anonymous classes in your Runnable.
In the next piece of code:
bp.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>()
{
#Override
public void handle(ContextMenuEvent event) {
//...
}
});
you introduce an anonymous class extending EventHandler which holds inner link to a Runnable. To solve that you can use nested static class instead.
P.S.: Unfortunately you can't make anonymous class static in Java, see Is it possible to make anonymous inner classes in Java static?