Visual J# Concepts
How to: Create a New Swing Application

The Supplemental UI Library for the Visual J# library provides much of the Swing functionality, which supports building traditional graphic user interface (GUI) and graphics functionality for client applications. The vjssupuilib library automatically ships with Visual J# and contains features for building robust Windows applications that run within the .NET Framework.

The following example demonstrates many of the Swing features and how they can interoperate with the AWT library. This example also shows you how to create them programmatically. At run time, the sample allows you to load a JPG graphic and shade, shape, or orient the image.

Create the frame and menu stubs

  1. Obtain a graphic .jpg file for editing in this example.

  2. Open a new console project named Swing.

  3. In Solution Explorer, right-click on References, and click to Add Reference.

  4. Select the VJSSupUILib.dll, and click OK.

    A reference to the Microsoft Supplemental UI Library for Visual J# library is now included in your project. This library includes Swing components for user applications such as buttons, boxes, and borders.

  5. In Solution Explorer, make sure Program.jsl is selected, and then replace the code with the following code:

    import javax.swing.*;
    import javax.swing.event.*;
    import javax.swing.border.*;
    import javax.swing.filechooser.FileFilter;
    import java.awt.*;
    import java.awt.image.*;
    import java.awt.event.*;
    import java.io.File;
    
    public class ImageViewerApp extends JFrame implements ActionListener, ChangeListener
    {
        // Component handles:
        private JMenuItem mLoad, mExit, mUndo, mOriginal,mProperties, mFlipX, mFlipY;
        private JSplitPane splitPane;
        private JLabel origImageLbl, workImageLbl;
        private JSlider sliderWidth, sliderHeight;
    
        // Working, original, and previous images:
        private Image workImage, originalImage, previousImage;

    Notice that the class declaration inherits from JFrame to create a simple Swing window. To monitor the frame, this example also implements both the ActionListener and ChangeListener interfaces.

  6. Now add the menus and formatting for the viewer as follows:

        public ImageViewerApp(String title)
        {
            super(title);
            // Exit when window is closed.
            setDefaultCloseOperation(EXIT_ON_CLOSE);
    
            // Initalize each menu.
            initMenuBar();
            origImageLbl = new JLabel();
            workImageLbl = new JLabel();
            origImageLbl.setHorizontalAlignment(JLabel.CENTER);
            workImageLbl.setHorizontalAlignment(JLabel.CENTER);
    
            JScrollPane origImagePane = new JScrollPane(origImageLbl);
            origImagePane.setBorder(new TitledBorder("Original Image"));
    
            JScrollPane workImagePane = new JScrollPane(workImageLbl);
            workImagePane.setBorder(new TitledBorder("Modified Image"));
    
            splitPane = new JSplitPane();
            splitPane.setLeftComponent(origImagePane);
            splitPane.setRightComponent(workImagePane);
            splitPane.setDividerSize(10);
            splitPane.setOneTouchExpandable(true);
            splitPane.setContinuousLayout(true);
            getContentPane().add(splitPane);
            getContentPane().setBackground(Color.lightGray);
    
            setSize((int)(550 * 1.61), 550);
            setResizable(false);
            showWorkBench();
        }

    Remember that your code manually controls the shape and size of the screen. For example, you can change the screen size by updating the XY coordinates in the setSize method.

  7. Define each item that displays on the menu bar and add it to the ActionListener as follows:

        private void initMenuBar()
        {
            JMenuBar menuBar = new JMenuBar();
            JMenu menu;
    
            // File.
            menu = new JMenu("File");
            menu.setMnemonic('F');
            menu.setToolTipText("Load Image to manipulate");
    
            mLoad = new JMenuItem("Load Image");
            mLoad.setMnemonic('L');
            mLoad.addActionListener(this);
            menu.add(mLoad);
            menu.addSeparator();
    
            mExit = new JMenuItem("Exit");
            mExit.setMnemonic('x');
            mExit.addActionListener(this);
            menu.add(mExit);
            menuBar.add(menu);
    
            // Edit.
            menu = new JMenu("Edit");
            menu.setMnemonic('E');
            menu.setToolTipText("Edit Image");
    
            mUndo = new JMenuItem("Undo");
            mUndo.setMnemonic('U');
            mUndo.setEnabled(false);
            mUndo.addActionListener(this);
            menu.add(mUndo);
    
            mOriginal = new JMenuItem("Revert to Original Image");
            mOriginal.setMnemonic('R');
            mOriginal.setEnabled(false);
            mOriginal.addActionListener(this);
            menu.add(mOriginal);
    
            mProperties = new JMenuItem("Scale");
            mProperties.setMnemonic('C');
            mProperties.addActionListener(this);
            mProperties.setEnabled(false);
            menu.add(mProperties);
            menuBar.add(menu);
    
            // Rotate.
            menu = new JMenu("Rotate");
            menu.setMnemonic('R');
            menu.setToolTipText("Rotate images");
    
            mFlipX = new JMenuItem("Flip Vertically");
            mFlipX.setMnemonic('V');
            mFlipX.setEnabled(false);
            mFlipX.addActionListener(this);
            menu.add(mFlipX);
    
            mFlipY = new JMenuItem("Flip Horizontally");
            mFlipY.setMnemonic('H');
            mFlipY.setEnabled(false);
            mFlipY.addActionListener(this);
            menu.add(mFlipY);
            menuBar.add(menu);
            setJMenuBar(menuBar);
        }

    Each instance of JMenuItem controls the text that is displayed to the user from the drop-down menus. The setMnemonic method defines an alternate short cut key. In the final step, setJMenuBar adds each component to the menu bar.

  8. Create a window called Workbench that generates at run time, manage the slider bars, and implement ActionListener as follows:

        // Shows the screen.  
        private void showWorkBench()
        {
            final Window workBench;
            Timer timer = null;
    
            // Creates a Swing window, casts to AWT: 
            JWindow wnd = new JWindow(this);
            wnd.pack();
            workBench = wnd;
    
            ActionListener listen = new ActionListener()
            {
                public void actionPerformed(ActionEvent event)
                {
                    workBench.dispose();
                    workBench.getParent().show();
    
                    // Set center divider to 0.495 after frame displays.
                    splitPane.setDividerLocation(0.495);
                }
            };
                // Center dialog on screen.
                Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
                workBench.setLocation((screenSize.width - workBench.getWidth()) / 2,
                    (screenSize.height - workBench.getHeight()) / 2);
    
                // Listener is time-driven.
                // One second.
                timer = new Timer(1000, listen);
                timer.setRepeats(false);
                timer.start();
                workBench.show();
        }
    
        // Fires when size changes by slider.
        public void stateChanged(ChangeEvent event)
        {
            if (sliderWidth.getValueIsAdjusting() || sliderHeight.getValueIsAdjusting())
                return;
    
            int width = sliderWidth.getValue();
            int height = sliderHeight.getValue();
    
            Image filteredImage = workImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            setImage(filteredImage);
        }

    Notice that workBench = wnd, casts a JWindow to an AWT Window, so that the AWT ActionListener can manage the window. Using the Timer, the listener checks the window for updates at one-second intervals.

  9. Insert the following code to implement each menu item:

        public void actionPerformed(ActionEvent event)
        {
            Object evtSource = event.getSource();
            if (evtSource.equals(mUndo))
            {
                if (previousImage != null)
                    setAndCommitImage(previousImage);
            }
            else if (evtSource.equals(mProperties))
                new ScaleDialog(this);
            else if (evtSource.equals(mOriginal))
            {
                setAndCommitImage(originalImage);
                // Restoring the original background:
                splitPane.getRightComponent().setBackground(
    splitPane.getLeftComponent().getBackground());
            }
            else if (evtSource.equals(mLoad))
            {
                JFileChooser fileChooser = new JFileChooser(new File("."));
                fileChooser.setFileFilter(new JpgFileManager());
    
                int returnVal = fileChooser.showOpenDialog(this);
                if (returnVal != JFileChooser.APPROVE_OPTION)
                    return;
    
                File file = fileChooser.getSelectedFile();
                if (file == null)
                    return;
                else if (!file.exists())
                {
                    String msg = "The file '" + file.getName() + "' not found.\n" +
                        "Please verify that the correct file name was given.";
                    JOptionPane.showMessageDialog(this, msg, "Image Viewer",
                        JOptionPane.ERROR_MESSAGE);
                    return;
                }
    
                if (workImage != null)
                    workImage.flush();
    
                workImage = Toolkit.getDefaultToolkit().getImage(file.getAbsolutePath());
                if (workImage == null)
                    return;
    
                originalImage = Toolkit.getDefaultToolkit().getImage(file.getAbsolutePath());
                origImageLbl.setIcon(new ImageIcon(originalImage, ""));
                workImageLbl.setIcon(new ImageIcon(workImage, ""));
                previousImage = null;
                mFlipX.setEnabled(true);
                mFlipY.setEnabled(true);
                mUndo.setEnabled(false);
                mOriginal.setEnabled(true);
                mProperties.setEnabled(true);
                repaint();
            }
    
            else if (evtSource.equals(mExit))
            {
                dispose();
                System.exit(0);
            }
            (evtSource.equals(mFlipX))
                flip(false);
            else if (evtSource.equals(mFlipY))
                flip(true);
        }

    Notice that the event.getSource method returns the user's action. If you add more features to the application, you can add an additional else if clause to manage these events.

  10. Insert the main method that drives the application as follows:

        public static void main(String[] args)
        {
            new ImageViewerApp("ImageViewer - A Visual J# .NET Demo");
        } 
  11. From the Build menu, click Build Solution.

  12. If you run the application at this point, an empty window with menu items opens.

To add code to manage loading

  • Insert the following code to assist the user while working with JPG graphics:

        class JpgFileManager extends FileFilter
        {
            public String getDescription()
            {
                return "JPG Files (*.jpg)";
            }
    // Seeks directory or file.
            public boolean accept(File file)
            {
                if (file.isDirectory())
                {
                    return true;
                }
                else
                {
                    String filepathname = file.getAbsolutePath().toLowerCase();
                    if (filepathname.endsWith(".jpg"))
                        return true;
                }
                return false;
            }
        }
    //Rotates the image and copies it to the right panel.
        private void flip(boolean aboutY)
        {
            final int width = workImage.getWidth(null);
            final int height = workImage.getHeight(null);
            final int total = width * height;
    
            // Load the workImage pixels into the imagePixels array:
            int imagePixels[] = new int[total];
    
            PixelGrabber pg = new PixelGrabber(workImage, 0, 0, width, height,
                imagePixels, 0, width);
            try
            {
                pg.grabPixels();
            }
            catch (InterruptedException e) { } ;
    
            if (aboutY)
            {
                // About Y-axis:
                int center = width / 2;
                int temp;
                for (int t = 0; t < total; t += width)
                {
                    for (int c = 0; c < center; c++)
                    {
                        temp = imagePixels[t + c];
                        imagePixels[t + c] = imagePixels[t + width - 1 - c];
                        imagePixels[t + width - 1 - c] = temp;
                    }
                }
            }
            else
            {
                // About X-axis:
                int center = total / 2;
                int temp;
                for (int t = 0; t < width; t++)
                {
                    for (int c = 0; c < center; c += width)
                    {
                        temp = imagePixels[t + c];
    `                    imagePixels[t + c] = imagePixels[total + t - width - c];
                        imagePixels[total + t - width - c] = temp;
                    }
                }
            }
    
            Image filteredImage = createImage(new
     MemoryImageSource(width, height, imagePixels, 0, width));
            setAndCommitImage(filteredImage);
        }
    // Copies the image to the right panel that stores modified image.
        private void setImage(Image newImage)
        {
            workImageLbl.setIcon(new ImageIcon(newImage));
        }
    // Refresh the right panel that stores modified image.
        private void setAndCommitImage(Image newImage)
        {
            if (workImage != null)
                workImage.flush();
    
            previousImage = workImage;
            workImage = newImage;
            workImageLbl.setIcon(new ImageIcon(workImage));
            mUndo.setEnabled(true);
        }
        private void commitImage()
        {
            Icon icon = workImageLbl.getIcon();
            setAndCommitImage(((ImageIcon)icon).getImage());
        }
    }

    Notice that the JpgFileManager class extends FileFilter for assisting the user with loading the images for a particular directory. In the method flip, the image rotates and calls ActionListener to copy the graphic to the right panel that stores the modified image.

To add code to scale graphics

  1. Insert the following code to add the following class and manage scaling:

    class ScaleDialog extends JDialog implements ActionListener
        {
            public ScaleDialog(JFrame parent)
            {
                super(parent, "Scale", true);
    
                int width = workImage.getWidth(null);
                int height = workImage.getHeight(null);
                int maxW = Math.max(width, 1200);
                int maxH = Math.max(height, 1000);
    
                sliderWidth = new JSlider(0, maxW, width);
                sliderWidth.setBorder(new TitledBorder("Width"));
                sliderWidth.setMajorTickSpacing(100);
                sliderWidth.setPaintTicks(true);
                sliderWidth.setPaintLabels(true);
                sliderWidth.setMinorTickSpacing(50);
                sliderWidth.addChangeListener((ChangeListener)parent);
    
                sliderHeight = new JSlider(0, maxH, height);
                sliderHeight.setBorder(new TitledBorder("Height"));
                sliderHeight.setMajorTickSpacing(100);
                sliderHeight.setPaintTicks(true);
                sliderHeight.setPaintLabels(true);
                sliderHeight.setMinorTickSpacing(50);
                sliderHeight.addChangeListener((ChangeListener)parent);
    
                JPanel sliders = new JPanel(new GridLayout(2, 1, 4, 4));
                sliders.add(sliderWidth);
                sliders.add(sliderHeight);
    
                // ok cancel buttons panel
                JButton ok = new JButton("OK");
                JButton cancel = new JButton("Cancel");
                ok.addActionListener(this);
                cancel.addActionListener(this);
                ok.addActionListener((ActionListener)parent);
                cancel.addActionListener((ActionListener)parent);
    
                JPanel buttonsPanel = new JPanel();
                buttonsPanel.add(ok);
                buttonsPanel.add(cancel);
    
                getContentPane().add(sliders, BorderLayout.CENTER);
                getContentPane().add(buttonsPanel, BorderLayout.SOUTH);
    
                setResizable(false);
                setSize((int)(300 * 1.61), 300);
                setLocationRelativeTo(parent);
    
                // Add a Window closing listener to simulate cancel.
                addWindowListener(new WindowAdapter()
                {
                    public void windowClosing(WindowEvent e)
                    {
                        setImage(workImage);
                    }
                });
    
                show();
            }
    
            public void actionPerformed(ActionEvent event)
            {
                String eventName = (String)event.getActionCommand();
                if (eventName.compareTo("OK") == 0)
                {
                    commitImage();
                    dispose();
                }
                else if (eventName.compareTo("Cancel") == 0)
                {
                    setImage(workImage);
                    dispose();
                }
            }
        }

    The ScaleDialog constructor accepts the parent window and creates a slider box for scaling images. Instead of manually entering the values on the new slider bar, the setMajorTickSpacing(100) method inserts the value every 100 ticks. Notice that another actionPerformed method handles the OK and Cancel buttons on the slider.

  2. Press F5 to compile and run the application.

    A window opens for image editing. When you open a graphic, the image displays in both label box panels. As you edit, or reorient the graphic, the update displays in the right panel.

See Also

Tags :


Page view tracker