当前位置: 首页 > 面试题库 >

自定义Java Swing组件模型,UIDelegate,组件格式

燕翼
2023-03-14
问题内容

我被赋予创建自定义摆幅组件的任务。我的组件在包含JSlider的测试应用程序中正常运行,该应用程序用于放大和缩小Image。但是,我需要以Model,UIDelegate和Component类格式显示自定义组件,而我完全迷失了如何转换代码以使其遵循这种格式。这是我的测试应用程序的代码。

package test;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.*;

import java.io.File;
import java.net.URL;

import javax.imageio.ImageIO;

public class ZoomDemo extends JComponent implements ChangeListener {

JPanel gui;
/**
 * Displays the image.
 */
JLabel imageCanvas;
Dimension size;
double scale = 1.0;
private BufferedImage image;

public ZoomDemo() {
    size = new Dimension(10, 10);
    setBackground(Color.black);
    try {
         image = ImageIO.read(new File("car.jpg"));
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

public void setImage(Image image) {
    imageCanvas.setIcon(new ImageIcon(image));
}

public void initComponents() {
    if (gui == null) {
        gui = new JPanel(new BorderLayout());
        gui.setBorder(new EmptyBorder(5, 5, 5, 5));
        imageCanvas = new JLabel();
        JPanel imageCenter = new JPanel(new GridBagLayout());
        imageCenter.add(imageCanvas);
        JScrollPane imageScroll = new JScrollPane(imageCenter);
        imageScroll.setPreferredSize(new Dimension(300, 100));
        gui.add(imageScroll, BorderLayout.CENTER);
    }
}

public Container getGui() {
    initComponents();
    return gui;
}

public void stateChanged(ChangeEvent e) {
    int value = ((JSlider) e.getSource()).getValue();
    scale = value / 100.0;
    paintImage();
}

protected void paintImage() {

    int imageWidth = image.getWidth();
    int imageHeight = image.getHeight();
    BufferedImage bi = new BufferedImage(
            (int)(imageWidth*scale), 
            (int)(imageHeight*scale), 
            image.getType());
    Graphics2D g2 = bi.createGraphics();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
    AffineTransform at = AffineTransform.getTranslateInstance(0, 0);
    at.scale(scale, scale);
    g2.drawRenderedImage(image, at);
    setImage(bi);
}

public Dimension getPreferredSize() {
    int w = (int) (scale * size.width);
    int h = (int) (scale * size.height);
    return new Dimension(w, h);
}

private JSlider getControl() {
    JSlider slider = new JSlider(JSlider.HORIZONTAL, 1, 500, 50);
    slider.setMajorTickSpacing(50);
    slider.setMinorTickSpacing(25);
    slider.setPaintTicks(true);
    slider.setPaintLabels(true);
    slider.addChangeListener(this);
    return slider;
}

public static void main(String[] args) {
    ZoomDemo app = new ZoomDemo();
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(app.getGui());
    app.setImage(app.image);

    // frame.getContentPane().add(new JScrollPane(app));  
    frame.getContentPane().add(app.getControl(), "Last");
    frame.setSize(700, 500);
    frame.setLocation(200, 200);
    frame.setVisible(true);
}
}

以下代码是我需要遵循的类格式

组件类别

package component;

import javax.swing.JComponent;

import javax.swing.JSlider;
import javax.swing.plaf.ComponentUI;

public class ProgressBar extends JComponent {

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

public void installUI(JComponent c){



}

public void uninstallUI (JComponent c){

}
}

型号CLass

public class ZoomModel extends JSLider  {



}

UIDelegate类

public class ZoomUI extends ComponentUI implements ChangeListener{

}

我将以这种格式实现自定义组件的任何帮助将不胜感激。我是Swing的新手,我在自定义组件上发现的文档非常混乱,几乎没有帮助。

测试应用

package test;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.*;

import java.io.File;
import java.net.URL;

import javax.imageio.ImageIO;

import component.ZoomComponent;

public class ZoomDemo  extends JPanel implements PropertyChangeListener, ActionListener {

ZoomComponent zoomer;
JPanel board;
private BufferedImage image;

public ZoomDemo( ) {
    super(true);  
    setLayout(new BorderLayout( )); 
    board = new JPanel(true); 
    board.setPreferredSize(new Dimension(300, 300)); 
    board.setBorder(new LineBorder(Color.black, 5));

    zoomer = new ZoomComponent();
    add(board, BorderLayout.NORTH);
    add(zoomer, BorderLayout.SOUTH);



}


@Override
public void actionPerformed(ActionEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void propertyChange(PropertyChangeEvent arg0) {
    // TODO Auto-generated method stub

}

public static void main(String[] args) {

    UIManager.getDefaults().put("ZoomComponentUI", "component.BasicZoomUI");
    ZoomDemo s= new ZoomDemo();
    JFrame frame = new JFrame("Sample Sketch Application"); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setContentPane(s); 
    frame.pack( ); 
    frame.setVisible(true);
}

}


问题答案:

好的,那是对我不使用的API部分的一次有趣的冒险:首先,通读如何编写自定义Swing组件及其相关链接,这将为您提供基础知识,以了解什么是即将发生…

介面

就个人而言,我总是从界面开始,界面使生活变得更好,并且它为您提供了更大的灵活性。现在,您应该从哪个模型扩展(根据您的要求)…?

好吧,我能找到的最佳选择是BoundedRangeModel,它也被JSlider
使用…实际上,这意味着我不仅可以将此模型传递给视图,而且还可以传递给,而JSlider无需任何额外的工作,就可以让滑块更改图像!! 双赢

import java.awt.Dimension;
import java.awt.Image;
import javax.swing.BoundedRangeModel;

public interface ZoomModel extends BoundedRangeModel {

    public Image getImage();

    public Dimension getScaledSize();

}

摘要

接下来,我想制作一个抽象版本,这是我放置“通用”功能的地方,对于大多数实现来说,它可能是相同的,在这种情况下,可能不需要,但是我有点像这样。 。

import java.awt.Dimension;
import java.awt.Image;
import javax.swing.DefaultBoundedRangeModel;

public abstract class AbstractZoomModel extends DefaultBoundedRangeModel implements ZoomModel {

    public AbstractZoomModel() {
        super(100, 0, 0, 200);
    }

    @Override
    public Dimension getScaledSize() {
        Dimension size = new Dimension(0, 0);
        Image image = getImage();
        if (image != null) {
            double scale = getValue() / 100d;
            size.width = (int) Math.round(image.getWidth(null) * scale);
            size.height = (int) Math.round(image.getHeight(null) * scale);

        }
        return size;
    }

}

因此,您可以在这里看到,我定义了一些基本属性,初始缩放级别为100,最大级别为200,最小级别为0,此外,我还实现了getScaledSize,使用了一点,使生活更轻松…

默认…

现在,因为我们喜欢,所以我们提供了该模型的“默认”实现。这是非常基本的,因为它所做的全部工作都是引用图像…

import java.awt.Image;

public class DefaultZoomModel extends AbstractZoomModel {
    Image image;

    public DefaultZoomModel(Image image) {
        this.image = image;
    }

    @Override
    public Image getImage() {
        return image;
    }

}

您可以创建从URL例如下载图像的实现…

风景

好的,这是实际的组件本身,已添加到您的UI中。它包含构造和准备UI委托以及管理模型所需的基本功能。这里感兴趣的关键是使用属性更改支持来提供对模型更改的通知,这很重要,如您所见…

import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JComponent;
import javax.swing.UIManager;

public class ZoomComponent extends JComponent {

    private static final String uiClassID = "ZoomComponentUI";
    private ZoomModel model;

    public ZoomComponent() {
        setBackground(Color.black);
        setFocusable(true);
        updateUI();
    }

    public void setModel(ZoomModel newModel) {
        if (model != newModel) {
            ZoomModel old = model;
            this.model = newModel;
            firePropertyChange("model", old, newModel);
        }
    }

    public ZoomModel getModel() {
        return model;
    }

    @Override
    public Dimension getPreferredSize() {
        ZoomModel model = getModel();
        Dimension size = new Dimension(100, 100);
        if (model != null) {
            size = model.getScaledSize();
        }
        return size;
    }

    public void setUI(BasicZoomUI ui) {
        super.setUI(ui);
    }

    @Override
    public void updateUI() {
        if (UIManager.get(getUIClassID()) != null) {
            ZoomUI ui = (ZoomUI) UIManager.getUI(this);
            setUI(ui);
        } else {
            setUI(new BasicZoomUI());
        }
    }

    public BasicZoomUI getUI() {
        return (BasicZoomUI) ui;
    }

    @Override
    public String getUIClassID() {
        return uiClassID;
    }
}

UI委托

现在还有其他有趣的东西…如果遵循标准约定,通常您会提供abstractUI委托的概念,例如…

import javax.swing.plaf.ComponentUI;

public abstract class ZoomUI extends ComponentUI {       
}

由此,其他代表将会增长。

基本UI委托

常规通常会建议您提供一个“基本”实施,完成许多繁重的工作,但允许其他实施有机会跳到那里进行更改

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;

public class BasicZoomUI extends ZoomUI {

    private ZoomComponent zoomComponent;
    private MouseAdapter mouseHandler;
    private ChangeListener changeHandler;

    private Action zoomIn;
    private Action zoomOut;
    private PropertyChangeListener propertyChangeHandler;

    protected ChangeListener getChangeHandler() {
        if (changeHandler == null) {
            changeHandler = new ChangeHandler();
        }
        return changeHandler;
    }

    protected void installMouseListener() {
        mouseHandler = new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                zoomComponent.requestFocusInWindow();
            }

            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                int amount = e.getWheelRotation();
                ZoomModel model = zoomComponent.getModel();
                if (model != null) {

                    int value = model.getValue();
                    model.setValue(value + amount);

                }
            }

        };
        zoomComponent.addMouseListener(mouseHandler);
        zoomComponent.addMouseWheelListener(mouseHandler);

    }

    protected void installModelPropertyChangeListener() {

        propertyChangeHandler = new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                ZoomModel old = (ZoomModel) evt.getOldValue();
                if (old != null) {
                    old.removeChangeListener(getChangeHandler());
                }
                ZoomModel newValue = (ZoomModel) evt.getNewValue();
                if (newValue != null) {
                    newValue.addChangeListener(getChangeHandler());
                }
            }
        };

        zoomComponent.addPropertyChangeListener("model", propertyChangeHandler);

    }

    protected void installKeyBindings() {

        zoomIn = new ZoomInAction();
        zoomOut = new ZoomOutAction();

        InputMap inputMap = zoomComponent.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "zoomIn");
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), "zoomOut");
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0), "zoomIn");
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "zoomOut");

        ActionMap actionMap = zoomComponent.getActionMap();
        actionMap.put("zoomIn", zoomIn);
        actionMap.put("zoomOut", zoomOut);
    }

    protected void installModelChangeListener() {

        ZoomModel model = getModel();
        if (model != null) {
            model.addChangeListener(getChangeHandler());
        }

    }

    @Override
    public void installUI(JComponent c) {

        zoomComponent = (ZoomComponent) c;

        installMouseListener();
        installModelPropertyChangeListener();
        installKeyBindings();
        installModelChangeListener();

    }

    protected void uninstallModelChangeListener() {

        getModel().removeChangeListener(getChangeHandler());

    }

    protected void uninstallKeyBindings() {

        InputMap inputMap = zoomComponent.getInputMap(JComponent.WHEN_FOCUSED);
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "donothing");
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), "donothing");
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0), "donothing");
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "donothing");

        AbstractAction blank = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
            }
        };

        ActionMap actionMap = zoomComponent.getActionMap();
        actionMap.put("zoomIn", blank);
        actionMap.put("zoomOut", blank);

    }

    protected void uninstallModelPropertyChangeListener() {

        zoomComponent.removePropertyChangeListener(propertyChangeHandler);
        propertyChangeHandler = null;

    }

    protected void uninstallMouseListener() {

        zoomComponent.removeMouseWheelListener(mouseHandler);
        mouseHandler = null;

    }

    @Override
    public void uninstallUI(JComponent c) {

        uninstallModelChangeListener();
        uninstallModelPropertyChangeListener();
        uninstallKeyBindings();
        uninstallMouseListener();

        mouseHandler = null;
        zoomComponent = null;

    }

    @Override
    public void paint(Graphics g, JComponent c) {
        super.paint(g, c);
        paintImage(g);
    }

    protected void paintImage(Graphics g) {
        if (zoomComponent != null) {
            ZoomModel model = zoomComponent.getModel();
            Image image = model.getImage();
            Dimension size = model.getScaledSize();
            int x = (zoomComponent.getWidth() - size.width) / 2;
            int y = (zoomComponent.getHeight() - size.height) / 2;
            g.drawImage(image, x, y, size.width, size.height, zoomComponent);
        }
    }

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

    protected ZoomModel getModel() {

        return zoomComponent == null ? null : zoomComponent.getModel();

    }

    protected class ChangeHandler implements ChangeListener {

        @Override
        public void stateChanged(ChangeEvent e) {
            zoomComponent.revalidate();
            zoomComponent.repaint();
        }

    }

    protected class ZoomAction extends AbstractAction {

        private int delta;

        public ZoomAction(int delta) {
            this.delta = delta;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            ZoomModel model = getModel();
            if (model != null) {
                model.setValue(model.getValue() + delta);
            }
        }

    }

    protected class ZoomOutAction extends ZoomAction {

        public ZoomOutAction() {
            super(-5);
        }

    }

    protected class ZoomInAction extends ZoomAction {

        public ZoomInAction() {
            super(5);
        }

    }

}

From here you could go and devise platform specific implementations, but I’ve
decided to stick with the basic delegate…

Putting it all together

If that wasn’t enough, before you can use any of it, you must install the
delegate…

UIManager.getDefaults().put("ZoomComponentUI", "your.awesome.package.name.BasicZoomUI");

nb: Change your.awesome.package.name to reflect your actual package name…

Runnable Example

 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.EventQueue;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.io.File;
 import java.io.IOException;
 import javax.imageio.ImageIO;
 import javax.swing.JFrame;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JSlider;
 import javax.swing.UIManager;
 import javax.swing.UnsupportedLookAndFeelException;

 public class TestZoom100 {

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

      public TestZoom100() {
           EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                     try {
                          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                     } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                          ex.printStackTrace();
                     }

                     UIManager.getDefaults().put("ZoomComponentUI", "your.awesome.package.name.BasicZoomUI");

                     try {
                          DefaultZoomModel model = new DefaultZoomModel(ImageIO.read(new File("/your/awesome/image.jpg")));
                          model.setValue(50);
                          ZoomComponent zoomComp = new ZoomComponent();
                          zoomComp.setModel(model);

                          JSlider slider = new JSlider(model);

                          JFrame frame = new JFrame("Testing");
                          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                          frame.add(new JScrollPane(zoomComp));
                          frame.add(slider, BorderLayout.SOUTH);
                          frame.pack();
                          frame.setLocationRelativeTo(null);
                          frame.setVisible(true);
                     } catch (IOException exp) {
                          exp.printStackTrace();
                     }
                }
           });
      }

 }

