Нужна помощь в настройке системы масштабирования в Graphics2D - Java

Это мой 1-й вопрос. Я пытаюсь создать белую страницу, регулируемую масштабированием. Он находится внутри JScrollPane, поэтому размер полос прокрутки JScrollPane регулируется в соответствии с размером этой панели JPanel.

Я хочу настроить размер этих полос прокрутки как размер страницы (ширина и высота переменных в коде) + 2 borderSize, чтобы полный размер был равен Page + margin для borderSize вокруг него. Работает, если zoom = 1.0.

Если масштаб <1.0, полоса прокрутки меньше, чем страница, и вырежьте ее кусок. Если масштаб> 1, размер Dimension намного больше, чем размер страницы, оставляя большую границу в правом и нижнем углах, больше, чем borderSize.

Как мне это сделать?

PS: Я начал изучать java самостоятельно, в прошлом году на карантине, учителя никогда не было, только интернет, так что любые критические замечания или предложения, пожалуйста, сообщите мне.

Вот код JPanel:

package test;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowStateListener;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
import javax.swing.JSlider;
import javax.swing.JScrollPane;
import javax.swing.JLabel;

public class Main2 {
private MyPanel mp = new MyPanel();
private JFrame frame;
private JSlider zoomSlider = new JSlider();
private JLabel zoomLabel = new JLabel("Zoom: XXX");

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                Main2 window = new Main2();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}


public Main2() {
    initialize();
}


private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 619, 403);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    SpringLayout springLayout = new SpringLayout();
    frame.getContentPane().setLayout(springLayout);
    
    
    springLayout.putConstraint(SpringLayout.SOUTH, zoomSlider, 40, SpringLayout.NORTH, frame.getContentPane());
    springLayout.putConstraint(SpringLayout.EAST, zoomSlider, -115, SpringLayout.EAST, frame.getContentPane());
    zoomSlider.setValue(100);
    zoomSlider.setSnapToTicks(true);
    zoomSlider.setPaintTicks(true);
    zoomSlider.setMaximum(200);
    zoomSlider.setMinorTickSpacing(5);
    zoomSlider.setMinimum(5);
    springLayout.putConstraint(SpringLayout.NORTH, zoomSlider, 0, SpringLayout.NORTH, frame.getContentPane());
    springLayout.putConstraint(SpringLayout.WEST, zoomSlider, 0, SpringLayout.WEST, frame.getContentPane());
    frame.getContentPane().add(zoomSlider);
    
    JScrollPane scrollPane = new JScrollPane(mp);
    springLayout.putConstraint(SpringLayout.NORTH, scrollPane, 10, SpringLayout.SOUTH, zoomSlider);
    springLayout.putConstraint(SpringLayout.WEST, scrollPane, 10, SpringLayout.WEST, frame.getContentPane());
    springLayout.putConstraint(SpringLayout.SOUTH, scrollPane, -10, SpringLayout.SOUTH, frame.getContentPane());
    springLayout.putConstraint(SpringLayout.EAST, scrollPane, -10, SpringLayout.EAST, frame.getContentPane());
    frame.getContentPane().add(scrollPane);
    
    
    springLayout.putConstraint(SpringLayout.NORTH, zoomLabel, 10, SpringLayout.NORTH, frame.getContentPane());
    springLayout.putConstraint(SpringLayout.WEST, zoomLabel, 6, SpringLayout.EAST, zoomSlider);
    frame.getContentPane().add(zoomLabel);
    
    
    frame.addWindowStateListener(new WindowStateListener() {

        @Override
        public void windowStateChanged(WindowEvent arg0) {
            // TODO Auto-generated method stub
            mp.draw();
        }
        
    });
    
    
    zoomSlider.addMouseListener(new MouseListener() {

        @Override
        public void mouseClicked(MouseEvent arg0) {
            // TODO Auto-generated method stub
            int temp = (zoomSlider.getValue())-zoomSlider.getValue()%5;
            setZoom(temp);
            
            mp.draw();
            
        }

        @Override
        public void mouseEntered(MouseEvent arg0) {
            // TODO Auto-generated method stub
            
        }

        @Override
        public void mouseExited(MouseEvent arg0) {
            // TODO Auto-generated method stub
            
        }

        @Override
        public void mousePressed(MouseEvent arg0) {
            // TODO Auto-generated method stub
    
        }

        @Override
        public void mouseReleased(MouseEvent arg0) {
            int temp = (zoomSlider.getValue())-zoomSlider.getValue()%5;
            setZoom(temp);
            
            
            mp.draw();
        
            
        }
        
        
        
    });
    
    mp.addMouseWheelListener(new MouseWheelListener() {
        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
            if (e.getPreciseWheelRotation() < 0) {
                
                setZoom(zoomSlider.getValue()- 5);
           
            } else {
                setZoom(zoomSlider.getValue()+ 5);
            }
        // zoom += e.getPreciseWheelRotation();
            if (mp.getZoom()*100 < 10) {
                setZoom(10);
            }
            mp.draw();
        }
        });
    
    AdjustmentListener adj = new AdjustmentListener() {

        @Override
        public void adjustmentValueChanged(AdjustmentEvent e) {
            setZoom(zoomSlider.getValue());
            mp.draw();
            
        }
        
    };
    scrollPane.getVerticalScrollBar().addAdjustmentListener(adj);
    scrollPane.getHorizontalScrollBar().addAdjustmentListener(adj);
    
    
}
public void setZoom(int n) {
    mp.setZoom(n);
    zoomSlider.setValue(n);
    zoomLabel.setText("Zoom: "+mp.getZoom()+"x");
    
}
}
class MyPanel extends JPanel{

private static final long serialVersionUID = -716735372803790424L;

int borderSize=28;
int zoom=100;
int height = 3565;
int width = 2537;
int widthz, heightz; 

public MyPanel() {
setBackground(Color.DARK_GRAY);
}

@Override
public Dimension getPreferredSize() {
int a, b;
String temp;
Float x, y;
x=(getZoom()*width); //Size of the page adjusted by zoom
y=(getZoom()*height);

temp = x.toString(); 
String temp1[] = temp.split("\\."); // converted to string to convert it to int
a = Integer.valueOf(temp1[0])+2*borderSize; //that value + 2 BorderSize
temp = y.toString();
String temp2[] = temp.split("\\.");
b = Integer.valueOf(temp2[0])+2*borderSize;

return new Dimension (a,b);
}

@Override
public void paintComponent (Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d = putZoom(g2d);
g2d.setColor(Color.WHITE);
g2d.fillRect(this.getX(),this.getY(), width, height);
g2d.setColor(Color.BLACK);
g2d.drawRect(this.getX()+borderSize,this.getY()+borderSize,width-2*borderSize,height-2*borderSize);
g2d.dispose();

}

public Graphics2D putZoom(Graphics2D g) {

AffineTransform at = new AffineTransform();
at.translate(borderSize,borderSize); // put the page a borderSize from the upper-left corner
at.scale(getZoom(),getZoom()); //adjust the page as zoom 

Graphics2D g2d = g;
g2d.setTransform(at);
return g2d;
}

public void draw() { //this method is to update the draw from the main
repaint();

}

public Float getZoom() {
return Float.valueOf(zoom)/100;
}
public void setZoom(int zom) { //this method is to update Zoom from the main

zoom=zom;
String zoomheight []= (String.valueOf(getZoom()*height)).split("\\.");
heightz = Integer.valueOf(zoomheight[0]);
String zoomwidth []= (String.valueOf(getZoom()*width)).split("\\.");
widthz = Integer.valueOf(zoomwidth[0]);

}

public int getZoomInt() {
return this.zoom;
}

}

