Каскадное и мозаичное расположение фреймов Java

Каскадное и мозаичное расположение фреймов JavaВ операционной системе Windows предусмотрено несколько команд для организации каскадного(cascading) расположения фреймов с перекрытием(см. рис. 1) и мозаичного(tiling) расположения фреймов безе перекрытия(см. рис. 2). Однако в классах JDesktopPane и JInternalFrame не предусмотрено никаких средств для поддержки этих операций. В программе которая находится в конце статьи показано, как можно самостоятельно организовать такое упорядочение фреймов.

Для каскадного расположения нужно указать для фреймов одинаковый размер и указывать их позиции с одинаковым шагом.

Каскадное и мозаичное расположение фреймов JavaРис. 1. Каскадное расположение фреймов

Каскадное и мозаичное расположение фреймов JavaРис. 2. Мозаичное расположение фреймов

Для получения массива всех внутренних фреймов используется метод getAllFrames() класса JDesktopPane:

JInternalFrame[] frame = desktop.getAllFrames();

Однако при этом нужно учитывать текущее состояние фрейма, которое может быть таким:

  • пиктограмма, то есть фрейм полностью свернут;
  • фрейм имеет обычные размеры и допускает их изменение;
  • фрейм полностью развернут.

Для поиска полностью свернутых фреймов, которые нужно пропустить, следует применять метод isIcon(). Для полностью развернутых фреймов нужно задать их обычный размер с помощью метода setMaximum(false). На изменение этого свойства также может быть наложен запрет, следовательно, необходимо организовать перехват исключения PropertyVetoException.

Ниже представлен цикл перебора всех внутренних фреймов панели рабочего стола:

for(JInternalFrame frame : desktop.getAllFrames())
{
    if(!frame.isIcon())
    {
        try
        {
            //    ,
            //    .
            frame.setMaximum(false);
            frame.reshape(x, y, width, height);
            x += frameDistance();
            y += frameDistance();
            //     .
            if(x + width > desktop.getWidth()) x = 0;
            if(y + height > desktop.getHeight()) y = 0;
         }
         catch(PropertyVetoException e)
         {}
    }
}

Мозаичное расположение фреймов организовать гораздо сложнее, особенно если количество фреймов таково, что они не образуют в точности квадратную решетку. Сначала необходимо подсчитать количество несвернутых фреймов, а затем определить количество строк мозаики:

int rows = (int) Math.sqrt(frameCount);

После этого определяется количество столбцов за исключением последнего:

int cols = frameCount / rows;

Последний незаполненный столбец выявляется так:

int extra = frameCount % rows;

Ниже представлен цикл перебора всех внутренних фреймов рабочего стола, которые будут расположены в виде мозаики:

int width = desktop.getWidth() / cols;
int height = desktop.getHeight() / rows;
int r = 0;
int c = 0;
for(JInternalFrame frame : desktop.getAllFrames())
{
    if(!frame.isIcon())
    {
        try
        {
            frame.setMaximum(false);
            frame.reshape(c * width, r * height, width, height);
            r++;
            if(r == rows)
            {
                r = 0;
                c++;
                if(c == cols - extra)
                {
                    //   .
                    rows++;
                    height = desktop.getHeight() / rows;
                 }
             }
         }
         catch(PropertyVetoException e)
         {}
    }
}

В программе, которая будет рассмотрена далее, показана еще одна распространенная операция: перемещение выбора от текущего фрейма к следующему несвернутому фрейму. Нужно вручную организовать обход всех фреймов и вызов метода isSelected() до тех пор, пока не будет найден текущий выбранный фрейм. Затем нужно найти следующий несвернутый фрейм и попытаться выбрать его с помощью приведенного ниже метода:

frames[next].setSelected(true);

Как и прежде, этот метод может генерировать исключение PropertyVetoException. Возврат к исходному фрейму означает, что не существует других доступных для выбора фреймов. Покажем, как выглядит цикл перебора всех внутренних фреймов.

