【问题标题】:How to set a new value (Date) for a Java bean property?如何为 Java bean 属性设置新值(日期)?
【发布时间】:2020-04-26 00:55:42
【问题描述】:

我正在编写一个 bean(我正在学习 Java 和 Java bean),它是一个扩展 JLabel 的数字手表。显示的文本为hh:mm:ss

当我尝试在新项目中使用组件(手表)时,它默认显示系统日期(我将 bean 编程为以这种方式工作)。但是我想允许开发人员(在这种情况下是我自己)可以编辑属性“hora”来设置不同的日期。所以如果开发者在一个新项目中插入组件,文本必须是系统的时间。但是,如果开发人员编辑属性“hora”并设置一个新日期,例如多一小时,则显示的文本应该是新值,在本例中为system date + 1 hour

我当前的代码部分工作:

在上一张图片中:

  • 右侧属性“hora”的值是:系统日期 + 1 小时。
  • NetBeans 的预览视图左侧显示正确的时间(系统时间 + 1 小时)。分钟的差异是因为手表每秒钟都在工作并改变它的时间。屏幕截图是在编辑属性值几分钟后制作的。
  • 在中心项目正在运行并显示错误的日期(系统日期)。
  • 请忽略按钮和微调器,它们仅用于测试目的。

如何改变这种行为?那么当我运行项目时,显示的时间与“hora”属性中选择的时间相同吗?

相关代码:

public class Reloj extends JLabel implements Serializable {
    private Date hora = new Date();
    private SimpleDateFormat formatoHora;
    private boolean doceHoras = false;

    public Reloj() {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
             public void run() {
                setHora(new Date((getHora().getTime())+1000));

            }
        }, 0, 1000);
    }

    public Date getHora() {
        return this.hora;
    }

    public void setHora(Date hora) {
        this.hora = hora;
        this.setText(this.getFormatoHora().format(hora));
        this.repaint();
    }

    public SimpleDateFormat getFormatoHora() {
        if (this.isDoceHoras()) {
            this.formatoHora = new SimpleDateFormat("hh:mm:ss a");
        } else {
            this.formatoHora = new SimpleDateFormat("HH:mm:ss");
        }
        return this.formatoHora;
    }

    public void setDoceHoras(boolean doceHoras) {
        this.doceHoras = doceHoras;
        this.setHora(hora);
    }
}

感谢您的帮助,对不起我的英语。

【问题讨论】:

  • 您使用的是什么 Java 版本?如果您正在编译 Java 8+,请考虑使用 java.time 而不是 java.util...
  • 开发者如何输入修改后的日期?您的代码没有显示 - 我怀疑 setHora(Date) 会在某个时候被调用,但由于用户只能输入一些 text ,因此缺少将该文本解析为正确的 Date 对象。另请注意,您的计时器不是线程安全的,因此用户的输入可能会丢失。
  • @deHaar 我使用的是 Java 8。java.timejava.util 有什么不同?我如何使用java.time 来获得我需要的东西?
  • @Thomas 开发人员只需单击属性值并编辑新日期。例如,如果系统日期为08-Jan-2020 17:38:38,则手动将其更改为08-Jan-2020 18:38:38
  • 包完全不同...例如在java.time 中,您可以像这样为LocalTime 添加一个小时:LocalTime nowPlusOneHour = LocalTime.now().plusHours(1);。您甚至可以传递时区 (ZoneId) 或只是偏移到某些对象,并轻松地将日期时间从一个区域转换为另一个区域。看看the Oracle tutorial,这也解释了为什么你应该切换到java.time

标签: java swing date javabeans jlabel


【解决方案1】:

JavaBeans 作为小部件组件

(我正在学习Java和Java bean)

据我所知,在视觉设计工具中使用JavaBeans 作为组件从未流行过。我很惊讶NetBeans 仍然支持这一点。我建议您不要在 JavaBean 技术的这方面花费太多时间或精力。

java.time

它默认显示系统的日期(我将 bean 编程为以这种方式工作)。

您正在使用糟糕的日期时间类,这些类在几年前被 JSR 310 中定义的现代 java.time 类所取代。

切勿使用DateSimpleDateFormat。如果您必须与尚未更新到 java.time 的旧代码进行互操作,请在 java.time 中执行所有逻辑,最后使用添加到旧类的新方法进行转换.

对于只有时间的值,没有日期和时区,请使用LocalTime

时区

获取当前时间涉及获取当前时刻。这需要一个时区。对于任何给定的时刻,日期和时间都因全球时区而异。

如果没有指定时区,JVM 会隐式应用其当前的默认时区。该默认值可能在运行时(!)期间change at any moment,因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。如果您想使用 JVM 当前的默认时区,请通过调用 ZoneId.systemDefault() 明确您的意图。如果关键,请与您的用户确认该区域。