Масштаб (значения от 0,1 до 2,0).

Как я могу это улучшить? Кроме того, я понятия не имею, как обновить полосы прокрутки JScrollPane вместе с увеличением. Спасибо за помощь.

Обновлено: Я создал минимальный воспроизводимый пример.

Что вы хотите, чтобы произошло с вашим графическим интерфейсом, когда масштаб больше 1.0? Без минимальный воспроизводимый пример, который мы можем скопировать в нашу IDE и поэкспериментировать, и не зная, что вы хотите, чтобы ваша функция масштабирования выполняла, трудно оказать какую-либо помощь. Поскольку вы новичок в Java и Swing, я рекомендую вам ознакомиться с Oracle Учебники по Java.

Gilbert Le Blanc 30.03.2021 15:58
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
1
44
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вступление

Я начал работать над этим до того, как вы обновили свой вопрос. Я использовал процент масштабирования, а не коэффициент масштабирования.

Я создал следующий графический интерфейс и установил начальное состояние на 30 процентов.

Zoom JPanel 1

Я сделал внутренний JPanel шахматной доской, чтобы вам было легче видеть зум. Я изменил ваши начальные значения так, чтобы внутренний JPanel представлял собой лист бумаги размером 8 1/2 x 11 с плотностью 50 пикселей на дюйм.

Вот тот же графический интерфейс на 100 процентов.

Zoom JPanel 2

Вот тот же графический интерфейс на 10 процентов.

Zoom JPanel 3

Объяснение

Я создал JFrame и контрольный JPanel для хранения JSlider. Я использовал GridLayout для создания контрольного JPanel.

