JMenuItem запускается только при вводе с клавиатуры, а не при нажатии

Я сделал простую программу для рисования на Java, используя JFrame (мой первый раз с таким). Пользователь и щелкает и перетаскивает, чтобы рисовать фигуры, но это не важно. У меня есть JMenuBar с кучей опций, таких как тип фигуры, «Создать» и «Выйти». Когда пользователь нажимает кнопку new, он должен очистить экран. Когда пользователь нажимает Ctrl+N, все работает отлично. Однако, когда кнопка нажата, она вообще не работает.

Я поместил отладочный System.out.println внутри actionEvent для newItem, и он отлично распечатывается при нажатии на элемент, но на самом деле он не стирает экран. Любая идея, что может вызвать это?

Я вырезал большую часть программы и оставил столько, сколько нужно, чтобы увидеть проблему. Вы по-прежнему можете нажать и перетащить, чтобы нарисовать фигуру (форма не появится, пока вы не отпустите кнопку мыши), и нажать Ctrl+N, чтобы очистить экран, но нажатие кнопки «Создать» этого не сделает.

import java.awt.*;
import java.awt.event.*;
import java.lang.*;
import javax.swing.*;

public class E3G04 extends JFrame implements WindowListener, ActionListener, MouseListener, MouseMotionListener
{
    //Variables are declared as volatile to ensure that they're always called from system RAM
    static volatile String type = "rectangle";
    static volatile Boolean fill = true;
    static Color lineColor = Color.BLACK;
    static Color fillColor = Color.RED;
    static int size = 1;

    CanvasEX cx = new CanvasEX();

    static boolean running = true;

    JMenuBar mb = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
            JMenuItem newItem = new JMenuItem("New");
            JMenuItem quitItem = new JMenuItem ("Quit");


    protected E3G04()
    {

        mb.add(fileMenu);
        fileMenu.add(newItem);
        fileMenu.add(quitItem);             
        newItem.setMnemonic('N');
        quitItem.setMnemonic('Q');
        newItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
        quitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));          
        newItem.addActionListener(this);
        quitItem.addActionListener(this);
        cx.setSize(800,600);
        cx.addMouseListener(this);
        cx.addMouseMotionListener(this);
        setJMenuBar(mb);
        setBounds(100,100,800,600);
        setLayout(new BorderLayout());
        add("Center",cx);
        addWindowListener(this);
        setResizable(true);
        setVisible(true);
    }

    public static void main(String [] args)
    {
        new E3G04();
    }

    public void stop()
    {
        newItem.removeActionListener(this);
        quitItem.removeActionListener(this);    
        dispose();
        System.exit(0);
    }

    public void actionPerformed(ActionEvent e)
    {
        Object o = e.getSource();

        if (o == newItem)
        {
            cx.erase = true;
            cx.repaint();
        }

        if (o == quitItem)
        {   
            running = false;
            stop();
        }

    }      

    public void mousePressed(MouseEvent m)
    {
        cx.start = m.getPoint();
        cx.end = cx.start;
        cx.cur = cx.start;
    }

    public void mouseDragged(MouseEvent m)
    {
        cx.cur = m.getPoint();
    }   

    public void mouseReleased(MouseEvent m)
    {
        cx.end = cx.cur;
        cx.repaint();
    }   
    public void itemStateChanged(ItemEvent e)
    {
        Object o = e.getSource();

    }
    public void windowClosing(WindowEvent e)
    {
        running = false;
        stop();
    }
    public void mouseClicked(MouseEvent m){}    
    public void mouseExited(MouseEvent m){}
    public void mouseEntered(MouseEvent m){}    
    public void mouseMoved(MouseEvent m){}
    public void windowClosed(WindowEvent e){}
    public void windowOpened(WindowEvent e){}
    public void windowActivated(WindowEvent e){}
    public void windowDeactivated(WindowEvent e){}
    public void windowIconified(WindowEvent e){}
    public void windowDeiconified(WindowEvent e){}
}


class CanvasEX extends Canvas
{
    Point start = new Point(100,100);
    Point cur = new Point(100,100);
    Point end = new Point(100,100);
    Image offscreen;
    boolean erase = false;

    public void update(Graphics g)
    {
        //This is adds the new stuff to the screen or erases the screen if erase is true
        Graphics buffer;
        if (offscreen == null)
        {
            offscreen = createImage(getWidth(), getHeight());
        }
        buffer = offscreen.getGraphics();
        if (erase)
        {
            buffer.setColor(getBackground());
            buffer.fillRect(0,0,800, 600);
            buffer.dispose();
            erase = false;
        }
        paint(buffer);
        g.drawImage(offscreen, 0, 0, this);
    }   

