PDA

View Full Version : Java: GUI help


TR_Twiggy
02-17-2006, 10:13 AM
I have never programmed with a GUI before, but I want to learn so I am trying to write one with two buttons on it I want them side by side and I want one to close the application and the other one to execute my ftp code that I will later add once I finish the GUI. Here is what I have so far and at the top where i create the buttons it keeps telling me invalid method declaration; return type required. right now I have it set up to beep once click becuase I have no idea how to close the program yet.

/**
* Export
* This is just the frame for the Export program
*
* @Tyler Reid AKA TR_Twiggy
*
* @V 1.0b
**/

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;


public class ExportFrame {
public class ExportFrame implements ActionListener {

JButton pull;
JButton close;

public execute() {
super(new BorderLayout());
pull = new JButton("Pull");
pull.setMnemonic('p');
pull.setPreferredSize(new Dimension(20, 15));
add(pull, BorderLayout.LEFT);
pull.addActionListener(this);
}

public close() {
super(new BorderLayout());
close = new JButton("Close");
close.setMnemonic('c');
close.setPreferredSize(new Dimension(20, 15));
add(close, BorderLayout.Right);
close.addActionListener(this);

}

public void actionPerformed(ActionEvent e) {
Toolkit.getDefaultToolkit().close();
Toolkit.getDefaultToolkit().execute();
}



private static void createAndShowGUI(){
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);

//Create and set up the window.
JFrame frame = new JFrame("Stratis Export by Tyler Reid");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);









//Shows the UI
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();
}
});
}


} }

SS2K4
02-17-2006, 11:25 PM
Hi, i've edited your code a bit so you can get the idea of how to set up a GUI and make your buttons do what you want, you don't have to use my code if you dont want to. I'ts just a guide to help you.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ExportFrame extends JFrame implements ActionListener {

Container pane;
JButton pull, close;

public ExportFrame() {
super("App Name");

pane = getContentPane();
pane.setLayout(new FlowLayout());

pull = new JButton("Pull");
close = new JButton("Close");

pull.setMnemonic('p');
close.setMnemonic('c');

close.setActionCommand("close");

pull.addActionListener(this);
close.addActionListener(this);

pane.add(pull);
pane.add(close);
}

public void actionPerformed(ActionEvent e) {
if ("close".equals(e.getActionCommand())) {
System.exit(0);
}
if ("pull".equals(e.getActionCommand())) {
// do stuff
}
}

public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);

ExportFrame frame = new ExportFrame();

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setSize(400, 400);
//frame.pack();
frame.setVisible(true);
}

}