Я создал внутренний JPanel для хранения чертежа и дисплей JPanel, в котором находится JScrollPane. Я сделал дисплей JPanel пропорциональным размеру внутреннего JPanel, чтобы у меня не было проблем с растяжением.

Получение GUI для повторной проверки / перерисовки оказалось самой большой проблемой. Я получил invalidate, JScrollPane, как JScrollBars, так и дисплей JPanel. Мне также приходилось сбрасывать JScrollBars на ноль каждый раз, когда я менял процент масштабирования.

Код

Вот полный исполняемый код. Я сделал все классы внутренними классами, чтобы опубликовать их как один блок кода.

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ZoomJPanelGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new ZoomJPanelGUI());
    }
    
    private int zoomPercentage = 30;
    
    private DisplayPanel displayPanel;
    
    private JFrame frame;

    @Override
    public void run() {
        frame = new JFrame("Zoom JPanel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(createControlPanel(), BorderLayout.BEFORE_FIRST_LINE);
        this.displayPanel = new DisplayPanel(zoomPercentage);
        frame.add(displayPanel.getPanel(), BorderLayout.AFTER_LAST_LINE);

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JPanel createControlPanel() {
        JPanel panel = new JPanel(new GridLayout(0, 1));
        panel.setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
        
        JLabel label = new JLabel("Zoom Percentage");
        label.setFont(panel.getFont().deriveFont(Font.BOLD, 24f));
        panel.add(label);
        
        JSlider slider =  new JSlider(
                JSlider.HORIZONTAL, 10, 100, zoomPercentage);
        slider.setFont(panel.getFont().deriveFont(16f));
        slider.setMajorTickSpacing(30);
        slider.setMinorTickSpacing(5);
        slider.setPaintTicks(true);
        slider.setPaintLabels(true);
        
        slider.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent event) {
                JSlider slider = (JSlider) event.getSource();
                if (!slider.getValueIsAdjusting()) {
                    zoomPercentage = (int) slider.getValue();
                    displayPanel.setZoomPercentage(zoomPercentage);
                    displayPanel.repaint();
                    frame.pack();
                }
            }   
        });
        
        panel.add(slider);
        
        return panel;
    }
    
    public class DisplayPanel {
        
        private InnerPanel innerPanel;
        
        private final JPanel panel;
        
        private JScrollPane scrollPane;
        
        private int zoomPercentage;
        
        public DisplayPanel(int zoomPercentage) {
            this.zoomPercentage = zoomPercentage;
            this.panel = createDisplayPanel();
        }

        private JPanel createDisplayPanel() {
            JPanel panel = new JPanel(new BorderLayout());
            panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
            
            this.innerPanel = new InnerPanel(zoomPercentage);
            scrollPane = new JScrollPane(innerPanel);
            scrollPane.setPreferredSize(new Dimension(475, 600));
            panel.add(scrollPane, BorderLayout.CENTER);
            
            return panel;
        }
        
        public void setZoomPercentage(int zoomPercentage) {
            this.zoomPercentage = zoomPercentage;
            innerPanel.setZoomPercentage(zoomPercentage);
        }

        public JPanel getPanel() {
            return panel;
        }

        public void repaint() {
            innerPanel.repaint();
            scrollPane.invalidate();
            JScrollBar hScrollBar = scrollPane.getHorizontalScrollBar();
            JScrollBar vScrollBar = scrollPane.getVerticalScrollBar();
            hScrollBar.setValue(0);
            vScrollBar.setValue(0);
            hScrollBar.invalidate();
            vScrollBar.invalidate();
            panel.invalidate();
        }
        
    }
    
    public class InnerPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        private int maximumBorderSize = 25;
        private int maximumCellSize = 50;
        private int maximumHeight = 5500;
        private int maximumWidth = 4250;
        private int zoomPercentage;
        
        public InnerPanel(int zoomPercentage) {
            this.zoomPercentage = zoomPercentage;
        }
        
        public void setZoomPercentage(int zoomPercentage) {
            this.zoomPercentage = zoomPercentage;
        }

        @Override
        public Dimension getPreferredSize() {
            int width = maximumWidth * zoomPercentage / 100;
            int height = maximumHeight * zoomPercentage / 100;
            return new Dimension(width, height);
        }
        
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            
            int borderSize = maximumBorderSize * zoomPercentage / 100;
            paintBackground(g2d);
            paintBorder(g2d, borderSize);
            paintCheckerboard(g2d, borderSize);
        }

        private void paintBackground(Graphics2D g2d) {
            g2d.setColor(Color.WHITE);
            g2d.fillRect(0, 0, getWidth(), getHeight());
        }

        private void paintBorder(Graphics2D g2d, int borderSize) {
            g2d.setColor(Color.BLACK);
            g2d.setStroke(new BasicStroke(3f));
            g2d.drawRect(borderSize, borderSize, getWidth() - 2 * borderSize,
                    getHeight() - 2 * borderSize);
        }

        private void paintCheckerboard(Graphics2D g2d, int borderSize) {
            int cellSize = maximumCellSize * zoomPercentage / 100;
            int width = maximumWidth - maximumBorderSize * 2 - 2;
            int height = maximumHeight - maximumBorderSize * 2 - 2;
            int cellWidth = width / maximumCellSize;
            int cellHeight = height / maximumCellSize;
            
            boolean isBlue = true;
            int x = borderSize;
            int y = borderSize;
            int heightRemainder = height - cellHeight * cellSize;
            for (int i = 0; i < cellHeight; i++) {
                int widthRemainder = width - cellWidth * cellSize;
                for (int j = 0; j < cellWidth; j++) {
                    if (isBlue) {
                        g2d.setColor(Color.BLUE);
                    } else {
                        g2d.setColor(Color.YELLOW);
                    }
                    isBlue = !isBlue;
                    g2d.fillRect(x, y, cellSize, cellSize);
                    x += cellSize;
                    if (widthRemainder > 0) {
                        x++;
                        widthRemainder--;
                    }
                }
//              isBlue = !isBlue;
                x = borderSize;
                y += cellSize;
                if (heightRemainder > 0) {
                    y++;
                    heightRemainder--;
                }
            }
        }
        
    }

}

