Наложенные JPanels не выстраиваются - PullRequest
0 голосов
/ 28 апреля 2018

Я пытаюсь создать окрашиваемую JPanel с опциональным отображением линии сетки. Для этого у меня есть пользовательская JPanel, которая создает другую JPanel, которая содержит только линии сетки. Таким образом, я могу показать / скрыть линии сетки, даже не удаляя то, что находится на холсте.

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

Вот пример проблемы: An Example of the grid

package com.carvethsolutions.guilib.customcomp;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

/**
 * A custom component for displaying a grid
 */
public class GridCanvas extends JPanel implements MouseListener {

/**
 * Width and height of the canvas, in pixels
 */
private int width, height;

/**
 * How many pixels represent one square on the grid
 */
private int gridScale;

/**
 * The separate panel that holds the grid lines
 */
private JPanel gridPanel;

private boolean gridLinesVisible = true;

/**
 * Holds color selections
 */
private Paintbrush paintbrush;

public GridCanvas() {
    super();
    width = 500;
    height = 500;

    setupComponent();
}

public GridCanvas(int width, int height) {
    super();
    this.width = width;
    this.height = height;

    setupComponent();
}

/**
 * Private function to prepare the component.
 */
private void setupComponent() {
    gridScale = 50;
    this.setPreferredSize(new Dimension(width,height));
    this.setBackground(Color.WHITE);

    this.addMouseListener(this);

    gridPanel = new JPanel() {
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            // Vertical Lines
            for (int x = gridScale; x <= width; x += gridScale) {
                g.drawLine(x, 0, x, height);
            }

            for (int y = gridScale; y <= height; y += gridScale) {
                g.drawLine(0, y, width, y);
            }
        }
    };

    gridPanel.setVisible(gridLinesVisible);
    gridPanel.setPreferredSize(this.getPreferredSize());
    this.add(gridPanel);

    this.setSize(gridPanel.getSize());
    paintbrush = new Paintbrush(Color.black);
}

/**
 * Enable or disable grid lines from appearing on the Canvas
 */
public void toggleGridlines() {
    gridLinesVisible = !gridLinesVisible;
    gridPanel.setVisible(gridLinesVisible);
}


/**
 * Invoked when the mouse button has been clicked (pressed
 * and released) on a component.
 *
 * @param e
 */
@Override
public void mouseClicked(MouseEvent e) {
    int x = e.getX() / gridScale;
    int y = e.getY() / gridScale;

    System.out.println("mouseClicked Event : (" + x + ", " + y + ")");

    this.getGraphics().setColor(paintbrush.getColor());
    this.getGraphics().fillRect(x * gridScale, y * gridScale, gridScale, gridScale);
}

/**
 * Invoked when a mouse button has been pressed on a component.
 *
 * @param e
 */
@Override
public void mousePressed(MouseEvent e) {

}

/**
 * Invoked when a mouse button has been released on a component.
 *
 * @param e
 */
@Override
public void mouseReleased(MouseEvent e) {

}

/**
 * Invoked when the mouse enters a component.
 *
 * @param e
 */
@Override
public void mouseEntered(MouseEvent e) {

}

/**
 * Invoked when the mouse exits a component.
 *
 * @param e
 */
@Override
public void mouseExited(MouseEvent e) {

}
}

1 Ответ

0 голосов
/ 28 апреля 2018

Для этого у меня есть пользовательская JPanel, которая создает другую JPanel, которая содержит только линии сетки. Таким образом, я могу показать / скрыть линии сетки, даже не удаляя то, что находится на холсте.

Ну, это неправильный подход. Ваша панель должна иметь свойства:

  1. рисовать линии сетки или нет
  2. 2D-массив для контроля того, какие квадраты должны быть заполнены.

Ваша логика рисования неверна:

this.getGraphics().setColor(paintbrush.getColor());
this.getGraphics().fillRect(x * gridScale, y * gridScale, gridScale, gridScale);

Вы никогда не должны использовать getGraphics (...) на компоненте, чтобы сделать пользовательскую рисование. В первый раз, когда Swing определит, что компоненты должны быть перекрашены, вы потеряете всю картину. Например, если вы измените размер фрейма.

Вместо. произвольная окраска должна быть сделана в paintComponent() компонента. Тогда вы:

  1. сначала закрасьте линии сетки, если требуется
  2. итерация по массиву 2D и рисование любых квадратов по мере необходимости.

Прочтите раздел из учебника Swing по Custom Painting для получения дополнительной информации и рабочих примеров.

Или вместо 2D Array, используйте ArrayList для хранения объектов, которые нужно нарисовать. Этот объект может просто быть Point объектом для управления положением x / y квадрата, который должен быть нарисован, или может быть объектом, который содержит полную информацию об объекте, который будет нарисован, такой как местоположение / цвет / форма. Проверьте Пользовательские подходы к рисованию для рабочего примера этого подхода.

...