Как использовать Canvas для рисования нескольких прямоугольников на основе пользовательского ввода?

Итак, в основном я пишу программу, в которой пользователь щелкает и перетаскивает мышь до желаемого размера и отпускает, заполняя прямоугольник на основе выбора из JComboBox.

базовый макет

Я реализовал MouseListener и MouseMotionListener для отслеживания местоположения мыши и рисования прямоугольника в зависимости от того, где пользователь впервые щелкнул, до того места, где он был отпущен.

Когда пользователь щелкает и перетаскивает (но не отпускает), есть drawRect(), но не fillRect() (например, прямоугольник не заполняется - только когда пользователь отпускает мышь, прямоугольник заполняется цветом ).

Этот класс создает объект Rect, у которого есть еще одна часть в конструкторе, представляющая собой выбранный цвет (который определяется в классе ColorListener ниже).

Здесь я включил свои переменные экземпляра, и все создается в конструкторе ниже:

private ArrayList<Rect> rectList;
private Color currentColor;
private Canvas canvas;
private JPanel controlPanel;
private JButton undo, erase;
private JComboBox comboBox;
private int xStart, yStart, xEnd, yEnd;
private Graphics page;
private Point pt = null;
private PointListener pointListener;
private ColorListener colorListener;

public WholePanel()
{
    // here we use black to draw a rectangle
    currentColor = Color.black;
    pointListener = new PointListener();
    addMouseListener(pointListener);
    addMouseMotionListener(pointListener);

    String[] listOfColors = {"black", "red", "blue", "green", "orange"};

    comboBox = new JComboBox(listOfColors);
    comboBox.setSelectedIndex(0);

    rectList = new ArrayList<Rect>();
    controlPanel = new JPanel(new GridLayout(1,3));

    undo = new JButton("Undo");
    erase = new JButton("Erase");
    controlPanel.add(comboBox);
    controlPanel.add(undo);
    controlPanel.add(erase);
    undo.addActionListener(new ButtonListener());
    erase.addActionListener(new ButtonListener());

    canvas = new Canvas();

    JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, controlPanel, canvas);

    setLayout(new BorderLayout());
    add(sp);
}

Класс Rect может создать объект Rect, используемый позже.

public class Rect
{
private int x1, y1, width1, height1;
private Color color1;

public Rect(int x, int y, int width, int height, Color color)
{
    x1 = x;
    y1 = y;
    width1 = width;
    height1 = height;
    color1 = color;
}

public void draw(Graphics page)
{
    page.setColor(color1);
    page.drawRect(x1,y1,width1,height1);
}
}

Класс Canvas создает пространство, которое позволяет рисовать объект.

private class Canvas extends JPanel
{

    public void paintComponent(Graphics page)
    {
        super.paintComponent(page);
        setBackground(Color.white);
        if (pt != null)
        {
            Rect rect = new Rect(xStart, yStart, xEnd-xStart, yEnd-yStart, currentColor);
            rect.draw(page);
        }
    }
}

Класс PointListener находит все точки, которые есть, например, где пользователь щелкает, куда пользователь перетаскивает, а также где пользователь отпускает.

private class PointListener implements MouseListener, MouseMotionListener
{
    public void mousePressed(MouseEvent event)
    {
        pt = event.getPoint();
        xStart = pt.x;
        yStart = pt.y;
    }
    public void mouseReleased(MouseEvent event)
    {
        pt = event.getPoint();
        if (pt != null)
        {
            xEnd = pt.x;
            yEnd = pt.y;
            page.fillRect(xStart, yStart, xEnd-xStart, yEnd-yStart);
        }
    }
    public void mouseClicked(MouseEvent event) {}
    public void mouseEntered(MouseEvent event) {}
    public void mouseExited(MouseEvent event) {}
    public void mouseDragged(MouseEvent event)
    {
        pt = event.getPoint();
        if (pt != null)
        {
            xEnd = pt.x;
            yEnd = pt.y;
            Rect rect = new Rect(xStart, yStart, xEnd-xStart, yEnd-yStart, currentColor);
            rect.draw(page);
        }
        repaint();
    }
    public void mouseMoved(MouseEvent event) {}

}

ColorListener находит тип объекта, который выбран в JComboBox, определенном в методе main(), и устанавливает для него currentColor (он возвращается как цвет в конструкторе Rect выше).

private class ColorListener implements ActionListener
{
    public void actionPerformed(ActionEvent event)
    {
        if (event.getSource().equals("black"))
        {
            currentColor = Color.black;
            comboBox.setSelectedIndex(0);
        }
        else if (event.getSource().equals("red"))
        {
            currentColor = Color.red;
            comboBox.setSelectedIndex(1);
        }
        else if (event.getSource().equals("blue"))
        {
            currentColor = Color.blue;
            comboBox.setSelectedIndex(2);
        }
        else if (event.getSource().equals("green"))
        {
            currentColor = Color.green;
            comboBox.setSelectedIndex(3);
        }
        else if (event.getSource().equals("orange"))
        {
            currentColor = Color.orange;
            comboBox.setSelectedIndex(4);
        }
    }
}

Так что у меня проблемы с тем, чтобы нарисовать его. Я не вижу каких-либо недостатков в логике в программе выше, и ничего нельзя нарисовать на холсте (не беспокойтесь о кнопках JButtons Undo и Erase, так как с ними легко работать с ArrayList и remove() и clear() и тому подобное).


person Community    schedule 20.02.2012    source источник
comment
Это переменная экземпляра, которую я объявил ранее, созданная в конструкторе всего класса, она же WholePanel (я добавлю ее через секунду).   -  person    schedule 20.02.2012


Ответы (1)


В вашей программе не должно быть графического поля, которое является полем класса (поле класса вашей страницы). Я удивлен, что вы не видите NullPointException с тем, как вы пытаетесь использовать его выше, скажем, в своем классе прослушивателя мыши:

public void mouseReleased(MouseEvent event)
{
    pt = event.getPoint();
    if (pt != null)
    {
        xEnd = pt.x;
        yEnd = pt.y;


        // !!!! don't do this !!!!
        page.fillRect(xStart, yStart, xEnd-xStart, yEnd-yStart);
    }
}

Вместо этого объект Graphics должен быть получен только из JVM, должен существовать только в методе paintComponent и должен использоваться только в том же методе paintComponent (за исключением любых методов, вызываемых с помощью paintComponent, которым передается этот объект, и, конечно, полученный объект Graphics из BufferedImage). MouseListener/MouseMotionListener должен заполнить ваши переменные x-start, y-start, x-end и y-end во время mouseDragged, а затем в mouseRelease эти переменные должны использоваться для создания нового объекта Rect, который помещается в rectList, а потом перекрасить называется.

Затем paintComponent должен выполнить итерацию по rectList, заполняя каждый объект Rect, который он там находит.

person Hovercraft Full Of Eels    schedule 20.02.2012
comment
Я все еще не понимаю, почему они все еще не рисуют их ... вы говорите, что mousePressed должен получить точку нажатия и установить координату x на xStart, а координату y на yStart, или должен mouseDragged получить все из 4-х точек (те две и xEnd и yEnd)? - person ; 20.02.2012
comment
Я просто запутался в том, что все еще не так с логикой и прочим - person ; 20.02.2012