Ender
02-18-2006, 02:41 AM
Here's the jist of Java GUI building. I'm going to teach you about the basics, listeners, interfaces, layouts, and style. All references to class names are based on the AWT and Swing packages (which most people use). A topic I don't address is threads, but for that's not necessary for simple GUIs (and by simple, I mean no animations, etc.; it can have a lot of components to it and look nice, and still be simple). Threads would have made this response a bit too long (if it's not too long already).

I. Basics

So the conventional pattern for making a GUI is that you extend JFrame, add JPanel(s) to it, and group your components inside the JPanel(s). For some of the common components, such as a JMenuBar, you use JFrame's interface for adding these components, instead of adding them to the JPanel(s). Of course, there are other ways of doing it, like embedding JFrame, but this is a quick, easy, and conventional way of doing it.

Your JFrame should be a top-level class, and oftentimes programmers put their main function inside this JFrame class.

public class MyJFrameClass extends JFrame
{
...
public static void main(String[] args)
{
MyFrameClass application = new MyFrameClass();
application.setVisible(true);
// The method which sets a JFrame visible. It used to be show(), but
// that was deprecated and replaced with setVisible(boolean).
}
}

Just like every other class in the JRE System Library, JFrame is documented on the Sun website at http://java.sun.com/j2se/1.5.0/docs/api/. If you're not already familiar with this documentation, it's important to become so. I sort of assume in this tutorial that you're familiar with it, so when I talk about some broad concepts I assume you'll look into the details yourself.

II. Listeners

Now, as for listeners. Every java.awt.Component has an addXListener() method (the X is a variable (i.e. Action, Menu, etc.) ). What this basically does is register a listener object with the component so that when the component is acted upon, it casts itself into a type of Event and sends itself to the listener. The listener can then identify what kind of Event it is, and more specifically, its class etc., and do something based on that.

III. Interfaces

Listeners are interfaces. I'll fill you in on interfaces, in case you're not familiar with them. Interfaces are a list of methods. Alone, they may not sound like much, but they are an essential part of OOP. If an object implements an interface, then that means that any object can rely on calling a method of that object that is listed in its interface. Interfaces don't define methods, they involve no implementation - and for good reason. What if a Listener interface's methods were implemented? You'd have to override them every time you use the interface. It would be pointless. A common OOP theme is program to an interface, not an implementation. Implementation is when you have a class extend another class and inherit concrete members from that class. It could be a base class or an abstract class (an abstract class is not termed as concrete yet it still can have concrete members). The reason behind this theme is that changes in a base class can affect all child classes down the line of inheritance. Lets say you have a long line of inheritance - that's going to be a lot of classes affected by a few changes! Interfaces give you flexibility - since there is no implementation, you don't have to worry about changes rippling throughout your entire program.

Another key thing about interfaces - just like class inheritance, interface implementation means that the object can take the type of the interface. This means that objects don't necessarily have to know the immediate class of an object, if they know one of its types. You can implement multiple interfaces, whereas you can only extend one class. Java purposely refrained from multiple inheritance, replacing it with the ability to implement multiple interface, for the reason mentioned above: programming to an implementation can lead to base changes rippling throughout the entire program. The reason I am talking so much about interfaces is that it is a key part of GUI building.
Interfaces are not only used in GUI building, they extend to all aspects of programming (i.e. packet structures in socket programming, command handling, etc.).

Note: Implementation isn't evil, it's very useful and great to use. You just have to be careful when using it and aware of when it's better to use an interface instead of implementation. You may get a better idea of this as you read further.

IV. Layouts

Layouts, IMHO, are the most annoying part of GUI building. They can be very tedious. Basically, the convention is to have each JPanel in your JFrame have a different layout. You can make JFrames have layouts, as well, but doing it with your JPanels provides more flexibility, as you can have different layouts for different components in your GUI. Basically, the java.awt.Container.setLayout(LayoutManager) method is what you use to set your layout. Some common LayoutManagers (this is an interface, by the way) are BorderLayout (NSEW) and GridBagLayout (lets you specify where you want your components based on a two-dimensional xy grid). You then use JPanel's add(...) methods to add a component with the given constraints (you use the members of your layout manager to specify the constraints). I would suggest starting out with BorderLayout before using GridBagLayout, as BorderLayout is much easier to use.

V. Style

Here's where we get into some code examples of good practices in Java GUI building. I'm going to give you some sample code (which, btw, isn't meant to be compiled; it's only meant to serve as an example).

public class MyJFrameClass extends JFrame
{
private Reporter reporter;
private Ears listener;
private JPanel jContentPane;
private JMenuBar jMenuBar;
private MyButton fibonacciButton;
// ...

public static void main(String[] args)
{
MyJFrameClass application = new MyJFrameClass();
application.setVisible(true);
}

private class Ears implements ActionListener, MenuListener // ..., etc.
{
public void actionPerformed(ActionEvent evt)
{
// Look at how easy this is!
// By using interfaces, this method doesn't have to
// determine what type of component it is, it only has to know
// that every component has a Command interface
Command cmd = (Command) evt;
cmd.execute();

}
}

public MyJFrameClass()
{
// Some sample JFrame settings
// Instead of grouping things in multiple JPanels
// I use some of JFrame's methods for adding common
// components
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBackground(java.awt.SystemColor.control);
this.setSize(600, 400);
this.setJMenuBar(getJMenuBar());
this.setContentPane(getJContentPane());
this.setTitle("My Title");
// ...
reporter = new Reporter(getJContentPane());
}

private JPanel getJContentPane()
{
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.setPreferredSize(new Dimension(..., ...));
jContentPane.setBackground(java.awt.Color.white);
jContentPane.setBorder(...);
jContentPane.add(MyComponent, MyConstraints);
// Example of adding a component with constraints
jContentPane.add
(getFibonacciButton(), BorderLayout.EAST);
// ...
}
return jContentPane;
}

private JMenuBar getJMenuBar()
{
if (jMenuBar == null) {
jMenuBar = new JMenuBar();
jMenuBar.add(...);
// ...
}
return jMenuBar;
}

private JButton getFibonacciButton()
{
if (fibonacciButton == null) {
fibonacciButton = new MyButton("Fibonacci");
}
return fibonacciButton;
}
}

// The Command interface
public interface Command
{
public void execute();
public CmdType getType().
}
// Each Command will have a CmdType field
public enum CmdType
{
FIBONACCI, WHATEVER_1, WHATEVER_2 // etc.
}

// Now for an example of a Command implementation
public class MyButton extends JButton implements Command
{
private CmdType type;

public MyButton(String title)
{
super(title);
type = CmdType.FIBONACCI;
}

public void execute()
{
int a = 0, b = 1, c = 0;
Reporter.print(c + ", ");
// Lets print out 100 more numbers in the Fib. sequence
for (int i = 0; i < 100; i++) {
c = a + b;
a = b;
b = c;
Reporter.print(c + ", ");
}
}

public CmdType getType()
{
return type;
}
}