Continent/Region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 2-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalTime lt = LocalTime.now( z ) ;

如果您想使用 JVM 当前的默认时区,请显式请求它,并作为参数传递。如果省略,代码会变得模糊,因为我们不确定您是否打算使用默认值,或者您是否像许多程序员一样没有意识到这个问题。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.
LocalTime lt = LocalTime.now( z ) ;

如果此内容至关重要,您应该与用户确认时区。系统默认设置可能不符合用户的意图,尤其是考虑到移动设备和笔记本电脑很容易在时区之间移动。在这种情况下,您应该将 ZoneId 对象作为成员字段保留在您的小部件类或小部件可访问的其他位置。

所以如果开发者在新项目中插入组件,文本必须是系统时间。

您可以解析用户输入的文本。如果采用标准ISO 8601 格式,HH:MM:SS 和 24 小时制,您无需费心指定格式模式。 java.time 类在解析/生成文本时默认使用标准格式。

String input = "23:01:23" ;
LocalTime lt = LocalTime.parse( input ) ;

如果您想本地化表示我们LocalTime 对象值的显示文本,请使用DateTimeFormatter。指定Locale 来确定人类语言和文化规范used in localizing。并指定一个FormatStyle 来说明多长时间或缩写。

Locale locale = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedTime( FormatStyle.MEDIUM ) ;

搜索以了解更多信息。这已经在 Stack Overflow 上讨论过很多次了。

动态更新

你的其余代码让我有点困惑。您似乎想将时钟更新到当前时刻,不断刷新。然而,您还允许用户更改时间。这是矛盾的。

我怀疑你真正想要的是 两个 部分一起工作:一个时间显示和一个时区。如果你试图让用户改变时钟显示以匹配他们的时区,你应该通过让用户指定一个时区来做到这一点(如上所述)。换句话说,改变时钟应该是一个结果,而不是一个原因。用户操作您的时区属性,时钟会自动更改其时间,如该时区所代表的地区的人们使用的偏移量所示。

另一个问题:定期更新。您正在使用TimerTimerTask,这两个类已被Executor framework 取代。特别是在 Swing 中,您应该使用javax.swing.Timer 类(请参阅Tutorial)而不是java.util.Timer

强制性警告:切勿从后台线程访问、更新或操作 Swing 小部件。仅在用户界面线程中这样做。

示例应用

这是一个简单粗暴的 Swing 应用示例。这不是 JavaBean 组件。我不太记得 Swing。但这可能会对您有所帮助。您可以看到更改时区 (ZoneId) 如何更新时间,同时将其移动到该区域当前有效的偏移量。

package org.example;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.DateTimeException;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;

/**
 * Hello world!
 */
public class App extends JFrame
{
    ZoneId zoneId;
    LocalTime localTime;
    JTextField timeZone;
    JLabel displayTime;
    DateTimeFormatter formatter;


    public App ( )
    {
        initUI();
    }

    private void initUI ( )
    {

        setTitle( "Simple example" );
        setSize( 300 , 200 );
        setLocationRelativeTo( null );
        setDefaultCloseOperation( EXIT_ON_CLOSE );

        // Widgets
        this.zoneId = ZoneId.systemDefault();
        this.timeZone = new JTextField( this.zoneId.getId() , 20 );
        this.localTime = LocalTime.now( this.zoneId );
        Locale locale = Locale.CANADA_FRENCH;
        this.formatter = DateTimeFormatter.ofLocalizedTime( FormatStyle.MEDIUM );
        this.displayTime = new JLabel( this.localTime.format( this.formatter ) );

        this.timeZone.addActionListener( new ActionListener()
        {
            @Override
            public void actionPerformed ( ActionEvent event )
            {
                System.out.println( "The entered text is: " + timeZone.getText() );
                try
                {
                    zoneId = ZoneId.of( timeZone.getText() );
                    localTime = LocalTime.now( zoneId );
                    String output = LocalTime.now( zoneId ).format( formatter );
                    displayTime.setText( output );
                }
                catch ( DateTimeException e )
                {
                    System.out.println( "BAD INPUT - The user gave an invalid time zone: " + timeZone );
                }
            }
        } );

        // Arrange
        JPanel panel = new JPanel();
        panel.add( this.displayTime );
        panel.add( this.timeZone );
        this.add( panel );
    }

    public static void main ( String[] args )
    {

        EventQueue.invokeLater( ( ) -> {

            var ex = new App();
            ex.setVisible( true );
        } );
    }
}

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    猜你喜欢
    • 2011-11-06
    • 2011-06-03
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    • 2014-11-03
    相关资源
    最近更新 更多