The graphical interface of the program in java. Improving the Java application interface


Swing library

Modern programs need a graphical user interface (GUI). Users have lost the habit of working through the console: they control the program and enter input data through the so-called controls (in programming, they are also called visual components), which include buttons, text fields, drop-down lists, etc.

Each of modern languages programming provides many libraries for working with a standard set of controls. Recall that under the library in programming is a set of ready-made classes and interfaces designed to solve a certain range of tasks.

Java has three visual component libraries for building a graphical user interface. The earliest of these is called AWT. It is believed that a number of shortcomings were made in its design, as a result of which it is rather difficult to work with it. The Swing library is developed on the basis of AWT and replaces most of its components with their own, designed more carefully and conveniently. The third, the most new library, called SWT.

Each library provides a set of classes for working with buttons, lists, windows, menus, etc., but these classes are designed differently: they have different set methods with different parameters, therefore it is not so easy to "transfer" a program from one library to another (for example, in order to increase performance). It's almost like switching from one programming language to another: all languages ​​can do the same thing, but each of them has its own syntax, its own program structure and its many tricks.

For this reason, instead of reviewing all three libraries, we will try to better understand one of them - the Swing library. Complete graphical interface can be developed with it.

JFrame window

Each GUI program runs in a window and can open several additional windows in the process.

The Swing library describes the JFrame class, which is a window with a frame and a title bar (with buttons "Minimize", "Full screen" and "Close"). It can resize and move around the screen.

about Swing windows

There are several other window classes in Swing. For example, JWindow is the simplest window, with no border and no title bar. Usually, it is used to create a splash screen for the program, which must perform several lengthy actions before launching (for example, loading information from the database).

The JFrame () constructor with no parameters creates an empty window. The JFrame (String title) constructor creates an empty window with the title title.

To write the simplest program that displays an empty window, we need three more methods:

setSize (int width, int height) - sets the size of the window. If you do not specify dimensions, the window will have a zero height regardless of what is in it and the user will have to manually stretch the window after launch. The dimensions of the window include not only the work area, but also the borders and title bar.

setDefaultCloseOperation (int operation) - allows you to specify the action to be performed when the user closes the window by clicking on the cross. Usually, a program has one or more windows, upon closing which the program stops working. To program this behavior, pass the EXIT_ON_CLOSE constant described in the JFrame class as the operation parameter.

setVisible (boolean visible) - When the window is created, it is invisible by default. To display the window on the screen, call this method with the parameter true. If you call it with the false parameter, the window will become invisible again.

We can now write a program that creates a window, displays it, and exits after the user closes the window.

import javax.swing. *; public class MyClass (public static void main (String args) (JFrame myWindow = new JFrame ("Trial Window"); myWindow.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); myWindow.setSize (400, 300); myWindow.setVisible (true); ))

Note that you will need to import the java.swing package to work with most Swing classes. *

As a rule, before displaying a window, you need to perform a lot more actions than in this simple program. You need to create a lot of controls, customize them appearance, place the windows in the right places. In addition, a program can have many windows and it is inconvenient and incorrect to configure all of them in the main () method, since it violates the principle of encapsulation: to keep data and commands that process them together. It would be more logical for each window to take care of its size and content on its own. Therefore, the classical structure of a windowed program looks like this:

In the SimpleWindow.java file:

public class SimpleWindow extends JFrame (SimpleWindow () (super ("Test Window"); setDefaultCloseOperation (EXIT_ON_CLOSE); setSize (250, 100);))

In the Program.java file:

public class Program (public static void main (String args) (JFrame myWindow = new SimpleWindow (); myWindow.setVisible (true);))

As you can see from the example, the window is described in a separate class that inherits from JFrame and adjusts its appearance and behavior in the constructor (the first command calls the constructor of the superclass). The main () method is contained in another class responsible for managing the flow of the program. Each of these classes is very simple, each does his own thing, so they are easy to understand and easy to maintain (i.e. improve if necessary).

Please note that the setVisible () method is not called in the SimpleWindow class, which is quite logical: the window itself keeps track of where which button is located and what size it should have, but to decide which window is displayed on the screen is the prerogative of the control class of the program.

Content pane

Controls are not placed directly in the window. To do this, use the content pane, which occupies the entire window space *. You can access this panel using the getContentPane () method of the JFrame class. Using the add (Component component) method, you can add any control to it.

In the examples of this lesson, we will use only one control - a button (without going into details of its design). The button is described by the JButton class and created by a constructor with a parameter of type String - a label.

Let's add a button to the content pane of our window with the commands:

JButton newButton = new JButton (); getContentPane (). add (newButton);

As a result, we get a window with a button. The button occupies the entire available area of ​​the window. This effect is not useful in all programs, therefore it is necessary to study different ways arrangement of elements on the panel.

Container class

Items that contain other items are called containers. They are all descendants of the Container class and inherit a number of useful methods from it:

add (Component component) - adds a component element to the container;

remove (Component component) - removes the component element from the container;

removeAll () - removes all elements of the container;

getComponentCount () - Returns the number of elements in the container.

In addition to those listed in the Container class, about two dozen methods are defined for managing the set of components contained in the container. As you can see, they are similar to methods of a collection class. This is not surprising, because in essence a container is a collection, but a collection of a special kind - a visual one. In addition to storing elements, the container deals with their spatial arrangement and drawing. Specifically, it has a getComponentAt (int x, int y) method that returns the component that point with given coordinates(coordinates are measured from the upper left corner of the component) and a number of others. We will not go into detail about the abstract container, but go straight to its most commonly used descendant - the JPanel class.

JPanel class (panel)

A JPanel is a rectangular space in which you can place other elements. Items are added and removed by methods inherited from the Container class.

In the button example, we saw how the button added to the content pane took up all of its space. This does not always happen. In fact, each panel has a so-called accommodation manager which defines the strategy mutual disposition items added to the panel. It can be changed using the setLayout method (LayoutManager manager). But in order to pass the required parameter to this method, you need to know what managers are.

FlowLayout Sequential Layout Manager

The simplest layout manager is FlowLayout. It places the components to be added to the panel strictly in turn, line by line, depending on the size of the panel. As soon as the next element does not fit in current line, it is carried over to the next one. The best way to observe this is with an example. Let's change the constructor of the SimpleWindow class as follows:

SimpleWindow () (super ("Test Window"); setDefaultCloseOperation (EXIT_ON_CLOSE); JPanel panel = new JPanel (); panel.setLayout (new FlowLayout ()); panel.add (new JButton ("Button")); panel. add (new JButton ("+")); panel.add (new JButton ("-")); panel.add (new JButton ( "Button with a long caption")); setContentPane (panel); setSize (250, 100); )

Location managers are described in the java.awt package. Don't forget to import the classes you want.

Observe the behavior of the window that appears after starting the program. The four buttons in it are arranged like words in text editor(when aligning to the center). The effect will be more noticeable if you resize the window while the program is running.

Let's analyze the example text. The new FlowLayout layout manager is created by the parameterless constructor. Please note that the program does not use an intermediate variable. That is, instead of two commands:

FlowLayout newLayout = new FlowLayout (); panel.setLayout (newLayout);

We use one:

Panel.setLayout (new FlowLayout ());

This is quite acceptable in those cases when in the future we do not need to refer to the object being created (which is true for this example). We create a layout manager, immediately bind it to the panel, and that's it. Now the panel and the manager will find a common language with each other.

about the relationship between the panel and its manager

The panel stores a link to its manager and itself refers to it every time it needs to calculate the coordinates of elements (this happens when they are added, deleted, resized, and also when the window is resized). In principle, we can even get this manager using the getLayout () method of the JPanel class, but usually this is not necessary at all.

By the way, the JPanel class, in addition to a constructor without parameters, has a constructor in which the location manager is set as a parameter. Therefore, instead of commands

JPanel panel = new JPanel (); panel.setLayout (new FlowLayout ());

you can write:

JPanel panel = new JPanel (new FlowLayout ());

Moreover, by default again the panel being created has exactly the layout manager FlowLayout. Therefore, in the example above, we are installing the manager rather for clarity, in general, this is not necessary.

Likewise, we add new buttons to the panel. Nowhere else are we trying to refer to these buttons in the program, so there is no point in setting variables under them.

