Launch GUI: facade vs main - java

It is better to launch the user interface from a method in the same class of the main, or from a different class called by the main? Here an example:
From the main
Main.java
package main_version;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
launchGUI();
}
});
}
private static void launchGUI() {
JFrame frame = new JFrame("Main version");
//other code
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(333, 333);
frame.setVisible(true);
}
}
From another class
Main.java
package facade_version;
import javax.swing.SwingUtilities;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
UserInterface.lauch();
}
});
}
}
UserInterface.java
package facade_version;
import javax.swing.JFrame;
public class UserInterface {
public static void lauch() {
JFrame frame = new JFrame("Facade version");
//other code
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(333, 333);
frame.setVisible(true);
}
}

I recommend having each GUI component in a different class, for reusability.
However it makes no big difference for small projects, if one only wants to test something, he can just skip creating multiple classes. It makes no difference for the compiler.

Related

How get data from JFrame Component Java?

I need get some data from "Board" Component but i dont know how. I tried Frame.Component.data but is doesn't work.
Code:
public class window extends JFrame {
public window() {
add(new Board());
setResizable(true);
pack();
setTitle("Game");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame ex = new window();
ex.setVisible(true);
ex.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
//ex.Board.data
System.exit(0);
}
});
});
}}
First a little tip to have a quick answer : reduced your code at the minimun to reproduced your bug its easier to understand especially in your case where your real purpose is in a comment ... and then make it compilable ...
To answer to your issue : personnaly i use dedicated fields to have a direct link to object i want to handle later there is two reason first a field is easy to use and don't use lot of memory . Second this solution will not depend on the way your frame is organised. an other way to get the same result is the second snippet the probelme is that if you change your frame organisation you will have to modify your listener
package so1;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Window extends JFrame {
private static final long serialVersionUID = 3000003489937872937L;
public class Data {
public void doSomethings() {
System.out.println("toto");
}
}
public class Board extends JLabel {
private static final long serialVersionUID = 7362684018638848838L;
private Data data = new Data();
}
private Board board;
public Window() {
board = new Board();
add(board);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
}
public static void main(String[] args) {
Window ex = new Window();
ex.setVisible(true);
ex.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
ex.board.data.doSomethings();
}
});
}
}
the bad solution :
public static void main(String[] args) {
Window ex = new Window();
ex.setVisible(true);
ex.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
((Board)((JPanel)((JLayeredPane)((JRootPane)ex.getComponents()[0]).getComponents()[1]).getComponents()[0]).getComponents()[0]).data.doSomethings();;
}
});
}

Java - Wait for component to be shown

UPDATE #3: After madProgrammer's suggestions, maybe the timed solution is the best. But no answer has been given to this strange behaviour.
I understand the fact that components are not shown immediately and need to be set.
The problem here is the onShow method, which executes correctly if called from onCreate, but doesn't work if called from the callback method "componentShown".
UPDATE #2: Added a componentListener on fragmentContentPane, to see when actually this component is shown and VALID
fragmentContentPane.addComponentListener(new ComponentAdapter(){
public void componentShown(ComponentEvent e){
if (e.getComponent().isValid()) System.out.println("SHOWN AND VALID!");
}
});
UPDATE:
The show method now gets called in EDT.
public void show() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
System.out.println("Showing..");
frame.setVisible(true);
}
});
}
By now, the problem still exists.
Original Post:
I have this code:
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class TEST {
private JFrame frame;
private JScrollPane contentPane;
private JPanel contentViewport;
private JScrollPane fragmentContentPane;
private JPanel fragmentContentViewport;
public TEST() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
onCreate();
}
});
}
public void onCreate(){
System.out.println("On create!");
frame=new JFrame();
contentPane=new JScrollPane();
contentViewport=new JPanel();
contentPane.setViewportView(contentViewport);
frame.setContentPane(contentPane);
frame.addComponentListener(new ComponentAdapter(){
public void componentShown(ComponentEvent e){
onShow();
}
});
}
public void onShow(){
System.out.println("On show!");
fragmentContentViewport=new JPanel();
fragmentContentPane=new JScrollPane(fragmentContentViewport);
fragmentContentPane.addHierarchyListener(new HierarchyListener() {
public void hierarchyChanged(HierarchyEvent e) {
if (e.getChangeFlags()==HierarchyEvent.SHOWING_CHANGED && fragmentContentPane.isShowing()) {
System.out.println("Component is completely shown");
}
}
});
contentViewport.add(fragmentContentPane);
}
public void show(){
frame.setVisible(true);
}
public static final void main(String[] args) throws InvocationTargetException, InterruptedException{
TEST t=new TEST();
t.show();
}
}
The task is simple. I want to get known when the fragmentContentPane has been correctly added and is completely shown.
With this code this never happens, why?
Everything works if the onShow method is called in the ThreadEvent together with onCreate, for example:
public TEST() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
onCreate();
onShow();
}
});
}
any help is appreciated

How to close Threads before opening new Threads in Java?