Мне очень понравился ваш код, я многому научился на нем и собираюсь прочитать его больше, спасибо за него, но у него все еще та же проблема. Если zoomPercentage <100% (или 1.0 в моем случае), полоса прокрутки обрезает шахматную доску (посмотрите, как шахматная доска выходит за пределы созданной вами черной границы), а если вы используете zoomPercentagem> 100%, при расширении ползунка шахматная доска будет меньше полоса прокрутки и граница.

Yuri Pinto 30.03.2021 22:30

@ Юрий Пинто: Ага. Независимо от того, как вы увеличиваете масштаб, вам приходится иметь дело с дробными пикселями. Я намеренно сохранил пределы масштабирования от 10 до 100 процентов по причинам, которые вы указали.

Gilbert Le Blanc 30.03.2021 22:56
Ответ принят как подходящий

Наконец-то я это сделал. Начинали с того, что не использовали преобразование для масштабирования, а создавали новую отрисовку с увеличенным размером, адаптируя все размеры в методе setSizes () и настраивая размер в соответствии с этими размерами. (Только что изменил этот класс)

class MyPanel extends JPanel{

private static final long serialVersionUID = -716735372803790424L;

int borderSize=28;
int zoom=100;
int height = 3565;
int width = 2537;
int widthz, heightz;
int maxHeight, maxWidth; //max size of draw
int maxAreaHeight, maxAreaWidth; //max size of area

public MyPanel() {
    setBackground(Color.DARK_GRAY);
}

@Override
public Dimension getPreferredSize() {
    setSizes();
    return new Dimension (maxAreaWidth,maxAreaHeight);
}

@Override
public void paintComponent (Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g.create();
    g2d= createBase(g2d);

}

public void draw() { //this method is to update the draw from the main
    repaint();

}

public Float getZoom() {return Float.valueOf(zoom)/100;}
public void setZoom(int zom) {zoom=zom;}
public int getZoomInt() {return this.zoom;}

public void setSizes () {
    widthz= width*getZoomInt()/100;
    heightz=height*getZoomInt()/100;
    maxHeight = heightz+2*borderSize;
    maxWidth = widthz +2*borderSize;
    maxAreaHeight = this.getY()+maxHeight;
    maxAreaWidth = this.getX()+maxWidth;

    if (this.getSize() != new Dimension(maxAreaWidth, maxAreaHeight)) {
        this.setSize(maxAreaWidth, maxAreaHeight);
    }
}
public Graphics2D createBase(Graphics2D g2d) {
    Graphics2D g = g2d;
    setSizes();

    g.setColor(Color.WHITE);
    g.fillRect(this.getX()+borderSize,this.getY()+borderSize, widthz, heightz);
    g.setColor(Color.BLACK);
    g.drawRect(this.getX()+borderSize+borderSize*zoom/100,this.getY()+borderSize+borderSize*zoom/100,widthz-2*borderSize*zoom/100,heightz-2*borderSize*zoom/100);


    return g;
}

}

Спасибо за помощь.

Другие вопросы по теме