【问题标题】:Moving JPasswordField to absolute position将 JPasswordField 移动到绝对位置
【发布时间】:2015-01-15 23:33:40
【问题描述】:

我有这个代码:

import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;

public class DialogExample extends JPanel {
   private static final int COLUMN_COUNT = 10;
   private static final int I_GAP = 3;
   public static final String BKG_IMG_PATH = "http://upload.wikimedia.org/wikipedia/commons/"
         + "thumb/9/92/Camels_in_Jordan_valley_%284568207363%29.jpg/800px-Camels_in_Jordan_valley_"
         + "%284568207363%29.jpg";

   private BufferedImage backgrndImage;
   private JTextField userNameField = new JTextField();
   private JPasswordField passwordField = new JPasswordField();
   private JPanel mainPanel = new JPanel(new GridBagLayout());
   private JButton okButton = new JButton("OK");
   private JButton cancelButton = new JButton("Cancel");

   public DialogExample(BufferedImage backgrndImage) {
      this.backgrndImage = backgrndImage;
      userNameField.setColumns(COLUMN_COUNT);
      passwordField.setColumns(COLUMN_COUNT);

      JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 5));
      btnPanel.setOpaque(false);
      btnPanel.add(okButton);
      btnPanel.add(cancelButton);

      GridBagConstraints gbc = getGbc(0, 0, GridBagConstraints.BOTH);
      mainPanel.add(createLabel("User Name", Color.white), gbc);
      gbc = getGbc(1, 0, GridBagConstraints.HORIZONTAL);
      mainPanel.add(userNameField, gbc);
      gbc = getGbc(0, 1, GridBagConstraints.BOTH);
      mainPanel.add(createLabel("Password:", Color.white), gbc);
      gbc = getGbc(1, 1, GridBagConstraints.HORIZONTAL);
      mainPanel.add(passwordField, gbc);
      gbc = getGbc(0, 2, GridBagConstraints.BOTH, 2, 1);
      mainPanel.add(btnPanel, gbc);

      mainPanel.setOpaque(false);
      add(mainPanel);
   }

   private JLabel createLabel(String text, Color color) {
      JLabel label = new JLabel(text);
      label.setForeground(color);
      return label;
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (backgrndImage != null) {
         g.drawImage(backgrndImage, 0, 0, this);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet() || backgrndImage == null) {
         return super.getPreferredSize();
      }
      int imgW = backgrndImage.getWidth();
      int imgH = backgrndImage.getHeight();
      return new Dimension(imgW, imgH);
   }

   public static GridBagConstraints getGbc(int x, int y, int fill) {
      GridBagConstraints gbc = new GridBagConstraints();
      gbc.gridx = x;
      gbc.gridy = y;
      gbc.gridwidth = 1;
      gbc.gridheight = 1;
      gbc.weightx = 1.0;
      gbc.weighty = 1.0;
      gbc.insets = new Insets(I_GAP, I_GAP, I_GAP, I_GAP);
      gbc.fill = fill;

      return gbc;
   }

   public static GridBagConstraints getGbc(int x, int y, int fill, int width,
         int height) {
      GridBagConstraints gbc = getGbc(x, y, fill);
      gbc.gridwidth = width;
      gbc.gridheight = height;

      return gbc;
   }

   private static void createAndShowGui() throws IOException {
      final JFrame frame = new JFrame("Frame");

      final JDialog dialog = new JDialog(frame, "User Sign-In", ModalityType.APPLICATION_MODAL);
      URL imgUrl = new URL(BKG_IMG_PATH);
      BufferedImage img = ImageIO.read(imgUrl);
      final DialogExample dlgExample = new DialogExample(img);
      dialog.add(dlgExample);
      dialog.pack();

      JPanel mainPanel = new JPanel();
      mainPanel.add(new JButton(new AbstractAction("Please Press Me!") {

         @Override
         public void actionPerformed(ActionEvent e) {
            dialog.setVisible(true);
         }
      }));
      mainPanel.setPreferredSize(new Dimension(800, 650));

      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            try {
               createAndShowGui();
            } catch (IOException e) {
               e.printStackTrace();
            }
         }
      });
   }
}