I have problems with Java's Multi-Threading feature, so hopefully somebody can help me....
Here is my problem:
In the JPanel ExamplePanel which is located in the JFrame ExampleFrame I've added a ComponentListener which invokes the startPaint()-Method. This method should work in a new Thread. My Problem is that by resizing the window "former" Threads aren't closed, meanwhile new Threads are added....
So is there a way to resize the JPanel and to close at the same time the "old" threads, so that the number of threads is not growing, when I resize the JPanel?
I have tried something with a boolean exiter-variable, but it do not seemed to work...
here is the code:
package example;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Example2 {
public static void main(String[] args) throws InterruptedException {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new ExampleFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class ExampleFrame extends JFrame {
private static final long serialVersionUID = 1L;
ExamplePanel examplePanel = new ExamplePanel();
private Thread t=null;
private class ExamplePanel extends JPanel implements ComponentListener {
private static final long serialVersionUID = 1L;
#Override
public void componentHidden(ComponentEvent e) {
}
#Override
public void componentMoved(ComponentEvent e) {
}
#Override
public void componentResized(ComponentEvent e) {
startPaint();
}
#Override
public void componentShown(ComponentEvent e) {
}
private void startPaint() {
t=new Thread(new Runnable() {
#Override
public void run() {
//System.out.println(Thread.currentThread().getName());
while (true) {
//System.out.println(Thread.activeCount());
}
}
});
t.start();
}
}
public ExampleFrame() {
examplePanel.addComponentListener((ComponentListener) examplePanel);
getContentPane().add(examplePanel);
}
}
if the calculations don't take long don't use an extra Thread.
if you need this extra Thread make sure that it doesn't run forever (no while (true) without returning at some point)
you can always interrupt your running Thread bfore creating the new one
if (t != null && t.isAlive()) {
t.interrupt();
}
and check in the while(true) loop if the Thread is interrupted
if (t.isInterrupted()) {
System.out.println("Thread ended");
return;
}
hope this helps

Java dialog does not dispose

Java noob here. My Swing class that extends JDialog does not dispose when the user presses the Windows Close button - java.exe stays in memory. I've stripped the code right down to this shell, I still get this behaviour.
I took a look at other samples, such as at Basic Java Swing, how to exit and dispose of your application/JFrame
When I commented out the two System.exit(0) lines in that sample code, the class in that sample still disposed correctly. What am I missing to make my class dispose?
import javax.swing.JFrame;
import javax.swing.JDialog;
public class WhyNoDispose extends JDialog{
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
WhyNoDispose frame = new WhyNoDispose("my title");
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
frame.setVisible(true);
//System.exit(0);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
public WhyNoDispose(String title) {
super(new JFrame(title), ModalityType.APPLICATION_MODAL);
pack();
}
}
You're creating a JFrame and never disposing it here:
public WhyNoDispose(String title) {
super(new JFrame(title), ModalityType.APPLICATION_MODAL); // *********
pack();
}
So since the JFrame is alive and a GUI has been rendered, the Swing event thread keeps on running.
If you instead make the JFrame behave so that the program exits on JFrame close, and then explicitly dispose of the JFrame, your program now exits:
import java.awt.Window;
import javax.swing.JFrame;
import javax.swing.JDialog;
public class WhyNoDispose extends JDialog {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
WhyNoDispose frame = new WhyNoDispose("my title");
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
JFrame win = (JFrame) frame.getOwner();
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
win.dispose();
// System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public WhyNoDispose(String title) {
super(new JFrame(title), ModalityType.APPLICATION_MODAL);
pack();
}
}
But this is very kludgy code, to say the least -- what if the owning window isn't a JFrame? What if it's null?
Another solution is to use no JFrame at all, so that when the JDialog is disposed, there's no persisting window left over to make the event thread persist:
import java.awt.Window;
import javax.swing.JFrame;
import javax.swing.JDialog;
public class WhyNoDispose extends JDialog {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
WhyNoDispose frame = new WhyNoDispose("my title");
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public WhyNoDispose(String title) {
super((JFrame)null, title);
pack();
}
}

Java Architecture - Question about ActionListener Conventions

I am making a user interface which shows graphs and manipulates graphs. The class extends JFrame implements ActionListener. The ActionListener then calls different classes to manipulate graphs depending on the action. This worked while the class had few ActionListeners; however, now the class is becoming unmanageable.
I know that in the interest of encapsulation, it would be best to have the ActionListener within the user interface class because it needs to access non-static components of the interface. However, it seems like there is a conflict between encapsulation and readability.
What I am proposing is breaking the class into one class for the interface and a second for the ActionListener and accessing the interface components statically. What I want to know is does this follow basic design conventions? And, if this is an acceptable approach would you place the main class in the user-interface class or the ActionListener class?
Not a duplicate question... but my answer should help with your question.
Short summery, my preference would be to have the JFrame class not implement ActionListener and then have a number of named inner classes withing the JFrame that do implement the ActionListener.
I would place the main in a class unto itself... and call it Main.
Here is some sample code for the way I like to do it:
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Main
{
private Main()
{
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
final FooFrame frame;
frame = new FooFrame();
frame.setupGUI();
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
and then the GUI:
import java.awt.FlowLayout;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class FooFrame
extends JFrame
{
private final JButton incrementBtn;
private final JButton decrementBtn;
private int value;
{
incrementBtn = new JButton("++");
decrementBtn = new JButton("--");
}
private class IncrementListener
implements ActionListener
{
public void actionPerformed(final ActionEvent evt)
{
increment();
}
}
private class DecrementListener
implements ActionListener
{
public void actionPerformed(final ActionEvent evt)
{
decrement();
}
}
public void setupGUI()
{
final LayoutManager layout;
layout = new FlowLayout();
setLayout(layout);
setupListeners();
addComponents();
}
private void setupListeners()
{
incrementBtn.addActionListener(new IncrementListener());
decrementBtn.addActionListener(new DecrementListener());
}
private void addComponents()
{
add(incrementBtn);
add(decrementBtn);
}
private void increment()
{
value++;
System.out.println("value = " + value);
}
private void decrement()
{
value--;
System.out.println("value = " + value);
}
}

Categories