You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java图形时钟开发:对象间属性数据传递问题求助

解决Java图形化时钟的组件通信问题

嘿,我来帮你理一理这个问题~你现在的架构思路其实是挺合理的:用Drawer作为协调层,整合数据模型Clock和视图ClockPanel,这种分层的思想本身就很规范,不用怀疑架构的合理性,只是需要调整一下组件间的通信方式,让Drawer真正发挥它的协调作用。


核心问题分析

你之前考虑把Clock直接传入ClockPanel,确实会让Drawer的存在感变弱——因为这样视图层直接依赖了数据模型,Drawer就只是个简单的创建者,而不是协调者。我们要做的是让各模块职责单一:

  • Clock:只负责时间的存储和更新(数据层)
  • ClockPanel:只负责根据给定的时间绘制时钟(视图层)
  • Drawer:负责连接数据层和视图层,传递数据并触发更新(协调层)

具体解决方案

方案1:让Drawer作为中间传递者

这是最简单直接的方式,适合当前的场景:

  1. 给ClockPanel添加时间设置方法
    去掉ClockPanel对Clock的直接依赖,改成通过方法接收时间数据,然后自动触发重绘:

    public class ClockPanel extends JPanel {
        private int currentHour;
        private int currentMinute;
        private int currentSecond;
        // 你已有的其他变量(m_radiusWhiteCircle、m_centerX等)
    
        // 添加设置时间的方法
        public void setCurrentTime(int hour, int minute, int second) {
            this.currentHour = hour;
            this.currentMinute = minute;
            this.currentSecond = second;
            repaint(); // 时间更新后自动触发重绘
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            // 你已有的静态元素绘制代码(背景、圆圈、刻度等)
    
            // 新增绘制指针的逻辑,使用currentHour、currentMinute、currentSecond
            drawHourHand(g);
            drawMinuteHand(g);
            drawSecondHand(g);
        }
    
        // 绘制时针
        private void drawHourHand(Graphics g) {
            // 计算时针角度:30度/小时 + 0.5度/分钟(因为时针会随分钟移动),减去90度让0点指向顶部
            double angle = (currentHour % 12) * 30 + currentMinute * 0.5 - 90;
            int handLength = m_radiusWhiteCircle / 2;
            int endX = (int) (m_centerX + handLength * Math.cos(Math.toRadians(angle)));
            int endY = (int) (m_centerY + handLength * Math.sin(Math.toRadians(angle)));
    
            g.setColor(Color.BLACK);
            g.setStroke(new BasicStroke(4));
            g.drawLine(m_centerX, m_centerY, endX, endY);
        }
    
        // 绘制分针(类似逻辑)
        private void drawMinuteHand(Graphics g) {
            double angle = currentMinute * 6 - 90; // 6度/分钟
            int handLength = m_radiusWhiteCircle * 3 / 4;
            int endX = (int) (m_centerX + handLength * Math.cos(Math.toRadians(angle)));
            int endY = (int) (m_centerY + handLength * Math.sin(Math.toRadians(angle)));
    
            g.setColor(Color.DARK_GRAY);
            g.setStroke(new BasicStroke(2));
            g.drawLine(m_centerX, m_centerY, endX, endY);
        }
    
        // 绘制秒针(类似逻辑)
        private void drawSecondHand(Graphics g) {
            double angle = currentSecond * 6 - 90; // 6度/秒
            int handLength = m_radiusWhiteCircle - 20;
            int endX = (int) (m_centerX + handLength * Math.cos(Math.toRadians(angle)));
            int endY = (int) (m_centerY + handLength * Math.sin(Math.toRadians(angle)));
    
            g.setColor(Color.RED);
            g.setStroke(new BasicStroke(1));
            g.drawLine(m_centerX, m_centerY, endX, endY);
        }
    }
    
  2. 修改Drawer的initDraw方法
    让Drawer持有Clock和ClockPanel的引用,定期从Clock获取时间,传递给ClockPanel:

    public void initDraw() { 
        clockWindow = new JFrame(); 
        // 你已有的窗口配置代码(标题、大小、位置等)
        
        clockPanel = new ClockPanel(); // 不再传入m_clock
        clockWindow.setContentPane(clockPanel); 
        clockWindow.setVisible(true); // 注意:最好把setVisible放在最后,避免组件加载问题
    
        // 启动定时任务,每秒更新一次时间
        javax.swing.Timer timer = new javax.swing.Timer(1000, e -> {
            // 从Clock获取当前时间(假设Clock有getHour()、getMinute()、getSecond()方法)
            int hour = m_clock.getHour();
            int minute = m_clock.getMinute();
            int second = m_clock.getSecond();
            // 传递给ClockPanel
            clockPanel.setCurrentTime(hour, minute, second);
        });
        timer.start();
    }
    

方案2:使用观察者模式(更优雅的解耦)

如果你的Clock需要主动通知视图时间变化(比如时间不是定时轮询,而是有外部触发更新),可以用观察者模式实现解耦:

  1. 让Clock成为被观察者

    import java.util.Observable;
    
    public class Clock extends Observable {
        private int hour;
        private int minute;
        private int second;
    
        // 假设你有更新时间的方法,比如每秒自动更新
        public void updateTime() {
            // 这里写更新hour、minute、second的逻辑(比如获取系统时间)
            // ...
    
            // 通知观察者时间已变化
            setChanged();
            notifyObservers(new TimeUpdate(hour, minute, second));
        }
    
        // 内部类封装时间更新数据
        public static class TimeUpdate {
            public final int hour;
            public final int minute;
            public final int second;
    
            public TimeUpdate(int hour, int minute, int second) {
                this.hour = hour;
                this.minute = minute;
                this.second = second;
            }
        }
    }
    
  2. 让Drawer成为观察者

    import java.util.Observer;
    import java.util.Observable;
    
    public class Drawer implements Observer {
        private Clock m_clock;
        private ClockPanel clockPanel;
        private JFrame clockWindow;
    
        public Drawer() {
            m_clock = new Clock();
            m_clock.addObserver(this); // 注册为观察者
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if (arg instanceof Clock.TimeUpdate update) {
                // 把时间传递给ClockPanel
                clockPanel.setCurrentTime(update.hour, update.minute, update.second);
            }
        }
    
        public void initDraw() {
            // 你已有的窗口初始化代码
            clockPanel = new ClockPanel();
            clockWindow.setContentPane(clockPanel);
            clockWindow.setVisible(true);
    
            // 启动Clock的时间更新任务
            javax.swing.Timer timer = new javax.swing.Timer(1000, e -> m_clock.updateTime());
            timer.start();
        }
    }
    

总结

你的架构思路完全没问题,Drawer作为协调层的定位很准确,只需要让它承担起数据传递和触发更新的职责,而不是让视图直接依赖数据模型。这样每个类都只做自己擅长的事,符合单一职责原则,后续维护和扩展都会更轻松。

内容的提问来源于stack exchange,提问作者Quentin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 09:02:38