The setContentPane (JPanel panel) method allows you to replace the window's content pane.

BorderLayout Manager

The BorderLayout layout manager divides the panel into five areas: center, top, bottom, right, and left. You can add exactly one component to each of these areas, and the component will occupy the entire area allocated for it. Components added to the top and bottom regions will stretch in width, those added to the right and left will stretch in height, and a component added to the center will stretch to fill the remaining panel space.

When adding an element to the panel with the BorderLayout placement manager, you must additionally specify in the add () method which of the areas is meant. To do this, use the lines with the names of the cardinal points: "North", "South", "East", "West" and "Center". But instead, it is recommended to use the constants defined in the BorderLayout class: NORTH, SOUTH, EAST, WEST and CENTER (because you can make a mistake in a line and not notice it, and if you try to write the wrong name of a constant, the compiler will issue a warning). If you use the add () method as usual, with one parameter, the element will be added to the center.

The content pane has exactly this location, which is why the button occupied the entire window (it was added to the center area). To see the BorderLayout effect, let's add buttons to all five areas:

SimpleWindow () (super ("Test Window"); setDefaultCloseOperation (EXIT_ON_CLOSE); getContentPane (). Add (new JButton ("Button"), BorderLayout.NORTH); getContentPane (). Add (new JButton ("+"), BorderLayout.EAST); getContentPane (). Add (new JButton ("-"), BorderLayout.WEST); getContentPane (). Add (new JButton ( "Button with a long caption"), BorderLayout.SOUTH); getContentPane (). add (new JButton ("CENTER!")); setSize (250, 100); )

The effect will be well observed if the window is resized.

This placement is not accidentally used in the default content pane. Most programs use areas around the edges of the window to position toolbars, status bars, and the like. And the limitation on one component in the central area is absolutely insignificant, because this component can be another panel with many elements and with any layout manager.

GridLayout Table Layout Manager

GridLayout splits the panel into cells of the same width and height (thus making the window look like a table). Each item added to a panel with this arrangement occupies one cell entirely. The cells are filled with elements one by one, starting from the top left.

This manager, unlike those discussed earlier, is created by a constructor with parameters (four integers). You must specify the number of columns, rows and the distance between cells horizontally and vertically. Follow the example below and observe the effect.

SimpleWindow () (super ("Test window"); setDefaultCloseOperation (EXIT_ON_CLOSE); JPanel panel = new JPanel (); panel.setLayout (new GridLayout (2,3,5,10)); panel.add (new JButton (" Button ")); panel.add (new JButton (" + ")); panel.add (new JButton (" - ")); panel.add (new JButton ( "Button with a long caption")); panel.add (new JButton ("another button")); setContentPane (panel); setSize (250, 100); )

BoxLayout box manager and Box class

The BoxLayout manager arranges items on the panel in a row or in a column.

Usually, to work with this manager, use helper class Box, which is a panel already configured for block placement. Such a panel is created not by a constructor, but by one of two static methods defined in the Box class: createHorizontalBox () and createVerticalBox ().

Items added to a block-layout panel line up one after the other. The default spacing between elements is zero. However, instead of a component, you can add an invisible "spacer", the only task of which is to move adjacent elements, providing a specified distance between them. The horizontal strut is created static method createHorizontalStrut (int width) and vertical is done by createVerticalStrut (int height) method. Both methods are defined in the Box class, and an integer parameter in each determines the size of the spacer.

In addition, one more special element can be added to such a panel - a kind of "spring". If the size of the panel is larger than necessary for optimal placement of all elements, those that are capable of stretching will try to fill extra space yourself. If one or more "springs" are placed among the elements, an additional free space will be distributed in these gaps between the elements. Horizontal and vertical springs are created by the createHorizontalGlue () and createVerticalGlue () methods, respectively.

It is better to understand the peculiarities of this manager's work with an illustrative example. We will position the four buttons vertically, placing a "spring" between the two central ones, and between the others - spacers of 10 pixels.

SimpleWindow () (super ("Test Window"); setDefaultCloseOperation (EXIT_ON_CLOSE); Box box= Box.createVerticalBox (); box.add (new JButton ("Button")); box.add (Box.createVerticalStrut (10)); box.add (new JButton ("+")); box.add (Box.createVerticalGlue ()); box.add (new JButton ("-")); box.add (Box.createVerticalStrut (10)); box.add (new JButton ( "Button with a long caption")); setContentPane (box); setSize (250, 100); )

Features of aligning elements

In the vertical pane example, all buttons were aligned to the left. This horizontal alignment is the default.

However, when designing a program window, you may want some elements to be aligned differently, for example, right-aligned or centered. To set the alignment of any visual component (for example, a button or a panel), use the setAlignmentX (float alignment) - horizontal alignment and setAlignmentY (float alignment) - vertical alignment methods. The easiest parameter is to use the constants defined in the JComponent class. For horizontal alignment, use the constants LEFT_ALIGNMENT (left), RIGHT_ALIGNMENT (right), and CENTER_ALIGNMENT (center). For vertical alignment, BOTTOM_ALIGNMENT (bottom), TOP_ALIGNMENT (top), and CENTER_ALIGNMENT (center).

However, alignment works slightly differently than expected. To find this out, let's modify the previous example to align the third button to the right. To do this, replace the line:

Box.add (new JButton ("-"));

Three others:

JButton rightButton = new JButton ("-"); rightButton.setAlignmentX (JComponent.RIGHT_ALIGNMENT); box.add (rightButton);

We had to introduce a variable to refer to this button, because now we need to do not one, but two actions with it: set the right alignment and add it to the panel. The old trick - creating a button at the same time and passing it as a parameter to a method - won't work here.

After starting the program, we will see a window in which the buttons are not located as, probably, expected. We're used to the fact that right-aligning pushes the object to the right edge of the container, but in this case, all elements have been rearranged, and the right-aligned button is the leftmost one.

The explanation is simple. Right-aligned, the object does not snuggle against the right edge of the component. Instead, it is right-aligned against an invisible alignment line. All other components are pressed against this line with their left edge, and therefore the observed effect is obtained.