    public void paint(Graphics g)
    {
        Graphics buffer = g;
        if (erase)
        {
            g.dispose();
            erase = false;
        }   
        g.setColor(E3G04.lineColor);
        if (end.x > start.x && end.y > start.y)
            g.fillRect(start.x,start.y, Math.abs(end.x-start.x),Math.abs(end.y-start.y));
        if (end.x > start.x && end.y < start.y)
            g.fillRect(start.x,end.y, Math.abs(end.x-start.x),Math.abs(end.y-start.y));  
        if (end.x < start.x && end.y > start.y)
            g.fillRect(end.x, start.y, Math.abs(end.x-start.x),Math.abs(end.y-start.y));
        if (end.x < start.x && end.y < start.y)
            g.fillRect(end.x, end.y, Math.abs(end.x-start.x),Math.abs(end.y-start.y));
        g.setColor(E3G04.fillColor);
        if (end.x > start.x && end.y > start.y)
            g.fillRect(start.x + E3G04.size,start.y + E3G04.size, Math.abs(end.x-start.x) - 2 * E3G04.size,Math.abs(end.y-start.y) - 2 * E3G04.size);
        if (end.x > start.x && end.y < start.y)
            g.fillRect(start.x + E3G04.size,end.y + E3G04.size, Math.abs(end.x-start.x) - 2 * E3G04.size,Math.abs(end.y-start.y) - 2 * E3G04.size);  
        if (end.x < start.x && end.y > start.y)
            g.fillRect(end.x + E3G04.size, start.y + E3G04.size, Math.abs(end.x-start.x) - 2 * E3G04.size,Math.abs(end.y-start.y) - 2 * E3G04.size);
        if (end.x < start.x && end.y < start.y)
            g.fillRect(end.x + E3G04.size, end.y + E3G04.size, Math.abs(end.x-start.x) - 2 * E3G04.size,Math.abs(end.y-start.y) - 2 * E3G04.size);          
    }
}

person Alex Kibler    schedule 10.12.2012    source источник
comment
Вы слышали о массивах и циклах? Вы можете значительно сократить код, если используете их.   -  person Nikolay Kuznetsov    schedule 10.12.2012
comment
Конечно, у меня есть. Почему вы спрашиваете?   -  person Alex Kibler    schedule 10.12.2012
comment
Или этот код генерируется какой-то программой?   -  person Nikolay Kuznetsov    schedule 10.12.2012
comment
Почему вы используете ItemListener для пунктов меню, почему бы не использовать ActionListener для всех??   -  person MadProgrammer    schedule 10.12.2012
comment
О, точно, я могу сделать это сейчас. Раньше я использовал AWT и обычный MenuBar вместо JMenuBar, поэтому я использовал CheckboxMenuItems. Я на самом деле изменить это очень быстро. А это связано с моей проблемой? Поскольку NewItem использует ActionListener   -  person Alex Kibler    schedule 10.12.2012
comment
Заменены все элементы ItemListener на ActionListener.   -  person Alex Kibler    schedule 10.12.2012
comment
Вот вся программа, потому что я не знаю, в чем проблема изолирована. Конечно, вы всегда можете попытаться ее разобрать. Либо проблема исчезает, и тогда вы знаете, в какой части кода она находится, либо вы получаете SSCCE, который иллюстрирует вашу проблему. Оба подхода предпочтительнее, чем просить нас сделать эту работу за вас.   -  person Robin    schedule 10.12.2012
comment
Да, ты прав, это было очень лениво с моей стороны. Я извиняюсь. Я вырезал около 500 строк кода и обновил ОП. Сейчас программа голая, но проблема осталась   -  person Alex Kibler    schedule 10.12.2012
comment
Если вы отказались от советов профессионалов по использованию AWT, измените class CanvasEX extends Canvas на class CanvasEX extends JPanel и public void paint(Graphics g) {.. на public void paintComponent(Graphics g) { super.paintComponent(g);...   -  person Andrew Thompson    schedule 10.12.2012
comment
@AndrewThompson Это фактически решило проблему. Я заменил первые две вещи (на самом деле у меня нет super.paint(g); нигде, что странно, потому что я думал, что у меня есть. Во всяком случае, теперь странно то, что как только я что-то рисую, оно рисует дубликат JMenubar на экране прямо под JMenuBar   -  person Alex Kibler    schedule 10.12.2012
comment
Я восстановил свой «комментарий, обновленный до ответа», так как он казался неуместным, но я проверил изменения здесь и заметил улучшение, поэтому (пожимает плечами) я оставлю его как ответ.   -  person Andrew Thompson    schedule 10.12.2012
comment
И когда я применил этот материал к своей программе, которая в основном работала (за исключением нажатия «Создать»), при запуске JFrame был достаточно большим, чтобы соответствовать строке меню, и больше ничего.   -  person Alex Kibler    schedule 10.12.2012


Ответы (1)


Если вы отказались от совета профессионалов использовать AWT, измените

class CanvasEX extends Canvas

..to..

class CanvasEX extends JPanel

&

public void paint(Graphics g)
{
    .. 

to

public void paintComponent(Graphics g)
{ 
  super.paintComponent(g);
  ..

Затем вам нужно будет понять, как заставить рисунки сохраняться.

person Andrew Thompson    schedule 10.12.2012
comment
Спасибо за помощь. Как я уже сказал в комментариях выше, это заставило кнопку «Создать» работать, но теперь окно не имеет своего нормального размера, хотя у меня объект CanvasEX установлен на 800x600, а границы JFrame также установлены на 800x600. И, да, есть проблема сохранения рисунков. Я даже не знаю, с чего начать, так как я впервые работаю со Swing. - person Alex Kibler; 10.12.2012
comment
Речь идет о нестандартной окраске компонента или просто нестандартной окраске? Я бы предпочел сделать последнее в BufferedImage, как показано здесь. - person Andrew Thompson; 10.12.2012
comment
Это просто о заказной живописи в целом. Я думал, что то, что я делаю, в любом случае было буферизованным изображением. Весь мой метод обновления в CanvasEX заключается в буферизации изображения. Еще раз спасибо за помощь. Мне пора ложиться спать (так как сейчас 3:10 утра), но я проверю ваш урок, когда проснусь. Это выглядит довольно мило. - person Alex Kibler; 10.12.2012