public class Reporter
{
// Declare fields here for the components it has to know about
// For writing things onto GUI
public Reporter(...)
{
// Assign fields with the references passed by value to the constructor
// ...
}

public static void println(String text)
{
// ...
}

public static void print(String text)
{
// ...
}

public static void print(char c)
{
// ...
}

public static void print(int i)
{
// ...
}
}


One more thing: Mediators. Mediators are basically objects that hold references to many of your GUI components. Each GUI component (Command) has a reference to the mediator, and can call methods of the Mediator so as to indirectly talk to other components/Commands. This makes it so that each individual component does not have to know about all the different components it needs to talk to, only the mediator, who in turn holds the references. Mediators are used in complex GUIs where GUI components affect other GUI components. The way to do it is either to hand the Mediator references to components in its constructor, or to provide registerComponent() methods in the Mediator's interface and have the Mediator keep a list of generic JComponents. Example:


public class EventMediator<K,V>
{
// list of components
private HashMap<K,V> hm;

public EventMediator()
{
hm = new HashMap<K,V>();
}

public void add(K key, V value)
{
hm.add(key, value);
}

public void changeBGColor(Color c)
{
if (hm.contains("Background"))
((Component) hm.get("Background")).setBackgroundColor(c);
}
}

// This class doesn't have to know about any GUI components. It relies on
// the mediator to carry out its calls to other GUI components.
public class ChangeColorButton extends JButton implements Command
{
private EventMediator med;
private CmdType type;

public ChangeColorButton(EventMediator med, String title)
{
super(title);
this.med = med;
type = CmdType.COLOR_BUTTON; // Made up
}

public void execute()
{
med.changeBGColor(java.awt.Color.BLUE);
}

public CmdType getType()
{
return type;
}
}

TR_Twiggy
02-21-2006, 12:22 PM
Awesome extremely helpful posts. They answered alot of questions. I am gonna try to get the two buttons working then it will be on to text boxes. Thank you very much for the help.

TR_Twiggy
02-21-2006, 12:42 PM
I was just trying to type up a rough draft and was wondering in this statement below if I could use Hex.


jContentPane.setBackground(java.awt.Color.white);

Ender
02-21-2006, 03:21 PM
You have to pass the setBackground(Color) method a Color, as shown here (http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Component.html), but you can create a Color object with an integer parameter representing the color. For hex, you just have put an 0x next to the number, so that Java knows it's hex.

jContentPane.setBackground(new Color(0xFFFFFFFF));


EDIT: linked to java.awt.Component api

TR_Twiggy
02-22-2006, 01:32 AM
Great thank you.

TR_Twiggy
02-22-2006, 01:54 AM
Sorry, but I have alot of questions here is another one. I was looking through the Java documentation with that link, and I found this:

p.add(new Button("Okay"), BorderLayout.SOUTH);

In my code I went with a FlowLayout for the buttons, but I wanted them at the bottom of the GUI so I put:

button.add(pull, FlowLayout.SOUTH);
button.add(close, FlowLayout.SOUTH);


With that I keep getting a "cannot find symbol variable SOUTH" I was reading a little more and was just wondering if that is possible with the FLowLayout or do I need to specify the alignment, Hgap, and Vgap to get it to the bottom, or should I just use a GridBagLayout?

Spookster
02-22-2006, 01:59 AM
The Java API is your friend.

http://java.sun.com/j2se/1.5.0/docs/api/java/awt/FlowLayout.html

SOUTH is not a valid field for that object.

SS2K4
02-22-2006, 03:12 AM
Hi, following on from my example above, i've set the content pane layout to BorderLayout and created a JPanel for you buttons, then added the JPanel to the BorderLayout SOUTH... see if this is of any help to you.
also you might want to check out this site (http://leepoint.net/notes-java/) mostly the right column

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ExportFrame extends JFrame implements ActionListener {

Container pane;
JButton pull, close;
JPanel bottomPanel;

public ExportFrame() {
super("App Name");

bottom();

pane = getContentPane();
pane.setLayout(new BorderLayout());

pane.add(bottomPanel, BorderLayout.SOUTH);
}

public void bottom() {
bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));

pull = new JButton("Pull");
close = new JButton("Close");

pull.setMnemonic("p");
close.setMnemonic("c");

close.setActionCommand("close");

pull.addActionListener(this);
close.addActionListener(this);

bottomPanel.add(pull);
bottomPanel.add(close);
}

public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("close")) {
System.exit(0);
}
if (e.getActionCommand().equals("pull")) {
//do stuff
}
}

public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);