我可以将 JPasswordField 移动到绝对位置 (X,Y) 吗?我一直在尝试不同的东西,比如 setPosition(int X, int Y) 但没有任何效果。我也尝试过使用布局,但也没有成功。我想在他的右边只有一个 JPasswordField 对象和一个按钮对象。就是这样

谢谢

【问题讨论】:

  • 您可以随机化插入和边框属性
  • 我不敢相信没有简单的方法来设置 JtextField 的位置,对吧?
  • 如果有人给我一个示例,说明如何将 JTextField 放在图像前面的绝对位置,我会给出有效的答案。谢谢各位
  • 问题是,问题比你看到的要多得多。每个平台(和硬件组合)都有可能以不同的方式呈现字体和其他图形元素,从而改变它们需要呈现的空间量,这就是为什么我们有布局管理器和许多 UI 工具包使用它们的原因。只是想将一个组件放置在给定位置还不到 10% 的问题....这就是您得到答案的原因。坦率地说,任何涉及简单地调用setLocationsetBounds 的答案都是错误的。
  • @MadProgrammer 感谢您的诚实回复。我可以获得一个片段代码来知道如何开始处理这个问题吗?即使我使用布局管理器,我也可以从那里开始。谢谢

标签: java swing layout jpasswordfield


【解决方案1】:

首先为密码字段和按钮创建一个面板。接下来,随机化 EmptyBorderInsetsGridBagConstraints 以定义父容器内的不同位置。使用这些随机约束将密码/按钮面板添加到此容器...

public class TestPane extends JPanel {

    public TestPane() {

        Random rnd = new Random();

        JPanel panel = new JPanel();
        JPasswordField pf = new JPasswordField(10);
        JButton btn = new JButton("Login");
        panel.add(pf);
        panel.add(btn);

        panel.setBorder(new EmptyBorder(rnd.nextInt(10), rnd.nextInt(10), rnd.nextInt(10), rnd.nextInt(10)));
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(rnd.nextInt(100), rnd.nextInt(100), rnd.nextInt(100), rnd.nextInt(100));

        add(panel, gbc);

    }

}

另一种选择是编写自己的自定义布局管理器...但如果可以避免,上面的示例要简单得多...

ps-您可以随机化边框或插图,也许使用更大的随机范围并获得相同的效果,我更简单地使用两者来证明这一点;)

更新了布局管理器示例

public class TestPane extends BackgroundImagePane {

    public TestPane() throws IOException {

        super(ImageIO.read(new File("Path/to/your/image")));            

        Random rnd = new Random();

        JPanel panel = new JPanel();
        panel.setOpaque(false);
        JPasswordField pf = new JPasswordField(10);
        JButton btn = new JButton("Login");
        panel.add(pf);
        panel.add(btn);

        setLayout(new RandomLayoutManager());

        Dimension size = getPreferredSize();
        size.width -= panel.getPreferredSize().width;
        size.height -= panel.getPreferredSize().height;

        add(panel, new Point(rnd.nextInt(size.width), rnd.nextInt(size.height)));

    }

}

public class RandomLayoutManager implements LayoutManager2 {

    private Map<Component, Point> mapConstraints;

    public RandomLayoutManager() {
        mapConstraints = new WeakHashMap<>(25);
    }

    @Override
    public void addLayoutComponent(String name, Component comp) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void removeLayoutComponent(Component comp) {
        mapConstraints.remove(comp);
    }

    @Override
    public Dimension preferredLayoutSize(Container parent) {
        Area area = new Area();
        for (Component comp : mapConstraints.keySet()) {

            Point p = mapConstraints.get(comp);
            Rectangle bounds = new Rectangle(p, comp.getPreferredSize());
            area.add(new Area(bounds));

        }

        Rectangle bounds = area.getBounds();
        Dimension size = bounds.getSize();
        size.width += bounds.x;
        size.height += bounds.y;

        return size;

    }

    @Override
    public Dimension minimumLayoutSize(Container parent) {
        return preferredLayoutSize(parent);
    }

