4

I am creating a costume component in Model UIDelegate using DrawPad example. However, for some reason I get the error UIDefaults.getUI() failed: no ComponentUI class. I am not even sure if I am implementing Model UIDelegate properly. But why am I getting that error?

Main

public class Main {
    static JFrame frame;
    static JButton clearButton;
    static DrawPad drawPad;

    public static void main(String[] args) {
        UIManager.put("DrawPadUI", "BasicDrawPadUI");
        frame = new JFrame();
        drawPad = new DrawPad();
        clearButton = new JButton("Clear");
        frame.add(drawPad, BorderLayout.CENTER);

        clearButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
                Graphics g = frame.getGraphics();
                g.setColor(Color.white);
                g.fillRect(0, 0, frame.getWidth(), frame.getHeight());

            }
        });
        frame.add(clearButton, BorderLayout.SOUTH);
        frame.setSize(280, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

BasicDrawPadUI

public class BasicDrawPadUI extends ComponentUI implements MouseListener, MouseMotionListener {
    Image image;
    Graphics2D graphics2D;
    int currentX, currentY, oldX, oldY;

    JFrame frame;
    JButton clearButton;

    public static ComponentUI createUI(JComponent c) {
        return new BasicDrawPadUI();
    }

    public void paintComponent(Graphics g, JComponent c) {
        if (image == null) {
            image = c.createImage(c.getWidth(), c.getHeight());
            graphics2D = (Graphics2D) image.getGraphics();
            graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
            clear(c);
        }
        g.drawImage(image, 0, 0, null);
      }

    @Override
    public void mouseDragged(MouseEvent e) {
        // TODO Auto-generated method stub
        currentX = e.getX();
        currentY = e.getY();
        if (graphics2D != null)
            graphics2D.drawLine(oldX, oldY, currentX, currentY);
        //repaint();
        oldX = currentX;
        oldY = currentY;
    }

    public void clear(JComponent c) {
        graphics2D.setPaint(Color.white);
        graphics2D.fillRect(0, 0, c.getWidth(), c.getHeight());
        graphics2D.setPaint(Color.black);
        c.repaint();
    }


    @Override
    public void mouseMoved(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseClicked(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mousePressed(MouseEvent e) {
        // TODO Auto-generated method stub
        oldX = e.getX();
        oldY = e.getY();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub

    }

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

    }

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

    }
}

DrawPad

class DrawPad extends JComponent {

    private final static String ID = "DrawPadUI";

    public DrawPad() {
        updateUI();
    }

    public void updateUI() {
        setUI(UIManager.getUI(this));
    }

    @Override
    public String getUIClassID() {
        return ID;
    }
}
Victor Luna
  • 1,746
  • 2
  • 17
  • 36

1 Answers1

5

Change UIManager.put("DrawPadUI", "BasicDrawPadUI"); to UIManager.put("DrawPadUI", "drawpad.BasicDrawPadUI");

You need to specify the full qualified class name of the UI class, including the package name

I'll need to have a look to be sure, but when it calls createUI, you could grab a reference to the component

Override the installUI method from ComponentUI and when it's called, maintain a reference to the component that is passed to you.

private DrawPad drawPad;
//...
@Override
public void installUI(JComponent c) {
    drawPad = (DrawPad) c;
    // Install required listeners and other functionality
}

Equally, in uninstallUI, you should dereference any strong references you have and uninstall your listeners

@Override
public void uninstallUI(JComponent c) {
    // Uninstall any listeners
    drawPad = null;
}

Have a look at custom java Swing component Model, UIDelegate, component format for a complete implementation.

Also, you should NEVER maintain a reference to a Graphics2D context that you did not create yourself

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • that worked thanks. One more question if possible. When I try to access repaint() from mousedragged in BasocDrawPadUI I cannot. Why is that? I think I have to use JConponent like I did with the method clear() but how can I do that? – Victor Luna Oct 30 '15 at 01:53
  • I'll need to have a look to be sure, but when it calls createUI, you could grab a reference to the component – MadProgrammer Oct 30 '15 at 01:57
  • I apologize if this is a stupid question, but what do you mean "grab a reference to the component"? – Victor Luna Oct 30 '15 at 02:23
  • Thanks a lot, I appreciate your help! :) – Victor Luna Oct 30 '15 at 03:16