Don’t forget to change the package name for the BasicZoomUI to the package
name you have it stored in and actually specify a image file ;)



 类似资料:
  • Mpx中的自定义组件完全基于小程序原生的自定义组件支持,与此同时,Mpx提供的数据响应和模板增强等一系列增强能力都能在自定义组件中使用。 原生自定义组件的规范详情查看这里 动态组件 Mpx中提供了使用方法类似于 Vue 的动态组件能力,这是一个基于 wx:if 实现的语法。通过对 is 属性进行动态绑定,可以实现在同一个挂载点切换多个组件,前提需要动态切换的组件已经在全局或者组件中完成注册。 使用

  • PyQt5有丰富的组件,但是肯定满足不了所有开发者的所有需求,PyQt5只提供了基本的组件,像按钮,文本,滑块等。如果你还需要其他的模块,应该尝试自己去自定义一些。 自定义组件使用绘画工具创建,有两个基本方式:根据已有的创建或改进;通过自己绘图创建。 Burning widget 这个组件我们会在Nero,K3B,或者其他CD/DVD烧录软件中见到。 #!/usr/bin/python3 # -*

  • 1. Component 创建自定义组件,接受一个 Object 类型的参数。 定义段 类型 是否必填 描述 最低版本 properties Object Map 否 组件的对外属性,是属性名到属性设置的映射表 data Object 否 组件的内部数据,和 properties 一同用于组件的模板渲染 observers Object 否 组件数据字段监听器,用于监听 properties 和

  • 1. 组件模板和样式 类似于页面,自定义组件拥有自己的 FXML 模板和 FTSS 样式。 1.1 组件模板 组件模板的写法与页面模板相同。组件模板与组件数据结合后生成的节点树,将被插入到组件的引用位置上。 在组件模板中可以提供一个 <slot> 节点,用于承载组件引用时提供的子节点。​ 代码示例 <!-- 组件模板 --> <view class="wrapper"> <view>这里是组件

  • 自定义组件 开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。自定义组件在使用时与基础组件非常相似。 创建自定义组件 一个自定义组件由 json jxml jxss js 4个文件组成。要编写一个自定义组件,首先需要在 json 文件中进行自定义组件声明(将 component 字段设为 true 可这一组文件设为自

  • 英文原文:http://emberjs.com/guides/components/customizing-a-components-element/ 默认情况下,每个组件是一个<div>元素。如果使用开发工具查看渲染后的组件,将看到一个如下所示的DOM表示: 1 2 3 <div id="ember180" class="ember-view"> <h1>My Component</h1>