given the following code:
public class MainFrame extends JFrame{
public MainFrame() throws HeadlessException {
super();
this.setSize(500, 400);
this.setVisible(true);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JButton myButton = new JButton("Test");
this.add(myButton);
this.pack();
}
public static void main(String[] args) {
new MainFrame();
}
}
Does the code inside the constructor run on the EDT. I think it does because it's executed "inside" an instance of a JFrame, but I need a second opinion.
Continuing the idea, If I were to create other controls, for example in the main() function, that code wouldn't be on the EDT?
Thank you!
No. You are calling the constructor from the main method which runs on the main thread.
Add the usual boilerplate:
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
new MainFrame();
}});
}
Also it's generally a bad idea to extend classes that you don't need to (including JFrame, JPanel and Thread). There is no need to declare HeadlessException as it is unchecked.
Related
Introduction
I'm learning how to present GUIs for user 'friendly' input. I will reference below some web pages for those who are interested in the matter.
Code
public class TestGUI{
private JFrame mainFrame;
private JLabel headerLabel;
private JLabel statusLabel;
private JPanel controlPanel;
public TestGUI()
{
prepareGUI();
}
private void prepareGUI()
{
mainFrame = new JFrame("TestGUI"); //Header name
mainFrame.setSize(420, 320); //Size of the frame
mainFrame.setLayout(new GridLayout(3, 1)); //??
mainFrame.addWindowListener(new WindowAdapter() //Waits for an user event
{
//When the frame is closes, the program does too.
#Override
public void windowClosing(WindowEvent windowEvent)
{
System.exit(0); //Exit program
}
});
mainFrame.setVisible(true);//GUI is visible
}
public static void main(String[] args) {
TestGUI test = new TestGUI(); //constructor
test.prepareGUI(); //Call the method
}
}
Problem
While running the code I saw that 2 identical frames pop up. I went to debug it and saw that it is executed twice when I call the method!
Why is that?
I only called it once with testGUI.prepareGUI(); in the main function.
Webpages for learning basic GUI in Java
JavaFX
GUI Programming with AWT
You call prepareGUI() in the constructor as well.
public TestGUI()
{
prepareGUI();
}
When you call new TestGUI(), this constructor gets called and so does the function.
You are calling prepareGui twice
Once here
public TestGUI()
{
prepareGUI();
}
and once here
TestGUI test = new TestGUI(); //constructor
test.prepareGUI(); //Call the method
so first block is executed on new TestGUI() call
You are calling the prepareGui() method twice. One in your constructor and once on your created object (in the main method)
The issue is that constructor (that is TestGUI()) you are already calling prepareGUI(). so just omit the other call to prepareGUI(), which is test.prepareGUI().
I'm trying to build a calculator.
I've developed the interface using the Swing plug-in (containers and controls), but when I try to run my program it says the package needs a main class.
Already tried to create a main class and call the Calc() JFrame class, but it didn't work.
Take a look at the code:
public class Calc extends javax.swing.JPanel {
public Calc() {
initComponents();
}
}
You need a main() method to execute your class.
Take a look at the FrameDemo example code found in the Swing tutorial on How to Make Frames for a basic example to get you started.
/* FrameDemo.java requires no other files. */
public class FrameDemo {
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("FrameDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(175, 100));
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
test.java
import javax.swing.JFrame;
public class test {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setSize(600, 600);
}
}
My Other java File test2.java
import javax.swing.JButton;
public class test2 {
public static void main(String[] args) {
JButton Button = new JButton();
frame.add(Button);
}
}
am trying to call frame to test2.java
The reason you are getting this problem:
When you run a java application, the application's main function will be called. Therefore you should really only have one main function per application.
In your scenario you had 2 main functions. Think of this as 2 different applications. The following scenarios were happening:
When you run the Test class, your application was creating a new JFrame object. That's pretty much it, it ended there. It had no idea that the Test2 class existed.
When you run the Test2 class, your application was creating a new JButton object. Although, your Test2 class had no reference to the frame variable (that is why you were getting an error). It didn't even know there was a Test class.
In order to fix this in your situation, try this:
Test.java
public class Test
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setSize(600, 600);
// By passing the frame as a reference, the function
// will be able to add the button to this frame.
Test2.addButton(frame);
}
}
Test2.java
public class Test2
{
public static void addButton(JFrame frame)
{
JButton button = new JButton();
frame.add(button);
}
}
A more OOP approach:
Here, I made a Driver class that would connect the Test2 and MyFrame classes together.
Driver.java
public class Driver
{
public static void main(String[] args)
{
MyFrame frame = new MyFrame();
Test2.addButton(frame);
}
}
MyFrame.java
public class MyFrame extends JFrame
{
public MyFrame()
{
this.setSize(600, 600);
this.setVisible(true);
}
}
Test2.java
public class Test2
{
public static void addButton(JFrame frame)
{
JButton button = new JButton();
frame.add(button);
}
}
I assume you're trying to add Button to the JFrame frame you created in test To do this, you'll need to make frame visible to what is essentially the global scope, as such:
import javax.swing.JFrame;
public class test {
public static JFrame frame;
public static void main(String[] args) {
frame = new JFrame();
frame.setVisible(true);
frame.setSize(600, 600);
test2.main(args)
}
}
and then, to add the button in test2, you need to access test by name
import javax.swing.JButton;
public class test2 {
public static void main(String[] args) {
JButton Button = new JButton();
test.frame.add(Button);
}
}
This question already has answers here:
Extends JFrame vs. creating it inside the program
(6 answers)
Closed 7 years ago.
so I've found multiple ways of implementing a swing GUI in java but don't know what each does and my teacher isn't able to help me. One method of creating a JFrame is:
import javax.swing.*;
import java.awt.*;
public class UI extends JFrame{
public UI() {
initaliseGUI();
}
private void initaliseGUI(){
setTitle("My Title");
setBackground(Color.red);
setSize(800,500);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args){
EventQueue.invokeLater(new Runnable(){
#Override
public void run(){
UI M = new UI();
M.setVisible(true);
}
});
}
But another way of implementing it is:
import javax.swing.*;
import java.awt.*;
public class Main{
public static void main(String[] args){
JFrame window = new JFrame();
window.setSize(500,500);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = window.getContentPane();
c.setBackground(Color.red);
window.setBackground(Color.red);
window.setTitle("main");
JLabel message = new JLabel("JLabel");
window.add(message);
window.setVisible(true);
}
}
what is the difference between how each one works and when should I use one over the other and how does the runnable work in this context?
thankyou!
Your first example calls the EventQueue invokeLater method, but extends a JFrame.
Your second example puts everything in the static method main, and doesn't run the invokeLater method.
Here's one way I start a Swing application.
public class TryingProject2 implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new TryingProject2());
}
#Override
public void run() {
JFrame frame = new JFrame("Color Gradient Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel();
// Add your Swing components here
return panel;
}
}
I don't extends Swing components. I use Swing components. The only time you extend a Swing component, or any Java class, is when you want to override one of the class methods.
The SwingUtilities invokeLater method is the same as the EventQueue invokeLater method. This method puts the creation and updates of all Swing components on the Event Dispatch thread.
I implement Runnable because it makes the invokeLater method parameter an instance of the class.
I create the main panel in a method to keep the JFrame code separate from the JPanel(s) code.
I have the following Java Program which one starts in about 50% of all launch attempts. The rest of the time it seams to deadlock in the background without displaying any GUI. I traced the problem to the setText method of the JTextArea Object. Using another Class like JButton works with setText but JTextArea deadlocks. Can anyone explain to me why this is happening and what is wrong with the following code:
public class TestDeadlock extends JPanel {
private JTextArea text;
TestDeadlock(){
text = new JTextArea("Test");
add(text);
updateGui();
}
public static void main(String[] args){
JFrame window = new JFrame();
window.setTitle("Deadlock");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.add(new TestDeadlock());
window.pack();
window.setVisible(true);
}
public synchronized void updateGui(){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
System.out.println("Here");
text.setText("Works");
System.out.println("Not Here");
}
});
}
}
your main method must be wrapped into invokeLater or invokeAndWait, that's basic Swing rule to create Swing GUI on EventDispashThread
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame window = new JFrame();
window.setTitle("Deadlock");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.add(new TestDeadlock());
window.pack();
window.setVisible(true);
}
});
}