The only difficulty for a beginner developer may be that it is not always easy to understand exactly where this line will go. Its position depends on the size and alignment of all elements of the container. However, it is easy to remember a simple rule: if all the elements in the container are aligned the same, we will get the usual behavior (as was the case in the previous example, when all the components were aligned to the left and the line as a result nestled against the left edge of the panel.

about aligning elements

The alignment parameter is actually real number in the range from 0 to 1. It shows how much of the component will be to the left of the alignment line, ie. in what proportions the component will be "cut". The constants LEFT_ALIGNMENT and TOP_ALIGNMENT are actually 0, RIGHT_ALIGNMENT and BOTTOM_ALIGNMENT are 1, and CENTER_ALIGHNMENT is 0.5. You can substitute these numbers directly (although the use of constants greatly improves clarity!), Or you can choose any other number from 0 to 1 and set up a completely arbitrary alignment.

Try experimenting with the vertical bar by setting different alignment for its elements to intuitively understand the logic behind the alignment line placement. Resize the window while the program is running to see how the position of this line changes.

Manual placement of elements

If you set null as the panel placement manager, the elements will not be placed automatically. In this case, the coordinates of each element must be specified explicitly, and they do not depend in any way on the dimensions of the panel and on the coordinates of other elements. By default, the coordinates are equal to zero (i.e. the element is located in the upper left corner of the panel). The size of the element must also be set explicitly (otherwise, its width and height will be zero and the element will not be displayed).

Element coordinates can be set using one of the following methods:

setLocation (int x, int y),

setLocation (Point point)

These methods work in a similar way, setting the left top corner element to a point with specified coordinates. The difference is in the way the point is set. You can represent a point with two integers, or it can be an object of the Point class. The Point class is essentially the same pair of numbers, its constructor is Point (int x, int y). A single coordinate can be accessed using the getX () and getY () methods.

One might wonder: why use the Point class when you can just pass in a couple of numbers? But the fact is that many useful methods return the result - the coordinates of some point - as an object of this class. For example, the getLocation () method, which returns the coordinates of an element. Suppose we want to place b exactly where a is. This can be easily achieved with one line:

B.setLocation (a.getLocation ());

The element size is set using one of two methods:

setSize (int width, int height),

setSize (Dimension size)

These methods work the same way - the difference, like last time, is in the way the parameter is passed. The Dimension class, similar to the Point class, simply stores two numbers, has a constructor with two parameters: Dimension (int width, int height) and allows you to access its components - width and height - using simple methods getWidth () and getHeigth (). In order to get the current size of an element, you can use the getSize () method, which returns an object of the Dimension class. Element b can be made exactly the same size as element a by running the command:

B.setSize (a.getSize ());

Let's create a panel with no layout manager associated with it and manually place two buttons on it:

SimpleWindow () (super ("Test window"); setDefaultCloseOperation (EXIT_ON_CLOSE); JPanel panel = new JPanel (); panel.setLayout (null); JButton button = new JButton ("Button"); button.setSize (80, 30 ); button.setLocation (20,20); panel.add (button); button = new JButton ( "Button with a long caption"); button.setSize (120, 40); button.setLocation (70,50); panel.add (button); setContentPane (panel); setSize (250, 150); )

We use the same variable button to refer to both buttons (moreover, we don't need to describe it a second time). Indeed, having performed all the necessary operations with the first button and knowing that we will no longer need to access it, we use the "freed" variable to manipulate the second.

Automatic sizing of components

If the panel has any layout manager, it ignores the explicit dimensions and coordinates of all of its elements. You can easily verify this by replacing the panel.setLayout (null) command with panel.setLayout (new FlowLayout ()) in the previous example. The placement manager itself determines the coordinates and sizes of all elements.

The method for determining the coordinates of elements in an obvious way follows from the algorithms of the work of each manager and, thus, we have discussed in detail above.

We also noted that in some cases, components try to fill all the space available to them. For example, the entire center area in the case of the BorderLayout manager, or the entire cell in the GridLayout manager. In contrast, in a panel with a FlowLayout manager, elements never try to go beyond certain boundaries. Consider what these boundaries are.

Each visual component has three types of sizes: minimum allowable, maximum allowable and preferred. You can find out what these dimensions are for a given component using the appropriate methods:

getMinimumSize (),

getPreferredSize (),

getMaximumSize ().

The methods return a result of type Dimension. They are programmed in the appropriate class. For example, the button minimum size- zero, maximum size not limited, but the preferred one depends on the caption on the button (calculated as the size of the caption text plus the size of the fields).

The FlowLayout manager always sets the preferred sizes of the elements. The BorderLayout manager sets the preferred widths of the right and left, as well as the preferred heights of the top and bottom. The rest of the dimensions are adjusted to the available panel space. The GridLayout manager tries to resize all elements to fit the cells. The BoxLayout manager focuses on preferred sizes.

When an element tries to occupy all the space available to it, it "takes into account" the wishes not to be made less than its minimum or more than its maximum.

All three sizes can be controlled using the appropriate setter methods:

setMinimumSize (Dimension size),

setPreferredSize (Dimension size),

setMaximumSize (Dimension size).

Most often, a simple technique is used when an element is "not recommended" to grow or shrink relative to its preferred size. This can be easily done with the command:

Element.setMinimumSize (element.getPreferredSize ());

Window "packing"

In the above examples, we explicitly set the window size using the setSize () method. But when using some sort of layout manager that arranges the elements and resizes them according to own rules, it is difficult to say in advance which window sizes will be the most suitable.

Of course, the most suitable option would be when all window elements have the preferred sizes or are close to them *.

If instead of explicitly specifying the size of the window, call the pack () method, they will be optimally selected taking into account the preferences of all elements placed in this window.

SetSize (250, 100);

per team

Note that when the panel does not have a placement method, this command does not work (since the panel has no algorithm to calculate its preferred size).

The exercise

As already noted, another panel can be a panel element. Create a panel with three buttons and a layout manager FlowLayout and a panel with two buttons and a layout manager BoxLayout (horizontal). Position both panels in the main window (without changing the layout manager of the content panel): one in the center and the other along either side of the window.

Framework

When panels serve not just to place elements in accordance with the algorithm of some manager, but to visually separate them from each other, they are framed with frames.

The border of the panel is set using the setBorder (Border border) method. The parameter of the method is a frame - an object of the Border class. This is an abstract class, so its descendants are used to create the frame:

EmptyBorder - an empty border, allows you to create padding around the panel. Indent sizes are specified in the constructor as four integers.

TitledBorder - Title frame. Simplest constructor has one parameter of type String (header text). The heading can be placed along any side of the frame, have different styles.

EtchedBorder - embossed frame. Can be concave or convex.

BevelBorder - volumetric border (convex or concave). You can adjust the colors as required for 3D effects.

SoftBevelBorder is the same as BevelBorder, but allows additional rounding of corners.

LineBorder is a simple solid line border. You can choose the color and thickness of the line, round the corners.

MatteBorder is a border from a repeating pattern.

CompoundBorder - Combines two frames passed as parameters to the constructor into one new frame.

All of the listed classes are described in the javax.swing.border package.

Let's look at an example. In this example, we will create six panels with different frames and arrange them in a table. In order not to describe the procedure for creating a new panel six times, we will move it into a separate method:

Private JPanel createPanel (Border border, String text) (JPanel panel = new JPanel (); panel.setLayout (new BorderLayout ()); panel.add (new JButton (text)); panel.setBorder (new CompoundBorder (new EmptyBorder ( 12,12,12,12), border)); return panel;)

The createPanel () method creates a panel with a button at its full size. As a parameter, the caption on the button and the frame to be added to the panel are passed. The frame is not added directly, but by composition with an empty frame. This technique is often used to prevent the frame from sticking to the edge of the panel.

Now we will use this method six times in the constructor of the program window.

SimpleWindow () (super ("Trial Window"); setDefaultCloseOperation (EXIT_ON_CLOSE); JPanel panel = new JPanel (); panel.setLayout (new GridLayout (2,3,5,10)); panel.add (createPanel (new TitledBorder ( "Title frame"), "TitledBorder")); panel.add (createPanel (new EtchedBorder (), "EtchedBorder")); panel.add (createPanel (new BevelBorder (BevelBorder.LOWERED), "BevelBorder")); panel.add (createPanel (new SoftBevelBorder (BevelBorder.RAISED), "SoftBevelBorder")); panel.add (createPanel (new LineBorder (Color.ORANGE, 4), "LineBorder")); panel.add (createPanel (new MatteBorder (new ImageIcon ("1.gif")), "MatteBorder")); setContentPane (panel); pack (); )

This example shows which constructors are used to create different frames and what they look like. It uses two new classes: Color and ImageIcon.

The Color class is designed to work with color. It contains several constants that describe the most common colors. In particular, this includes Color.ORANGE.

The ImageIcon class describes graphic image... The parameter to its constructor is the path to the file from which the image can be loaded. The example uses the relative file name "1.gif". For the ImageIcon object to be created successfully, a file with this name must be placed in the project folder.

I will say right away - when working with graphics, most likely, over time, you will have to use all the provided tools, without exception, to achieve the best visual effect. Detailed description on "what and how" can be found - this is the official tutorial on Graphics2D. It should be more than enough to get you up to speed.

I have already given a small example of writing my own UI, but there are other options for customizing the interface. Each separate J component performs its Lightweight rendering using the paint () method, which can be easily overridden and modified. It is better not to use it directly (not always, but most often) (I will not go into details, since this is a whole topic for a separate topic). For the next example, we'll use the paintComponent () method. Let's see how it can be applied more closely ...

I'll start with an example - a text field with visual feedback in the absence of content:

JTextField field = new JTextField ()
{
private boolean lostFocusOnce = false;
private boolean incorrect = false;

{
// Listeners to update the validation state
addFocusListener (new FocusAdapter ()
{
public void focusLost (FocusEvent e)
{
lostFocusOnce = true;

repaint ();
}
});
addCaretListener (new CaretListener ()
{
public void caretUpdate (CaretEvent e)
{
if (lostFocusOnce)
{
incorrect = getText () .trim () .equals ("");
}
}
});
}

protected void paintComponent (Graphics g)
{
super.paintComponent (g);

// Extended rendering when data is incorrect
if (incorrect)
{
Graphics2D g2d = (Graphics2D) g;

// Turn on anti-aliasing for smooth rendering
g2d.setRenderingHint (RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

// Get padding inside the margin
Insets insets;
if (getBorder () == null)
{
insets = new Insets (2, 2, 2, 2);
}
else
{
insets = getBorder () .getBorderInsets (this);
}

// Create an underline shape for the text
GeneralPath gp = new GeneralPath (GeneralPath.WIND_EVEN_ODD);
gp.moveTo (insets.left, getHeight () - insets.bottom);
for (int i = 0; i< getWidth () - insets.right - insets.left; i += 3)
{
gp.lineTo (insets.left + i,
getHeight () - insets.bottom - ((i / 3)% 2 == 1? 2: 0));
}

// Draw it in red
g2d.setPaint (Color.RED);
g2d.draw (gp);
}
}
};

The presence of the content is rechecked when printed and the field is out of focus. Switching to another component, we will see how our addition to the JTextField is rendered:

The complete example code can be taken.

Thus, you can extend any available component by quickly redefining and complementing the rendering method, without having to write separate cumbersome UI or full-fledged components. A plus given example can be easily moved into a separate class and used as a ready-made element for your interface.
Another plus this method what you get is independent of the currently installed LaF / UI application / component - it will always work. Naturally, for some specific UI you may need a slightly different rendering - to support it or not - it's up to you.

Although you often want to make the interface brighter and more attractive, you do not always need to invent new components for this - you can use by standard means... I will give an example of customizing a simple checkbox with an animated change of states and background. This time I again (yes, you can beat me with sticks) will use the prepared images from the skilled hands of the designer.

8 16x16 images are taken as a basis - 4 states of the checkbox background and 4 states of the checkbox (5 actually, but we will add the 5th programmatically):

The standard checkbox, of course, does not have the ability to set sprites for animating states, in addition, we need to superimpose the images of the jackdaw on the background in different variations. For this, we will add a separate method:

public static List BG_STATES = new ArrayList ();
public static List CHECK_STATES = new ArrayList ();

static
{
// Background state icons
for (int i = 1; i<= 4; i++)
{
BG_STATES.add (new ImageIcon (
MyCheckBox.class .getResource ("icons / states /" + i + ".png")));
}

// Additional "empty" selection state

new BufferedImage (16, 16, BufferedImage.TYPE_INT_ARGB)));

// Selection states
for (int i = 1; i<= 4; i++)
{
CHECK_STATES.add (new ImageIcon (
MyCheckBox.class .getResource ("icons / states / c" + i + ".png")));
}
}

private Map iconsCache = new HashMap ();

private synchronized void updateIcon ()
{
// Update the checkbox icon
final String key = bgIcon + "," + checkIcon;
if (iconsCache.containsKey (key))
{
// The required icon has already been used before
setIcon (iconsCache.get (key));
}
else
{
// Create a new icon that combines the background and state on top
BufferedImage b = new BufferedImage (BG_STATES.get (0) .getIconWidth (),
BG_STATES.get (0) .getIconHeight (), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = b.createGraphics ();
g2d.drawImage (BG_STATES.get (bgIcon) .getImage (), 0, 0,
BG_STATES.get (bgIcon) .getImageObserver ());
g2d.drawImage (CHECK_STATES.get (checkIcon) .getImage (), 0, 0,
CHECK_STATES.get (checkIcon) .getImageObserver ());
g2d.dispose ();

ImageIcon icon = new ImageIcon (b);
iconsCache.put (key, icon);
setIcon (icon);
}
}

It remains to add a few state transition handlers and we will get an animated transition between them:

The resulting component will be very easy to modify, for example, into a radio button, or add more transition states to it for smoother animation, etc.
Actually, I posted the full working code and images separately.

Thus, there are a lot of ways to customize elements (even I probably don't know / don't know about some of them). Which method to choose depends on the situation - what needs to be obtained, what changes can be made to an existing component, etc.

At the end of this chapter, I'll give you another example of a completely redesigned UI button with animation, the ability to round certain corners, the ability to customize the style and some other improvements. Here are some screenshots of the final look (of course, the animation is not visible here):


I won't lie, this button UI took a lot of time, but it was created without the help and hints of the designer using pure Graphics2D and Swing tools. you can download and study the full source and demo of this UI if you are interested. It uses a fairly wide range of Graphics2D capabilities and uses some tricks that can often be useful.

So, I think there is enough talk about graphics - I will tell you about it in more detail in future topics, and now I will give some interesting material that I have accumulated over a fairly long time of "communication" with Swing and Graphics2D.

DnD and GlassPane

I think the first thing - you all more than know, as well as the problems associated with it. As for the second - you probably heard about GlassPane in passing, or maybe even saw this old image (which is still relevant, by the way) about the arrangement of various layers of standard frames. What's wrong with that and why did I remember this? And even more so, how are DnD and GlassPane related, you ask? That's exactly how to connect them and what can come of it, and I want to tell you in this chapter.

Well, let's start in order - what do we know about DnD?
Some Swing components have ready-made implementations for drag (JTree and JList, for example) - for others, you can easily add your own. In order not to throw words into the wind, I will give a small example of a DnD string from a label:

JLabel label = new JLabel ( "Small text for DnD");
label.setTransferHandler (new TransferHandler ()
{
public int getSourceActions (JComponent c)
{
return TransferHandler.COPY;
}

public boolean canImport (TransferSupport support)
{
return false;
}

protected Transferable createTransferable (JComponent c)
{
return new StringSelection (((JLabel) c) .getText ());
}
});
label.addMouseListener (new MouseAdapter ()
{
public void mousePressed (MouseEvent e)
{
if (SwingUtilities.isLeftMouseButton (e))
{
JComponent c = (JComponent) e.getSource ();
TransferHandler handler = c.getTransferHandler ();
handler.exportAsDrag (c, e, TransferHandler.COPY);
}
}
});

Now it is possible to drag the text of this label directly from the interface to any other place where it is possible to insert the text through the drop.
In fact - TransferHandler is responsible for what data the component gives when dredging and how the component uses the incoming data when dredging to it.

But what if you need to track the sequence of user actions during the drag itself?
For this, there is a separate option to hang the listener:

DragSourceAdapter dsa = new DragSourceAdapter ()
{
public void dragEnter (DragSourceDragEvent dsde)
{
// When the dredge enters the area of ​​some component
}

public void dragExit (DragSourceEvent dse)
{
// When the dredge enters the area of ​​some component
}

public void dropActionChanged (DragSourceDragEvent dsde)
{
// When changing the action of the drag
}

public void dragOver (DragSourceDragEvent dsde)
{
// If the dredge can be completed correctly
}

public void dragMouseMoved (DragSourceDragEvent dsde)
{
// When moving the dredge
}

public void dragDropEnd (DragSourceDropEvent dsde)
{
// When finishing or canceling the dredge
}
};
DragSource.getDefaultDragSource () .addDragSourceListener (dsa);
DragSource.getDefaultDragSource () .addDragSourceMotionListener (dsa);

There is one last thing left - to define the role of GlassPane. GlassPane, in fact, allows you to position / draw components on itself, like any other container, but its peculiarity is that it lies on top of all Swing components when visible. Those. if we draw something on it, then it will cover the entire interface under it. This allows you to place components regardless of the main container anywhere, create any visual effects and do other fun things.

For better understanding, I will give a small example of such an "effect" - a frame with several Swing components on it. When you click in any part of the window, the effect of a "recognizing" circle will appear, which is visible on top of all elements. The most interesting thing is that this effect does not consume resources and does not require a large pile of code. Don't believe me? - look at the demo and take a look at the source included in the jar.

By the way, there is a rather interesting library on this topic, at the same time providing additional scrolling functionality and several other goodies - JXLayer (off site) (description # 1 description # 2 description # 3). Unfortunately, projects hosted on the java site are not in the best condition now, so you have to refer to separate resources.

So now let's combine everything that I have already described in this chapter and finally do something complete. For example - displaying a dredge panel with components inside a window:

When dragging a panel for a label, a translucent copy of the panel appears, showing exactly where the panel will be placed when the drag is completed. You can also cancel the move with the ESC key.
A working example and source code can be taken.

Of course, to implement this particular functionality, it would not be worth resorting to using DnD - there are shorter ways. However, it all depends on the situation. This option allows you to draw by dragging independently of other components in the window. It is also possible, based on it, for example, to implement a drag panel between application windows.

AWTUtilities

Since some future innovations from 7ki have been included in JDK6 for a long time, I cannot ignore them, since with their help it is possible to do a lot of things with much less effort.
So, we are interested in several methods from AWTUtilities:
  1. AWTUtilities.setWindowShape (Window, Shape) - allows you to set any window to a specific shape (be it a circle or a tricky polygon). To set the form correctly, the window should not be decorated with the native style (setUndecorated (true)).
  2. AWTUtilities.setWindowOpacity (Window, float) - allows you to set the transparency of the window from 0 (completely transparent) to 1 (opaque). At the same time, the window can be decorated with a native style.
  3. AWTUtilities.setWindowOpaque (Window, boolean) - allows you to completely hide the display of the background and window decoration, but any component placed on it will be visible. For the correct setting of this parameter, the window, as in step 1, should not be decorated with the native style.

What does this give us? In fact, there is a fairly wide range of possibilities. The windows of your application can be set any tricky forms that you just need, make "holes" in the middle of the application, create custom shadows under the window, make nice-looking pop-ups, etc., etc.

To be specific, I never actually use setWindowShape, since the form assigned to the window is strictly cropped around the edge and doesn't look very nice. SetWindowOpaque comes to the rescue - by hiding the decoration and background of the window, you can create absolutely any windows using a container with a custom rendered background. I will give a small example of use (it also uses some of the techniques from the previous chapters of the post):

you can take a working jar with the source code. Honestly, I spent no more than ten minutes on this example (of which five minutes I figured out how to arrange the elements inside the dialog :). Naturally, this is just one of the options for using these new opportunities - in fact, there are much more of them.

The only annoying little thing about using AWTUtilities is unstable work on Linux systems. Those. The transparency of windows does not always and does not always work out correctly. Not sure if this is a problem with the current JDK or the OS.

Creating your own interactive components

I have already superficially talked about how to create components, UI and some "bells and whistles" for the interface of your application, but what if we need to add a functional part to a component or create our own completely new component with some functionality and styling? Styling standard components and making separate parts of a new component out of them is a rather long and tedious task, especially since with the slightest change in one of the components, the entire circuit can go. It is in such cases that you should make your component "from scratch".

So, it is best to take the JComponent as a basis and use paint methods to draw its contents. In fact, JComponent itself is a blank canvas with some hard-wired improvements for rendering and ready-made standard methods setEnabled / setFont / setForeground / setBackground, etc. How to use (and whether to use them) is up to you. Everything that you add to the rendering methods will become part of the component and will be displayed when you add it to any container.

By the way, a small digression, since we are talking about containers - any inheritor and JComponent itself are containers, i.e. may contain other components, which will be located depending on the layout installed for the component. What is going on with the rendering of child components that lie in this one and how is it related to the rendering of this component? Previously, I did not go into detail on how the Jcomponent paint-methods are arranged and connected, "but now I will describe it in detail ...

In fact, the paint () method contains calls to 3 separate methods - paintComponent, paintBorder, and paintChildren. Of course, it additionally handles some "special" rendering cases such as printing or redrawing a specific area. These three methods are always called in the sequence shown in the image above. Thus, the component itself is drawn first, then the border is drawn on top, and then the rendering of child components is called, which in turn also call their paint () method, etc. Naturally, there are also various optimizations that prevent unnecessary rendering, but I will write about this in more detail later.

The component is rendered but static and is just an image. We need to handle the ability to control it with the mouse and various hotkeys.
To do this, first, you need to add appropriate listeners (MouseListener / MouseMotionListener / KeyListener) to the component itself and handle individual actions.

In order not to explain everything on the fingers, I will give an example of a component that allows you to visually resize the ImageIcon passed to it:

you can take a working example with the source code inside.

When creating this component, I would highlight several important points:

  1. Determining the functionality and appearance of the component- in this case, this is an area with an image placed on it, a border around the image and 4 resizers in the corners. Each of the resizers allows you to resize the image. It is also possible to move the image around the area, "grabbing" it by the center.
  2. Determine all the parameters necessary for the component to work- in this case, it is the image itself and its "anchor" points (upper left and lower right corners). There are also a number of variables that will be needed when implementing resizing and dragging an image.
  3. Throwing a blank for the component (preferably a separate class if you are going to use it more than once)- in this case, we create the ImageResizeComponent class, define all the parameters necessary for rendering, override the paintComponent () method and render the content. We also override the getPreferredSize () method so that the component itself can determine its "desired" size.
  4. We implement the functional part of the component- in this case, our MouseAdapter will be enough for us, but for the implementation of resize and movement. When the mouse is pressed in the area, we check the coordinates and check the IMX with the coordinates of the corners and the image itself - if the click happened in the area of ​​a certain corner, we remember it and change its coordinate when dragging , if you had to click on the image, remember its initial coordinates and change them when dragging. And finally, the final touch - in mouseMoved () we change the cursor depending on the control under the mouse.
Nothing complicated, right? With the implementation of the "button" parts of other components, it is even easier - just check that the click was in the button area. In parallel with tracking events, you can also visually change the display of the component (as done in this example on resizers). In general, you can do everything that you have enough imagination for.

Of course, I just described my steps when creating components - they are optional and can be easily extended and supplemented.

Important to remember

There are a few things to consider when working with interface elements in Swing - I'll cover them in this separate small chapter.
  1. Any operations of calling redrawing / updating of components should be performed inside the Event Dispatch thread to avoid visual "hangs" of the interface of your application. It is quite easy to execute any code in the Event Dispatch stream:
    SwingUtilities.invokeLater (new Runnable ()
    {
    public void run ()
    {
    // Place the executable code here
    }
    });
    It is also important to remember that events called from various listeners of standard components (ActionListener / MouseListener, etc.) are initially called from this thread and do not require additional processing.
  2. In no case should you influence the interface from any paint method, as this can lead to loops or deadlocks in the application.
  3. Imagine the situation - from the paint method you change the state of the button, say, through setEnabled (enabled). Calling this method causes the component to be redrawn and call the paint method again, and we are again taken to this ill-fated method. Rendering the button will loop and the application interface will simply hang while waiting for the rendering to complete (or at least eat up a good part of the processor). This is the simplest version of this error.
  4. You shouldn't do heavy calculations inside the Event Dispatch stream. You can do these calculations on a separate regular thread and then only invoke the update via SwingUtilities.invokeLater ().
  5. It is also not worth doing heavy calculations inside drawing methods. If possible, you should take them out separately and cache / remember them. This will speed up the rendering of components, improve the overall responsiveness of the application, and reduce the load on the Event Dispatch thread.
  6. To update the appearance of the components, use the repaint () method (or repaint (Rectangle) - if you know the exact area to update), the repaint method itself must be executed in the Event Dispatch thread. To update the arrangement of elements in the layout, use the revalidate () method (it does not need to be executed in the Event Dispatch thread). The updateUI () method can help in some cases for a complete update of an element (for example, changing table data), but it should be used carefully, since it will also override the UI you have installed and take the UI provided by the current LaF.
  7. A complete installation of LaF for the entire application will override any of your manually configured UI components and install on top of them the UI that the installed LaF offers. Therefore, it is better to install LaF when loading the application before opening any windows and showing visuals.
Following these simple steps will allow you not to worry about unexpected "brakes" or deadlocks in the application interface.
I think that this list can be supplemented with a few more points, but they will already be very specific / optional.

Outcomes

Using, combining and varying the above described capabilities and features of working with interfaces, it is possible to achieve any desired result. You just need to show a little imagination in this matter. I hope even the basic examples of this post gave you enough food for thought and, perhaps, helped with something.

I would also like to add that perhaps the title of the article may seem too loud and not fully disclosed to you - indeed, I am still not a designer or a usability specialist. I just offer you tools / methods that will allow you to expand and improve the application interface. Most (not necessarily all) of the work of creating graphics for the slider / button or defining the general style of the components and the application itself always remains with the designer - there is no getting away from this.

All examples of the article in a single "bottle". From the initial window, you can select the desired example:

  • interface
  • dnd
  • customization
  • interface
  • customization
  • Add tags

    What is Swing?

    Java Swing is a lightweight Graphical User Interface (GUI) toolkit that includes a rich set of widgets. It includes package lets you make GUI components for your Java applications, and It is platform independent.

    The Swing library is built on top of the Java Abstract Widget Toolkit ( AWT), an older, platform dependent GUI toolkit. You can use the Java GUI components like button, textbox, etc. from the library and do not have to create the components from scratch.

    In this tutorial, you will learn-

    Java Swing class Hierarchy Diagram

    All components in swing are JComponent which can be added to container classes.

    What is a container class?

    Container classes are classes that can have other components on it. So for creating a GUI, we need at least one container object. There are 3 types of containers.

    1. Panel: It is a pure container and is not a window in itself. The sole purpose of a Panel is to organize the components on to a window.
    2. Frame: It is a fully functioning window with its title and icons.
    3. Dialog: It can be thought of like a pop-up window that pops out when a message has to be displayed. It is not a fully functioning window like the Frame.

    Java GUI Example

    Example: To learn to design GUI in Java
    Step 1) Copy the following code into an editor

    Import javax.swing. *; class gui (public static void main (String args) (JFrame frame = new JFrame ("My First GUI"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setSize (300,300); JButton button = new JButton ("Press" ); frame.getContentPane (). add (button); // Adds Button to content pane of frame frame.setVisible (true);))

    Step 2) Save, Compile, and Run the code.
    Step 3) Now let "s Add a Button to our frame. Copy following code into an editor

    Import javax.swing. *; class gui (public static void main (String args) (JFrame frame = new JFrame ("My First GUI"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setSize (300,300); JButton button1 = new JButton ("Press" ); frame.getContentPane (). add (button1); frame.setVisible (true);))

    Step 4) Execute the code. You will get a big button

    Step 5) How about adding two buttons? Copy the following code into an editor.

    Import javax.swing. *; class gui (public static void main (String args) (JFrame frame = new JFrame ("My First GUI"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setSize (300,300); JButton button1 = new JButton ("Button 1 "); JButton button2 = new JButton (" Button 2 "); frame.getContentPane (). Add (button1); frame.getContentPane (). Add (button2); frame.setVisible (true);))

    Step 6) Save, Compile, and Run the program.
    Step 7) Unexpected output =? Buttons are getting overlapped.

    Java Layout Manger

    The Layout manager is used to layout (or arrange) the GUI java components inside a container. There are many layout managers, but the most frequently used are-

    Java BorderLayout

    A BorderLayout places components in up to five areas: top, bottom, left, right, and center. It is the default layout manager for every java JFrame

    Java FlowLayout

    FlowLayout is the default layout manager for every JPanel. It simply lays out components in a single row one after the other.

    Java GridBagLayout

    It is the more sophisticated of all layouts. It aligns components by placing them within a grid of cells, allowing components to span more than one cell.

    Step 8) How about creating a chat frame like below?

    Try to code yourself before looking at the program below.

    // Usually you will require both swing and awt packages // even if you are working with just swings. import javax.swing. *; import java.awt. *; class gui (public static void main (String args) (// Creating the Frame JFrame frame = new JFrame ("Chat Frame"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setSize (400, 400); // Creating the MenuBar and adding components JMenuBar mb = new JMenuBar (); JMenu m1 = new JMenu ("FILE"); JMenu m2 = new JMenu ("Help"); mb.add (m1); mb.add (m2); JMenuItem m11 = new JMenuItem ("Open"); JMenuItem m22 = new JMenuItem ("Save as"); m1.add (m11); m1.add (m22); // Creating the panel at bottom and adding components JPanel panel = new JPanel (); // the panel is not visible in output JLabel label = new JLabel ("Enter Text"); JTextField tf = new JTextField (10); // accepts upto 10 characters JButton send = new JButton ("Send") ; JButton reset = new JButton ("Reset"); panel.add (label); // Components Added using Flow Layout panel.add (label); // Components Added using Flow Layout panel.add (tf); panel.add (send); panel.add (reset); // Text Area at the Center JTextArea ta = new JText Area (); // Adding Components to the frame. frame.getContentPane (). add (BorderLayout.SOUTH, panel); frame.getContentPane (). add (BorderLayout.NORTH, mb); frame.getContentPane (). add (BorderLayout.CENTER, ta); frame.setVisible (true); ))

    Any developer begins a time when creating console applications is no longer fun, and you really want to learn something new.
    Then there are multiple paths in Java, for multiple OSes. Depending on the OS you are using or the environments that are installed in them.

    A little foreword:
    I myself am still a beginner programmer (I can write software of medium complexity, but I usually use a meager set of functions)
    The article is also designed for beginners. I myself work under Debian with Gnome, so there will be multiplatform libraries)

    To begin with, it would be worth paying attention to the GTK + library

    It is available not only for Java, but also for many other languages: C ++, C, etc.

    Writing Desktop Applications with GTK should be used if the application is designed to run under the GNOME environment.

    GTK + itself is considered one of the easiest Jav libraries to learn.

    Basics of working with the library:

    First, you need to connect the library itself with all that it implies:

    import org.gnome.gdk.Event;
    import org.gnome.gtk.Gtk;
    import org.gnome.gtk.Widget;
    import org.gnome.gtk.Window;
    import org.gnome.gtk.WindowPosition;

    If an error occurs, then most likely you simply do not have the library installed.

    If you are using a system like Debian or Ubuntu, then a simple command from the terminal will help you:
    apt-get install libjava-gnome-java

    After that, there should be no problems.

    public class DesktopExample extends Window (

    public DesktopExample () (

    SetTitle ( "Sample window on GTK and Gnome") ; // Application Name

    Connect (new Window .DeleteEvent () (
    public boolean onDeleteEvent (Widget source, Event event) (
    Gtk.mainQuit ();
    return false;
    }
    } ) ;

    SetDefaultSize (250, 150); // The size
    setPosition (WindowPosition.CENTER); // Position at startup, in this case the center
    show ();
    }


    Gtk.init (args);
    new DesktopExample ();
    Gtk.main ();
    }
    }

    As a result, we get an empty window.

    AWT - considered the original system for developing graphical interfaces, it is scolded for the fact that it
    it does not always work stably on different platforms, but now such problems do not seem to be observed and it is convenient to work with it.
    IMHO, this is my choice.
    SWT is the brainchild of IBM, a refreshed and refilled system, usually stable in operation and easy to learn.
    But SWT is heavier than AWT, has more functionality, as a result of which AWT is more complicated.
    But I would not use it often, although it is quite popular and holds its positions.

    Here's an example of an AWT window:

    // We connect all sorts of features, although swing is superfluous here, I screwed it in my application
    // This is just a snippet of code
    import java.awt.EventQueue;
    import javax.swing. *;
    import java.awt. *;
    import java.awt.event. *;

    import javax.swing.JFrame;

    public class Main (

    private JFrame frame;

    /**
    * Launching an application, something like initial setup, creating a window, and so on.
    */
    public static void main (String args) (

    EventQueue .invokeLater (new Runnable () (
    public void run () (
    try (
    Main window = new Main ();
    window.frame .setVisible (true);
    ) catch (Exception e) (
    e.printStackTrace ();
    }

    }
    } ) ;
    }

    /**
    * Call the initialization itself
    */
    public Main () (

    Initialize ();
    }

    /**
    * Window initialization
    */
    private void initialize () (
    frame = new JFrame ( "Blank window generated via Eclipse") ; // Make a new window with a title
    frame.setBounds (100, 100, 450, 300);
    frame.setSize (800, 800); // Dimensions
    frame.setDefaultCloseOperation (JFrame .EXIT_ON_CLOSE);

    }

    And here is an example of a window on SWT:

    // We connect all sorts of features for a fun life
    import org.eclipse.swt.SWT;
    import org.eclipse.swt.widgets.Display;
    import org.eclipse.swt.widgets.Shell;
    import org.eclipse.swt.widgets.Text;

    public class ExampleApp (

    public static void main (String args) (
    Display display = new Display ();
    Shell shell = new Shell (display);

    Shell.pack (); // Preparation (primary)
    shell.open (); // Prepare
    while (! shell.isDisposed ()) (// Run
    if (! display.readAndDispatch ()) display.sleep (); // Sleep for the time being
    }
    display.dispose ();
    }
    }

    It is also not complicated in principle, multiplatform. Differs in a large number of features and a small number of plug-in replenishments.

    Here is an example of a swing window:

    import javax.swing.JFrame;
    import javax.swing.SwingUtilities;

    public class Example extends JFrame (

    public Example () (
    setTitle ( "Sample Swing Application") ;
    setSize (300, 200);
    setLocationRelativeTo (null);
    setDefaultCloseOperation (EXIT_ON_CLOSE);
    }

    public static void main (String args) (
    SwingUtilities .invokeLater (new Runnable () (
    public void run () (
    Example ex = new Example ();
    ex.setVisible (true);
    }
    } ) ;
    }
    }

    This was the main list of Java graphical environments. Almost all the "pieces" presented here are multiplatform
    and work on any computer - Win, Linux, Mac.

    Tags: java, java libraries, java GUIs

    A screen form is an area that is visible on the screen as a window with various elements - buttons, text, drop-down lists, etc. And these elements themselves are called components.

    Environments that allow you to interactively place components on forms and set their parameters during application development are called RAD environments. RAD stands for Rapid Application Development - Rapid Application Development.

    In NetBeans and other modern development environments, this process is based on the Component Object Model, which is why it is called Object-Oriented Design (OOD).

    NetBeans is a RAD environment that allows you to quickly and easily create rich graphical user interface (GUI) applications. Although the Java language constructs that allow you to do this are not very simple, at the initial stage of working with screens and their elements there is no need to delve into these subtleties. It is enough to know the basic principles of working with such projects.

    First, from the very beginning, you master the creation of full-fledged applications that can be used for useful purposes. It is difficult to study abstract concepts for months, and only by becoming a professional be able to do something that can be shown to others. It is much more interesting and useful to immediately start applying the knowledge gained in practice.

    Secondly, such an interface, when solving a problem, allows you to better formulate what parameters should be entered, what actions and in what sequence to perform, and what ultimately turns out. And display all this on the screen: input parameters will correspond to text input items, actions - buttons and menu items, results - text output items.

    An example of opening a project with existing source code.

    NetBeans 5.0 had a good example of a GUI application, but NetBeans 5.5 does not. Therefore, for further work, you should copy a similar example from the author's site or the site on which this training course is posted. The example is called JavaApplicationGUI_example.

    First, you should unpack the zip archive and extract the folder with the project files in it to the folder with your projects (for example, C: \ Documents and Settings \ User). Then start NetBeans if it was not running, and close any open projects so they don't get in the way. Then select in the File / Open Project menu, or on the toolbar, the icon with an opening purple folder, or press the key combination ++ O. In the dialog that opens, select a folder JavaApplicationGUI_example(it is better not to go into it, but just set the selection to this folder), then click the Open Project Folder button.

    In this case, if you do not uncheck the "Open as Main Project" checkbox, the project automatically becomes the main one.

    The following text appears in the source editor window:

    * GUI_application.java

    package java_gui_example;

    * @author Vadim Monakhov

    public class GUI_application extends javax.swing.JFrame (

    * Creates new form GUI_application

    public GUI_application () (

    initComponents ();

    / ** This method is called from within the constructor to

    * initialize the form.

    * WARNING: Do NOT modify this code. The content of this method is

    * always regenerated by the Form Editor.

    private void exitMenuItemActionPerformed (java.awt.event.ActionEvent evt)

    * @param args the command line arguments

    public static void main (String args) (

    java.awt.EventQueue.invokeLater (new Runnable () (

    public void run () (

    new GUI_application (). setVisible (true);

    // Variables declaration - do not modify

    private javax.swing.JMenuItem aboutMenuItem;

    private javax.swing.JMenuItem contentsMenuItem;

    private javax.swing.JMenuItem copyMenuItem;

    private javax.swing.JMenuItem cutMenuItem;

    private javax.swing.JMenuItem deleteMenuItem;

    private javax.swing.JMenu editMenu;

    private javax.swing.JMenuItem exitMenuItem;

    private javax.swing.JMenu fileMenu;

    private javax.swing.JMenu helpMenu;

    private javax.swing.JMenuBar menuBar;

    private javax.swing.JMenuItem openMenuItem;

    private javax.swing.JMenuItem pasteMenuItem;

    private javax.swing.JMenuItem saveAsMenuItem;

    private javax.swing.JMenuItem saveMenuItem;

    // End of variables declaration

    Let us explain some of its parts. We are already familiar with specifying the java_gui_example package, which will contain the code of the application class. The declaration of the GUI_application class itself is somewhat more complicated in this case than before:

    public class GUI_application extends javax.swing.JFrame

    It means that the public class GUI_application is being specified, which inherits from the JFrame class specified in the swing package nested in the javax. The word extends translates to “extends” (the inheriting class always extends the capabilities of the parent class).

    The public constructor GUI_application () creates an application object and initializes all its components using the initComponents () method, which is automatically generated by the development environment and hidden in the source code by the + Generated Code node.

    By expanding the node, you can see the implementation of this method, but you cannot change the code. We will not dwell on what is being done in it.

    private void exitMenuItemActionPerformed

    It will be discussed a little later. Method

    public static void main (String args)

    we are already familiar - this is the main method of the application. It is a method of our application class and is automatically executed by the Java machine when the application starts. In this example, the method creates an application display and makes it visible. In order to understand how this is done, you will need to study quite a lot of material within the framework of this course.

    Running application. An application with an expanded menu.

    When the application is launched, the display looks like the one shown in the figure. It already has a blank menu that can expand and collapse, and even the Exit item works. When you click on it, you exit the application.

    The operator exitMenuItemActionPerformed is responsible for clicking on this menu item. When designing a display form, it is assigned as event handler- a subroutine that is executed when an event occurs. In our case, the event is the selection of the Exit menu item, and the exitMenuItemActionPerformed handler is called. There is only one line inside it

    It causes the main method to terminate and exit the application with a zero exit code. As a rule, a nonzero exit code is returned when the application terminates abnormally, so that by its value it is possible to find out the reasons for the program crash.

    Screen editor

    Click on the Design tab at the top left of the Source Editor. In this case, we will switch from the source code editing mode (the Source tab is active) to the screen form editing mode, as shown in the figure.

    Editing the display form.

    Instead of the source code, the display shows the appearance of the display form and the components located on it. To the right of the window in which the display is shown in edit mode are the Palette windows of the component palette and the Properties window for showing and editing the properties of the current component.

    A property is a data field that, after changing the value, can perform some action. For example, when changing the width value of a component, draw the component with the new width on the screen. A “regular” data field is not capable of this. Thus, a property is a “smart data field”.

    The component palette is designed to select the type of component that the programmer needs to be placed on the screen. For example, let's add a JButton component to our form (short for Java Button - "Java button"). To do this, click on the JButton item on the palette and move the mouse to the desired location on the screen. When the mouse enters an area of ​​the display form, a standard size button appears on it, which moves with the mouse. Clicking in the right place on the form causes the button to stay in that place. A frame and small squares are shown around it, indicating that our component is selected. For it, the properties are shown and edited in the Properties window.

    In addition, lines emanate from the selected component and snap to them to set the position of the component on the form.

    By default, component labels are set as the type name followed by the component number. But instead of a capital letter, unlike the type name, a lowercase letter is used. Therefore, the first button will be labeled jButton1, the second jButton2, and so on. The same names will be acquired by the variables corresponding to the buttons automatically created in the source code.

    There are several ways to change the label on a button. First, by double-clicking on it and editing the text. Second, by going to the Properties window, changing the value of the Text property and clicking to complete the input. Third, by changing the label property in a similar way. Finally, in the Properties window, you can edit the text not in the single-line field for entering values ​​for the Text or label properties, but by opening the multi-line editor by clicking on the button to the right of the property value editing item. However, the multi-line editor does not help to make the label on the button multi-line.

    Let's enter the inscription “OK” on the button - use this button to exit the program.

    Editing component properties

    The size of the component is set with the mouse by grabbing the frame and expanding or contracting in the appropriate directions. Installation to a new location - by dragging the component with the mouse.

    Some properties of the selected component (its size, position, text) can be changed directly in the display area. However, most properties are viewed and changed in the property edit window. It consists of two columns: the left one shows the names of the properties, the right one shows their values. The values ​​in the right column can in many cases be edited directly in the table cells. In this case, the entry ends by clicking on or exit from the edited cell, and you can cancel the results of unfinished input by pressing .

    On the right side of each cell there is a button labeled “…” - in modern operating systems, it is customary to add three dots in the names of menu items and buttons, after clicking on which a dialog box opens. In this case, the window of the specialized editor of the corresponding property opens, if it exists.

    If you need to view and edit a large number of component properties, it is more convenient to right-click on the required component and select “Properties” from the pop-up menu that appears. In this case, a separate window for editing the properties of the component will open. You can keep open at the same time an arbitrary number of such windows.

    Boolean properties in the property values ​​column are shown as checkbox selection buttons - squares with a checkbox inside. If there is no check mark, the property value is false, if present, it is true.

    Let's list some of the most important properties that can be set for components using the example of a button. Many of them apply to other components as well.

    Property name What does it ask
    background Background color
    componentPopupMenu Allows you to assign a popup menu that appears when you right-click in the component area.
    font The font used to label the component.
    foreground The color of the font used to label the component.
    icon The picture that is drawn on the component next to the text.
    text The text (label) on the component.
    toolTipText A tooltip that appears after a while when you hover the mouse cursor over a component.
    border The type of border around the component.
    borderPainted Whether a border is drawn around the component.
    contentAreaFilled Whether there is a color filling of the inner area of ​​the component (for buttons it creates a three-dimensional effect, without filling the button looks flat).
    defaultCapable Is the button capable of being the “default button”: when pressed the “default button” is automatically pressed (there should be one such button on the screen form).
    enabled Is the component available. By default, all components created on the form are available. Unavailable components are drawn with faded colors.

    As an example, let's add a tooltip for our button: enter the text “This button is intended to exit the program” in the field corresponding to the toolTipText property. Unfortunately, the hint can only be one-line - newline characters are ignored when displaying the hint, even if they are programmatically specified in the line.

    Finally, let's set the action that will be performed when the button is pressed - event handler(event handler) button click. To do this, first select the button, then right-click on it, and in the pop-up menu that appears, select the Events / Action / actionPerformed item.

    Event handler assignment

    Events means “Events”, Action means “Action”, actionPerformed means “performed action”.

    After that, an automatic transition to the source code editor will occur, and a stub of an event handler will appear there:

    // TODO add your handling code here:

    A similar result can be obtained in a faster way - after we select the button in the form editing window (Design), the name of this button is shown and highlighted in the Navigator window. Double-clicking on this name in the navigator window creates a stub for the event handler.

    Next to the jButton1ActionPerformed handler, there will be an existing event handler that is triggered when you click on the "Exit" menu item:

    private void exitMenuItemActionPerformed (java.awt.event.ActionEvent evt) (

    Let's replace the comment line in our event handler with the code that causes the program to exit:

    private void jButton1ActionPerformed (java.awt.event.ActionEvent evt) (

    Now, after launching our application, hovering the mouse cursor over the button will lead to the appearance of a tooltip, and clicking on the button will exit the program.

    A common case is displaying a message when an event occurs, for example, pressing a button. In this case, the panel is called with the message:

    javax.swing.JOptionPane.showMessageDialog (null, "I was clicked");

    If the classes of the javax.swing package are imported, the javax.swing prefix is ​​not required when calling.

    Application appearance

    At the stage of application editing, the appearance of its components corresponds to the platform. However, once launched, it becomes completely different, since by default all Java applications are displayed in a platform-independent way:

    Appearance of a running application with a platform-independent user interface set by default

    In addition, our application appears in the upper left corner of the screen, but we would like it to appear in the center.

    In order to show the application in a platform-oriented form (that is, in the form that uses the components and settings of the operating system), you need to change the code of the application constructor by inserting a setting of the user interface type (User's Interface, abbreviated UI) before calling the initComponents method:

    import javax.swing. *;

    import java.awt. *;

    public GUI_application () (

    UIManager.setLookAndFeel (UIManager.getSystemLookAndFeelClassName ());

    ) catch (Exception e) ();

    initComponents ();

    Dimension screenSize = Toolkit.getDefaultToolkit (). GetScreenSize ();

    Dimension frameSize = getSize ();

    setLocation (new Point ((screenSize.width-frameSize.width) / 2,

    (screenSize.height-frameSize.width) / 2)

    Appearance of a running application with a platform-oriented user interface in the Windows operating system ® XP

    The code following the initComponents () call is for setting the application window to the center of the screen.

    It is possible to define another platform-independent type of application - in the style of Motiff, used in the Solaris ® operating system. To set this kind, instead of calling

    UIManager.setLookAndFeel (UIManager.getSystemLookAndFeelClassName ()

    Should write

    UIManager.setLookAndFeel ("com.sun.java.swing.plaf.motif.MotifLookAndFeel");

    Appearance of a running application with a platform-independent user interface in the style of Motiff

    The constructions used will become clear to the reader after studying the further sections of the methodological manual.

    Project management

    In order not to get confused in different projects and their versions, especially taking into account the fact that educational projects often need to be transferred from one computer to another, you should take project management seriously. As a result of many years of practice with different languages ​​and programming environments, the author has developed the following system (adjusted for the NetBeans environment):

    · A folder with the name of the project is created for each project. Let's call it the archive folder for this project. The names of the folders used can be in Russian, as well as the names of applications and files.

    · When creating a new project, the development environment prompts you to enter the name of the folder where to store it - you should specify the name of the archive folder. In addition, you are prompted to enter a name for the project. This name will be used by NetBeans to create the project folder as well as the name of your application. In order to make it easier to work with your application in different countries, it is recommended to make this name in English. In the project folder, the development environment will automatically create a subfolder system for the project and all its files. The NetBeans project folder structure was described earlier.

    · If you take a project with existing source code, its folder is copied to our archive folder either manually or by choosing the appropriate sequence in the New NetBeans Project Wizard.

    · When you receive a workable version of the project, you should make an archive copy of it. To do this, in an open project in the “Projects” window, just right-click on the project name, and select the “Copy Project” item in the pop-up menu that appears. A dialog form will open in which an automatically generated copy name is proposed - an underscore and a copy number are added to the original project name. For the first copy it is _1, for the second it is _2, and so on. Moreover, the head folder of the archive by default remains the same as that of the original project. Which is very convenient, because it makes it possible to create a copy with just three clicks of the mouse without typing anything from the keyboard.

    Making a working copy of a project

    The copied project automatically appears in the Projects window, but does not become the main one. That is, you continue to work with the previous project, and all its open windows are saved. You can immediately close a new project - right-click on its name, and in the pop-up menu that appears, select “Close Project”.

    What is such a project management system for? The fact is that novice programmers have a habit of destroying the results of their own labor. They develop the project without preserving archives. They bring it to an almost working state, then improve it a little more, then another - and everything stops working. And since they are completely confused, it is no longer possible to restore a working version. And they have nothing to show the teacher or the boss!

    Therefore, you should get used to copying to the archive all intermediate versions of the project, which are more efficient than those already saved to the archive. In real projects, it is difficult to remember all the changes made in a particular version, and more importantly, all the relationships that caused those changes. Therefore, even experienced programmers have to admit from time to time: "Nothing works!" And to restore the version, which did not yet have those innovations that led to confusion. In addition, it often happens that a new version does not work correctly in some situations. And you have to go back dozens of versions in search of the one where there were no such "glitches". And then carefully compare the work of the two versions to find out why the later version does not work. Or make sure that all previous versions also worked incorrectly, just did not notice the error.

  • Foreign policy of the USSR during the war. Lend-Lease. Tehran conference. Yalta and Potsdam conferences 1945 Creation of the UN.
  • Foreign policy of the USSR during the war. Lend-Lease. Tehran conference. Yalta and Potsdam conferences 1945 Creation of the UN.
  • Resumption of BSG activities. Creation of Belnats parties and organizations





  • 

    2021 gtavrl.ru.