I had some previous experience to swing applications at school, so I know how they work and will be fine designing them, but I am unsure of the best way to set my application up.
We only created smaller programs at school so we had almost all of our code in the constructor, but I want to create something larger, and am unsure of how I should set things up.
I have my base class with the constructor that will create my JFrame that I will use throughout the application, but what classes do I make to add my components, or use action listeners? I am unsure exactly of the proper way to do this, so a guiding step would be great.
Here is my class declaration/constructor:
public class SwingApp1 extends JFrame{
public SwingApp1() {
setTitle("Greens Tracker");
setSize(800,500);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
}
Now what do I put in my main, and in what manor should I be adding components?
Any help is appreciated, thanks!
Good way of setting up your JFrame is
public GUI() {
buildGUI();
}
private void buildGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setSize(500, 300);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new GUI().setVisible(true);
}
});
}
I hope it helped :)
The program starts at the main as:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new SwingApp1().setVisible(true);
}
});
}
which can be abbreviated since Java 8 as:
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new SwingApp1().setVisible(true));
}
The JFrame constructor could be as follows. A setVisible I leave to the call,
and pack() will layout the contents.
public SwingApp1() {
setTitle("Greens Tracker");
setSize(800,500);
... add components, maybe in a separate method.
pack();
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
Actually look into MVC, Model View Controller.
I generally maky an XyzApplication class as controller, the JFrame being the main view and the separately kept data (in the application) the model.
It should be mentioned, that JavaFX may be slightly more advisable, say without FXML layout files. A bit more learning involved, but nicer behavior.
Other advise would be to use a build infrastructure like maven. That helps with libraries ("dependencies") and provides "best practices" like build directories (src/main/java, src/test/java, src/main/resources ...).
Of course a version control system like git or mercurial.
Related
Today, I am working on an Eclipse plugin project, where I am using the standard SWT_AWT bridge in order to plug my Swing components in:
public class MyView extends ViewPart {
public static final String ID = "HelloRCP.view";
Frame frame;
public void createPartControl(Composite parent) {
Composite composite = new Composite(parent, SWT.EMBEDDED | SWT.NO_BACKGROUND);
this.frame = SWT_AWT.new_Frame(composite);
SwingUtilities.invokeLater(new Runnable() {
private MainPanel swingPanel;
public void run() {
this.swingPanel = new MainPanel();
frame.add(swingPanel);
}
});
this.setResizeListener();
}
public void setFocus() {}
private void setResizeListener() {
this.frame.addComponentListener(new frameResizeListener(this));
}
public Frame getFrame() { return this.frame; }
}
I would like to get the "frameResizeListener" to somehow trigger an update of all subsequent Swing components (e.g. JPanels) constructed by the Swing Runnable instance, this upon the ViewPart's size-change, in order to achieve some kind of responsive design.
Somehow then, the underlying JPanels need to get to know about the ViewPart's Frame size...
I have read my fair share of SO Q&As, and only found the answer that "you need to pass a parameter at construction time". But my problem with this is that my usecase happes once the Components in question are already created and living...
The only solution that I see, so far, seems to break Thread-safety, by writing a shared file or property, and then signalling the Runnable to read it once done.
Can anyone else think of a better option please?
Thank you very much in advance for your support ! :) :)
Regards,
Peter
I am writing a java program which have a big amount of different GUI objects and GUI class file became huge. I wanted to ask if there is a way to separate these internal files in different files and if so, how to do that.
The general structure of the GUI(Runner)class is following
public class Gui extends JFrame{
<componendt definition>
public Gui()
{
<component initialization>
<containers and adding objects to container>
<attaching listeners>
// for example
generate_button.addActionListener(new generate_ButtonHandler());
}
// I want to separate these classes in different files
class generate_ButtonHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
<some suff>
}
}
public static void main(String[] args) {
JFrame f = new Gui();
f.setVisible (true);
f.setDefaultCloseOperation (EXIT_ON_CLOSE);
}
}
Or may be there is another solution how to handle these big files
You could try implement each UI part as separate component, and encapsulate most
code in the component. That will reduce amount of service code.
I am making a Java gui project and it consists of two frames.
The problem is that when I call the secondframe from the firstframe, I have set it such that the firstframe visibility is set to false. The problem is how do I make the firstframe visible again by using a button from the second frame.
should i ditch this method and create a new jpanel instead??? Does jpanel have similar capabilities as jframe?
Consider using CardLayout. This way you can switch via multiple UIs without needing another frame. Here's how to use it.
Edit: As Guillaume posted in his comment, this answer from Andrew also covers how to use the layout.
Edit2:
As you requested a little more information about my latest post, here's how such a class may look like:
import javax.swing.JFrame;
public abstract class MyFrameManager {
static private JFrame startFrame,
anotherFrame,
justAnotherFrame;
static public synchronized JFrame getStartFrame()
{
if(startFrame == null)
{
//frame isnt initialized, lets do it
startFrame = new JFrame();
startFrame.setSize(42, 42);
//...
}
return startFrame;
}
static public synchronized JFrame getAnotherFrame()
{
if(anotherFrame == null)
{
//same as above, init it
}
return anotherFrame;
}
static public synchronized JFrame getJustAnotherFrame()
{
//same again
return justAnotherFrame;
}
public static void main(String[] args) {
//let's test!
JFrame start = MyFrameManager.getStartFrame();
start.setVisible(true);
//want another window
JFrame another = MyFrameManager.getAnotherFrame();
another.setVisible(true);
//oh, doenst want start anymore
start.setVisible(false);
}
}
This way you would only instantiate every JFrame once, but you could always access them via your manager class. What you do with them after that is your decision.
I also just made it thread-safe, which is crucial for singletons.
So the program I am making uses 2 threads: One for the GUI and one to do the work.
I want updates from the work thread/class to print out on JTextArea in GUI class.
Everything I tried didn't seem to work. I added lines to print out text on the console right after lines to add text to the JTextArea to make sure it had got to the line but everytime console got text but no changes happened to JTextArea in the GUI.
public static void consoleText(String consoleUpdate){
GUI.console.append(consoleUpdate);
}
I tried this in the work class but nothing happened.
Anyone know how to fix my problem?
Edit:
MAIN.JAVA
public class main {
public static void main(String[] args) {
Thread t1 = new Thread(new GUI());
t1.start();
}
GUI.JAVA
public class GUI extends JFrame implements Runnable{
public static JTextArea console;
private final static String newline = "\n";
public void run(){
GUI go = new GUI();
go.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
go.setSize(350, 340);
go.setVisible(true);
}
public GUI(){
setLayout(new FlowLayout());
console = new JTextArea(ConsoleContents, 15, 30);
add(console);
}
WORK.JAVA
...{
consoleText("\nI want this text on the JText Area");
}
public static void consoleText(String consoleUpdate){
GUI.console.append(consoleUpdate);
}
First, as has been said, your GUI should only run on the Event dispatch thread.
As it is written, your GUI class does two things : it's a frame, and a runnable, and both
are used completely independently. As a matter of fact, calling "run" on a your GUI object creates another, unrelated GUI object. That's probably the reason why you see nothing.
So I suggest making your main the following:
... main(...) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GUI gui= new GUI();
gui.setVisible(true); // and other stuff
}
});
}
(I would also suggest getting rid of all "static" fields BTW. It's probably the source
of your problems, along with the weird place of the "run" method).
Now, your "consoleText" method, which I assume you call from another thread, should not
modify the text directly, but call SwingUtilities.invokeLater() to do so :
public void consoleText(final String consoleUpdate){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
console.append(consoleUpdate);
}
});
}
(the "final" declaration is important, as it allows the Runnable to use the consoleUpdate variable).
When I am running this, JLabel is not visible, but when I resize window (with mouse) JLabel is showed. Why?
import javax.swing.*;
import java.awt.*;
public class FrmTaoLogin extends JFrame {
private JPanel pnlLeft = new JPanel();
public FrmTaoLogin() {
super();
pnlLeft.setBorder(BorderFactory.createEtchedBorder());
pnlLeft.add(new JLabel("test1"));
getContentPane().add(pnlLeft,BorderLayout.SOUTH);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(200, 200);
}
public static void main(String[] args) {
FrmTaoLogin FrmLogin = new FrmTaoLogin();
FrmLogin.setVisible(true);
}
}
IIRC, this happens when you don't call Frame.pack(). It should work if you call 'pack()' as the last line of the constructor.
I suspect that the problem here may have to do with trying to build and show your GUI components outside of the Swing thread.
What if you change main() to invoke your GUI code on the Swing thread, like this?
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
FrmTaoLogin FrmLogin = new FrmTaoLogin();
FrmLogin.setVisible(true);
}
});
}
This look like some of the L&F bugs in older Java VMs on newer OS. For example on Windows 7 the most problems are solved first with 1.6.0_17. You should start your program with a console. If you see some stacktraces in the event thread then it is a problem of an L&F bug.
Thanx to all, problem resolved. I change Windows theme and all working fine. I think that's Windows Aero and my NVIDIA GeForce FX5500 problem. This card official not working with windows Aero.