    @Override
    public void layoutContainer(Container parent) {
        for (Component comp : mapConstraints.keySet()) {
            Point p = mapConstraints.get(comp);
            comp.setLocation(p);
            comp.setSize(comp.getPreferredSize());
        }
    }

    @Override
    public void addLayoutComponent(Component comp, Object constraints) {
        if (constraints instanceof Point) {

            mapConstraints.put(comp, (Point) constraints);

        } else {

            throw new IllegalArgumentException("cannot add to layout: constraint must be a java.awt.Point");

        }
    }

    @Override
    public Dimension maximumLayoutSize(Container target) {
        return preferredLayoutSize(target);
    }

    @Override
    public float getLayoutAlignmentX(Container target) {
        return 0.5f;
    }

    @Override
    public float getLayoutAlignmentY(Container target) {
        return 0.5f;
    }

    @Override
    public void invalidateLayout(Container target) {
    }

}

public class BackgroundImagePane extends JPanel {

    private Image image;

    public BackgroundImagePane(Image img) {

        this.image = img;

    }

    @Override
    public Dimension getPreferredSize() {
        return image == null ? super.getPreferredSize() : new Dimension(image.getWidth(this), image.getHeight(this));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (image != null) {
            int x = (getWidth() - image.getWidth(this)) / 2;
            int y = (getHeight() - image.getHeight(this)) / 2;
            g.drawImage(image, x, y, this);
        }
    }

}

BackgroundImagePane 基于this example,允许背景图像面板成为字段面板的容器,您应该可以顺利进行...

【讨论】:

  • 对不起,我的意思是绝对位置。所以我希望它位于例如位置(100,200)。谢谢你,再次抱歉,一开始没有说清楚
  • @RyanFold 避免使用null 布局,像素完美的布局是现代用户界面设计中的一种错觉。影响组件单个尺寸的因素太多,您无法控制。 Swing 旨在与核心布局管理器一起工作,丢弃这些将导致无穷无尽的问题和问题,您将花费越来越多的时间来尝试纠正
  • 如果您“真的”想要“绝对”定位,那么您将需要编写自己的布局管理器。例如,如果您将insets 设置为允许100top 位置和200left 位置,您将接近您正在寻找的东西而不会崩溃布局管理 API
  • 你能帮我写一个布局吗?谢谢你,很抱歉打扰你
  • 我之前告诉过他这一切。希望他能把它放在心上。
【解决方案2】:

您可以使用null 布局,但这需要的时间太长,而且它不会随框架重新调整大小。 像这样:

public class TestPane{

public static void main (String[] args) {

    Random rnd = new Random();

    JFrame frame = new JFrame();
    JPasswordField pf = new JPasswordField();
    JButton btn = new JButton("Login");
    frame.setSize(500, 500);
    frame.setLayout(null);
    btn.setBounds(y, x, width, height);
    pf.setBounds(y, x, width, height);
    frame.add(btn);
    frame.add(pf);        
}

}

这应该可行。 如果你想使用空布局。

【讨论】:

  • 避免使用null 布局,像素完美的布局是现代用户界面设计中的一种错觉。影响组件单个尺寸的因素太多,您无法控制。 Swing 旨在与核心布局管理器一起工作,丢弃这些将导致无穷无尽的问题和问题,您将花费越来越多的时间来尝试纠正
  • 我同意@MadProgrammer。这种方式只会导致痛苦。想象一下以这种方式创建一个复杂的 GUI,然后决定您需要将一个新的 JRadioButton 添加到中间的一组它们中。如果您使用空布局,则必须手动调整 GUI 中的 每个 组件以创建增强功能,然后调试此调整导致的所有问题。如果你使用布局管理器,你有时可以用一两行代码来做到这一点,而且出错的风险非常低。只是不推荐这个。说真的。
  • +1 因为这个答案突出显示了null 布局管理器,它启用了绝对定位(OP 所要求的),这正是我对 OP 问题的预期答案。
猜你喜欢
  • 1970-01-01
  • 2016-02-04
  • 1970-01-01
  • 1970-01-01
  • 2014-02-28
  • 2018-07-25
  • 2018-03-20
  • 2013-07-13
  • 1970-01-01
相关资源
最近更新 更多