JInternalFrames[] frames = desktop.getAllFrames();
for(int i = 0; i < frames.length; i++)
{
    if(frames[i].isSelected())
    {
        //    ,
        //    .
        int next = (i + 1) % frames.length;
        while(next != i)
        {
            if(!frames[next].isIcon())
            {
                try
                {
                    //    ,
                    //    .
                    frames[next].setSelected(true);
                    frames[next].toFront();
                    frames[i].toBack();
                    return;
                }
                catch(PropertyVetoException e)
                {}
            }
            next = (next + 1) % frames.length;
        }
    }
}

Код всей программы:

import java.awt.*;
import java.awt.event.*;
import java.beans.*;

import javax.swing.*;



/*
 *   
 *   .
 */

public class InternalFrameTest {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            
            public void run() {
                JFrame frame = new DesktopFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }

}

/*
 *    ,
 *    HTML-.
 */

class DesktopFrame extends JFrame
{
    public DesktopFrame()
    {
        setTitle("InternalFrameTest");
        setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        
        desktop = new JDesktopPane();
        add(desktop,BorderLayout.CENTER);
        
        //  .
        
        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);
        JMenu fileMenu = new JMenu("File");
        menuBar.add(fileMenu);
        JMenuItem openItem = new JMenuItem("New");
        openItem.addActionListener(new ActionListener() {
            
            public void actionPerformed(ActionEvent e) {
                createInternalFrame(
                        new JLabel(new ImageIcon(planets[counter] + ".gif")),
                        planets[counter]);
                counter = (counter + 1) % planets.length;
            }
        });
        fileMenu.add(openItem);
        JMenuItem exitItem = new JMenuItem("Exit");
        exitItem.addActionListener(new ActionListener() {
            
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        fileMenu.add(exitItem);
        JMenu windowMenu = new JMenu("Window");
        menuBar.add(windowMenu);
        JMenuItem nextItem = new JMenuItem("Next");
        nextItem.addActionListener(new ActionListener() {
            
            public void actionPerformed(ActionEvent e) {
                selectNextWindow();
            }
        });
        
        windowMenu.add(nextItem);
        JMenuItem cascadeItem = new JMenuItem("Cascade");
        cascadeItem.addActionListener(new ActionListener() {
            
            public void actionPerformed(ActionEvent e) {
                cascadeWindows();
            }
        });
        
        windowMenu.add(cascadeItem);
        JMenuItem tileItem = new JMenuItem("Tile");
        tileItem.addActionListener(new ActionListener() {
            
            public void actionPerformed(ActionEvent e) {
                tileWindows();
            }
        });
        windowMenu.add(tileItem);
        final JCheckBoxMenuItem dragOutlineItem =
                new JCheckBoxMenuItem("Drag Outline");
        dragOutlineItem.addActionListener(new ActionListener() {
            
            public void actionPerformed(ActionEvent e) {
                desktop.setDragMode(dragOutlineItem.isSelected() ?
                        JDesktopPane.OUTLINE_DRAG_MODE :
                                                JDesktopPane.LIVE_DRAG_MODE);
            }
        });
        windowMenu.add(dragOutlineItem);
    }
    
    /*
     *       .
     * @param       
     * @param t   .
     */
    
    public void createInternalFrame(Component c, String t)
    {
        final JInternalFrame iframe = new JInternalFrame(t, true,
                //   .
                true, //  .
                true, //  .
                true //  .
                );
        
        iframe.add(c, BorderLayout.CENTER);
        desktop.add(iframe);
        
        iframe.setFrameIcon(new ImageIcon("document.gif"));
        
        //     .
        iframe.addVetoableChangeListener(new VetoableChangeListener() {
            
            public void vetoableChange(PropertyChangeEvent event)
                    throws PropertyVetoException {
                String name = event.getPropertyName();
                Object value = event.getNewValue();
                
                //      
                //  .
                if(name.equals("closed") && value.equals(true)) {
                    int result = JOptionPane.showInternalConfirmDialog(iframe, "Ok to close?",
                            "Select an Option", JOptionPane.YES_NO_OPTION);
                    
                    //     
                    // ,   .
                    if(result != JOptionPane.YES_OPTION); {
                        throw new PropertyVetoException("User canceled close", event);
                    }
                }
            }
        });
        
        //  .
        int width = desktop.getWidth() / 2;
        int height = desktop.getHeight() / 2;
        iframe.reshape(nextFrameX, nextFrameY, width, height);
        
        iframe.show();
        
        //   -    .
        
        try
        {
            iframe.setSelected(true);
        }
        catch(PropertyVetoException e)
        {}
        
        frameDistance = iframe.getHeight() - iframe.getContentPane().getHeight();
        
        //    .
        
        nextFrameX += frameDistance;
        nextFrameY += frameDistance;
        if(nextFrameX + width > desktop.getWidth()) nextFrameX = 0;
        if(nextFrameY + height > desktop.getHeight()) nextFrameY = 0;
    }
    
    /*
     *   
     *  .
     */
    
    public void cascadeWindows()
    {
        int x = 0;
        int y = 0;
        int width = desktop.getWidth() / 2;
        int height = desktop.getHeight() / 2;
        
        for(JInternalFrame frame : desktop.getAllFrames())
        {
            if(!frame.isIcon())
            {
                try
                {
                    //     
                    //  .  
                    //  .
                    frame.setMaximum(false);
                    frame.reshape(x, y, width, height);
                    
                    x += frameDistance;
                    y += frameDistance;
                    
                    //    .
                    if(x + width > desktop.getWidth()) x = 0;
                    if(y + height > desktop.getHeight()) y = 0;
                }
                catch(PropertyVetoException e)
                {
                }
            }
        }
    }
    
    /*
     *     .
     */
    
    public void tileWindows()
    {
        //   .
        int frameCount = 0;
        for(JInternalFrame frame : desktop.getAllFrames())
        {
            if(!frame.isIcon()) frameCount++;
        }
        if(frameCount == 0) return;
        
        int rows = (int) Math.sqrt(frameCount);
        int cols = frameCount / rows;
        int extra = frameCount % rows;
        //     .
        
        int width = desktop.getWidth() / cols;
        int height = desktop.getHeight() / rows;
        int r = 0;
        int c = 0;
        for(JInternalFrame frame : desktop.getAllFrames())
        {
            if(!frame.isIcon())
            {
                try
                {
                    frame.setMaximum(false);
                    frame.reshape(c * width, r * height, width, height);
                    r++;
                    if(r == rows)
                    {
                        r = 0;
                        c++;
                        if(c == cols - extra)
                        {
                            //   .
                            rows++;
                            height = desktop.getHeight() / rows;
                        }
                    }
                }
                catch(PropertyVetoException e)
                {}
            }
        }
    }
    
    /*
     *    
     *   .
     */
    
    public void selectNextWindow()
    {
        JInternalFrame[] frames = desktop.getAllFrames();
        for(int i = 0; i < frames.length; i++)
        {
            if(frames[i].isSelected())
            {
                //    ,
                //    .
                int next = (i + 1) % frames.length;
                while(next != i)
                {
                    if(!frames[next].isIcon())
                    {
                        try
                        {
                            //    ,
                            //    .
                            frames[next].setSelected(true);
                            frames[next].toFront();
                            frames[i].toBack();
                            return;
                        }
                        catch(PropertyVetoException e)
                        {
                        }
                    }
                }
            }
        }
    }
    
    private JDesktopPane desktop;
    private int nextFrameX;
    private int nextFrameY;
    private int frameDistance;
    private int counter;
    private static final String[] planets = {"Mercury", "Venus", "Earth",
        "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto" };
    private static final int DEFAULT_WIDTH = 600;
    private static final int DEFAULT_HEIGHT = 400;
}

 

Комментариев 4 на “Каскадное и мозаичное расположение фреймов Java

  1. Обратите внимание на 146 строку. Там лишняя ” ; ” (точка с запятой). Фрейм закрываться не будет.

  2. Если при всех закрытых фреймах нажать кнопку “Следующее” то прога зависает. Необходимо добавить обработку исключительной ситуации if из строки 277 (например else после строки 300 выводящее сообщение “низя”).

  3. Чтобы поправить эту ошибку достаточно добавить после строки 298:
    next = (next + 1) % frames.length;

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *