【问题标题】:Changing a shape and a colour after a click (GUI, Java)单击后更改形状和颜色(GUI、Java)
【发布时间】:2021-10-28 15:50:14
【问题描述】:

我只是在学习 GUI 的工作原理,我想编写一个代码,其中会发生以下情况:

  • 首先我们看到红色矩形
  • 点击后会变成一个渐变的圆圈(我选择了橙色和粉色)+ 背景为黑色。

问题是,我使用repaint()时不知道如何通知更改,我尝试用另一种方法创建第一张图片 - 失败,也许我缺乏一些知识。目前我们只得到第二个在点击后不会改变的输出。

这是我卡住的那一刻的代码:

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

public class SimpleGUI implements ActionListener {
    
    JButton button; 
    JFrame frame;
    
    public void work() {
    frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
    button = new JButton("Color change");
    button.addActionListener(this);
    
    mojpanel panel = new mojpanel();
        
    frame.getContentPane().add(BorderLayout.SOUTH, button);
    frame.getContentPane().add(BorderLayout.CENTER, panel);
        
    frame.setSize(300,300);
    frame.setVisible(true);
    }
    
    public void actionPerformed(ActionEvent event) {
        frame.repaint();
    }   
    }

import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import javax.swing.*;
import java.awt.Graphics2D;

public class mojpanel extends JPanel  {
            
public void paintComponent(Graphics g) {
        
g.setColor(Color.black);
    
g.fillRect(0, 0, this.getWidth(), this.getHeight());

GradientPaint gradient = new GradientPaint(70,70, Color.orange, 150,150, Color.pink);

((Graphics2D) g).setPaint(gradient);    

g.fillOval(100, 100, 100, 100);
}                           
}

import javax.swing.JFrame;

public class Test {

        public static void main(String[] args) {
            
            SimpleGUI aplGUI = new SimpleGUI();
            JFrame frame = new JFrame();
            mojpanel panel = new mojpanel();
            frame.add(panel);
            aplGUI.work();          
    }
}

import java.awt.*;

public class Painting extends SimpleGUI {

     public void paint(Graphics g) {
         g.setColor(Color.red);
         g.drawRect(100, 100, 100, 100);
         g.fillRect(100, 100, 100, 100);
      }
}

【问题讨论】:

  • GUI 不是“初学者主题”,自定义绘画也不是。通过更改相关(颜色)属性的范围并定义设置这些属性的方法,对于任何持有对类实例的引用的类,这个问题可能会得到解决。对于准备制作 GUI 的人来说,这应该是有意义的。如果没有,请返回并学习基础知识。 编辑:顺便说一句,Painting 类似乎从未被使用过。
  • 不需要两个JFrame 实例(一个在Test 中,一个在SimpleGUI 中)。一步一步来:学习如何使用JButtonJPanel 制作JFrame。稍后学习如何在这个JPanel上进行自定义绘画。
  • 请修剪您的代码,以便更容易找到您的问题。请按照以下指南创建minimal reproducible example

标签: java swing graphics awt java-2d


【解决方案1】:

当您创建新课程时,您会在他们身上投入更多的精力。您有两个应该可以互换的类,一个绘制红色矩形,另一个绘制带有颜色渐变的圆形,并且能够从前者切换到后者。

因此,当您有一个类扩展 JPanel 和另一个扩展 SimpleGUI 时,没有办法将一个替换为另一个。此外,mojpanelPainting 的名称并不反映它们的用途。

除此之外,你还有它倒退。不要执行调用 repaint() 的操作,然后尝试识别已调用 repaint(),然后修改 GUI。相反,更改 GUI 的状态,在 GUI 以需要更新视觉外观的方式发生更改后,调用 repaint。请注意,当您更改 Swing 组件的大多数属性时,它们会自动触发相应的重绘。

您可以创建两个扩展 JComponent 的类,具有自定义的 paintComponent 方法,并在触发操作时将一个替换为另一个。但是有一种不那么侵入性的方式。让类实现Icon 并设置组件的图标属性,例如JLabel。这是自动触发绘画的属性之一:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class SimpleGUI {
  static class GradientOval implements Icon {
    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
      GradientPaint gradient
          = new GradientPaint(70,70, Color.orange, 150,150, Color.pink);
      ((Graphics2D)g).setPaint(gradient);    
      g.fillOval(100, 100, 100, 100);
    }
    @Override
    public int getIconWidth() {
      return 200;
    }
    @Override
    public int getIconHeight() {
      return 200;
    }
  }
  static class RedRectangle implements Icon {
    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
      g.setColor(Color.RED);
      g.fillRect(100, 100, 100, 100);
    }
    @Override
    public int getIconWidth() {
      return 200;
    }
    @Override
    public int getIconHeight() {
      return 200;
    }
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JLabel content = new JLabel(new RedRectangle());
    JButton button = new JButton("Change To Circle");
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        content.setIcon(new GradientOval());
      }
    });

    frame.getContentPane().add(BorderLayout.SOUTH, button);
    frame.getContentPane().add(BorderLayout.CENTER, content);

    frame.setSize(300, 300);
    frame.setVisible(true);
  }
}

我不知道你的 Java 知识水平是多少。代码

button.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
    content.setIcon(new GradientOval());
  }
});

创建一个实现ActionListeneranonymous inner class 的实例。您可以使用lambda expression 简化此代码:

button.addActionListener(e -> content.setIcon(new GradientOval()));

为了演示组件属性和重绘之间的交互,这里使用自定义组件的方法:

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

public class SimpleGUI {
  static class DualAppearance extends JComponent {
    private boolean first = true;

    public boolean isFirst() {
      return first;
    }

    public void setFirst(boolean shouldBeFirst) {
      if(shouldBeFirst != first) {
        first = shouldBeFirst;
        repaint();
      }
    }

    public void next() {
      if(first) {
        first = false;
        repaint();
      }
    }

    @Override
    protected void paintComponent(Graphics g) {
      if(first) {
        g.setColor(Color.RED);
        g.fillRect(100, 100, 100, 100);
      }
      else {
        GradientPaint gradient
            = new GradientPaint(70,70, Color.orange, 150,150, Color.pink);
        ((Graphics2D)g).setPaint(gradient);    
        g.fillOval(100, 100, 100, 100);
      }
    }
    @Override
    public Dimension getPreferredSize() {
      return new Dimension(200, 200);
    }
    @Override
    public Dimension getMinimumSize() {
      return new Dimension(200, 200);
    }
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    DualAppearance content = new DualAppearance();
    JButton button = new JButton("Change To Second");
    button.addActionListener(e -> content.next());

    frame.getContentPane().add(BorderLayout.SOUTH, button);
    frame.getContentPane().add(BorderLayout.CENTER, content);

    frame.setSize(300, 300);
    frame.setVisible(true);
  }
}

这个DualAppearance 组件遵循通常的模式。当被请求绘制自己时,它总是会根据当前状态绘制自己。由于其他原因,这可能会发生多次而没有状态更改,例如被系统请求。当它自己的状态发生变化并需要重新绘制时,只有这个组件可以知道,它会调用repaint

您可以通过替换轻松修改此示例代码以在两种外观之间切换

JButton button = new JButton("Change To Second");
button.addActionListener(e -> content.next());

JButton button = new JButton("Toggle");
button.addActionListener(e -> content.setFirst(!content.isFirst()));

【讨论】:

    猜你喜欢
    • 2016-05-03
    • 2016-08-12
    • 2016-11-04
    • 2021-12-31
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 2016-02-21
    • 1970-01-01
    相关资源
    最近更新 更多