ExportFrame frame = new ExportFrame();

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setSize(400, 400);
//frame.pack();
frame.setVisible(true);
}

}

TR_Twiggy
02-22-2006, 08:23 AM
Thank you very much I found that site a little easier to understand than the API site.

TR_Twiggy
02-23-2006, 11:49 AM
I haven't had that much time to really work on this lately, but I have put some time into it and this is what I have gotten so far with your help and that Java notes site. I was just posting to get some suggetions on anything that I can do better or in a different way than I have done it.


/**
* Export
* This is just the frame for the Export program
*
* @Tyler Reid AKA TR_Twiggy
*
* @V 1.0b
**/

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;


public class ExportFrame extends JFrame implements ActionListener {

Container ct;
JButton pull, close;
JTextField jd, p;
JPanel input, button;


public ExportFrame(){

super("Stratis Export");

ct = getContentPane();
ct.setLayout(new BorderLayout(20, 70));
ct.setBackground(new Color(0x3366CC));

action();
ct.add(button, BorderLayout.SOUTH);

text();
ct.add(input, BorderLayout.CENTER);

}


public void action(){

button = new JPanel();
button.setLayout(new FlowLayout(FlowLayout.CENTER));
button.setBackground(new Color(0x3366CC));



//Set up pull button
pull = new JButton("Pull");
pull.setMnemonic('p');
pull.addActionListener(this);
pull.setBackground(new Color(0x3399FF));
button.add(pull);

//Set up close button
close = new JButton ("Close");
close.setMnemonic('c');
close.setActionCommand("close");
close.addActionListener(this);
close.setBackground(new Color(0x3399FF));
button.add(close);


}


//function for the Jpanel for the textboxes
public void text(){


//Set up the Jpanel
input = new JPanel();
input.setLayout(new BoxLayout(input, BoxLayout.Y_AXIS));


//Set up the text fields for user input
jd = new JTextField(10);
p = new JTextField(10);
input.add(jd);
input.add(p);

}



public void actionPerformed(ActionEvent e) {
if ("close".equals(e.getActionCommand())) {
System.exit(0);
}
if ("pull".equals(e.getActionCommand())) {
// do stuff
}
}



public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);

ExportFrame frame = new ExportFrame();

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setSize(300, 200);
//frame.pack();
frame.setVisible(true);
}

}

Ender
02-23-2006, 11:44 PM
That's a great way to learn :). Here are some comments.

First off, your fields should be private. Encapsulation (http://java.sun.com/docs/books/tutorial/java/concepts/object.html)

In your actionPerformed() method, the use of string comparisons are fine, but if you have a lot of components, then you'll probably want to switch them. You can't switch strings in Java (and most other programming languages), but you can switch enums, which is a way around it. I suggest you look up enums if you have never used them before. Basically, you convert a String to an enum and switch that. I honestly don't know why people complain so much for the lack of switching strings. Here's an example:
MyEnum enum = MyEnum.valueOf(myString.toUppercase());
// Assumes your enum values are all capitalized, as is conventional with constants
For more complicated GUIs, you're going to want a nice design. By design, I don't mean the look and feel to it, but the design of the code. There are several design patterns which aid in making code more reusable, maintainable, and easy to build. You can use the Command pattern with a Mediator for smooth event handling. I provide an example of in the code I posted (look for the Command interface and how I use it). This is simply another way of event handling, and doesn't require any decision-making in the actionPerformed() method. My EventMediator class has a HashMap in it to store registered components, which may be confusing, so just don't pay attention to that. I should have provided more functionality to make it a better example, so focus on the text related to the Mediator instead.

A common style for adding the components to the JPanel, JFrame, etc., is to make accessor (get) methods that initialize these components and give an interface for accessing the components in other parts of the program. In that case, you would do MyJPanel.add(getExitButton()) or w/e. I provided an example for this in the code I posted.

Lastly, if you pass arguments to the constructor of the JFrame derived class, specifying certain things, then it is potentially more reusable. For instance, I have a GUI that I reuse for all my client chat programs. I can reuse this when making different bots or clients for different IM servers. I have to tweak it a little, of course, but you'd be surprised at how little. This is the power of reusability in OOP.

TR_Twiggy
02-25-2006, 08:08 AM
I have a window that looks good enough for me, but my problem is when it is resized it looks like ***. So my question is how can I make it unsizable. I googled Unsizable Java windows and it gave me stuff on Visual basic and web.

SS2K4
02-25-2006, 08:15 AM
Hi, use this:
setResizable(false);
Usage:
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);

ExportFrame frame = new ExportFrame();

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setSize(400, 400);
frame.setResizable(false);
frame.setVisible(true);
}

TR_Twiggy
02-25-2006, 08:20 AM
Thank you very much that helps alot.