質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JFrame

JFrameはJFC/Swingフレームワークのコンポーネントであり、トップレベルのコンテナです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Swing

SwingはJavaに標準で付属するグラフィック関連のクラスライブラリを指します。

スライダー

GUIのグラフィカルウィジェットのひとつです。インジケーターを動かすことで値を調節可能とします。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Q&A

解決済

2回答

969閲覧

jframeの画面上で動かしている時刻をJSliderを使って自由に任意の時刻へ飛べるようにしたい

asagao0

総合スコア1

JFrame

JFrameはJFC/Swingフレームワークのコンポーネントであり、トップレベルのコンテナです。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Swing

SwingはJavaに標準で付属するグラフィック関連のクラスライブラリを指します。

スライダー

GUIのグラフィカルウィジェットのひとつです。インジケーターを動かすことで値を調節可能とします。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

0グッド

0クリップ

投稿2022/01/01 21:26

前提・実現したいこと

jframeの画面上で動かしている時刻(自分で作成したものでリアルの時刻ではない)を同じく画面上にあるスライダーを使って自由に任意の時刻へ飛べるようにしたいです。
プログラミング初心者でいろいろ調べながらここまで作成しましたがこれ以上進まず行き詰っています。
どなたかアドバイスしてくださるとうれしいです。

発生している問題・エラーメッセージ

今現在、時間の作成、スライダーの作成、画面上への表示はできているのですが、時間とスライダーの対応付けができておらず、また、スライダーを左右に動かそうとしても動かないという状況です。

該当のソースコード

Java

1 2import java.awt.BorderLayout; 3import java.awt.Color; 4import java.awt.Font; 5import java.awt.Graphics; 6import java.util.Hashtable; 7 8import javax.swing.JComponent; 9import javax.swing.JFrame; 10import javax.swing.JLabel; 11import javax.swing.JPanel; 12import javax.swing.JSlider; 13public class Windows6 extends JFrame { 14 private static final long serialVersionUID = 1L; 15 //画面の作成 16 public Windows6() { 17 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 18 Hashtable<Integer, JComponent> table = new Hashtable<Integer, JComponent>(); 19 20 table.put(new Integer(0), new JLabel("8")); //8時 21 table.put(new Integer(10), new JLabel("9")); 22 table.put(new Integer(20), new JLabel("10")); 23 table.put(new Integer(30), new JLabel("11")); 24 table.put(new Integer(40), new JLabel("12")); 25 table.put(new Integer(50), new JLabel("13")); 26 table.put(new Integer(60), new JLabel("14")); 27 table.put(new Integer(70), new JLabel("15")); 28 table.put(new Integer(80), new JLabel("16")); 29 table.put(new Integer(90), new JLabel("17")); 30 table.put(new Integer(100), new JLabel("18")); 31 32 JSlider slider = new JSlider(); 33 slider.setValue(0); 34 slider.setLabelTable(table); 35 slider.setPaintLabels(true); 36 37 JPanel p = new JPanel(); 38 p.add(slider); 39 40 getContentPane().add(p, BorderLayout.CENTER); 41 // フレームを表示 42 setVisible(true); 43 44 } 45 //画面表示 46 public void paint(Graphics g){ 47 super.paint(g); 48 49 int sec=20,min=31, hour=8; 50 51 for(int t=0; t<10000; t++) { 52 53 try{ 54 55 Thread.sleep(100); 56 57 58 59 }catch(InterruptedException e){ 60 } 61 62 63 if(sec==60) { 64 min=min+1; 65 sec=0; 66 } 67 if(min==60) { 68 hour=hour+1; 69 min=0; 70 } 71 if(hour==24){ 72 73 hour=0; 74 break; 75 } 76 77 78 String time=hour+":"+min+":"+sec; 79 80 System.out.println(hour+":"+min+":"+sec); 81 g.setColor(Color.white); 82 g.fillRect(50, 100, 100, 100); 83 g.setColor(Color.black); 84 Font font1 = new Font("MS Pゴシック",Font.PLAIN,30); 85 g.setFont(font1); 86 g.drawString(time,50,150); 87 88 89 90 sec++; 91 92 93 } 94 95 96 97} 98 public static void main(String[] args) { 99 100 JFrame f = new Windows6(); 101 f.setTitle("スライダー"); 102 f.setBounds(10, 10, 300, 300); 103 104 f.setVisible(true); 105 106 } 107}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/01/02 01:27 編集

何よりもまず、 paint 系のメソッドで sleep 等は行ってはいけません。 逆に極力処理を早く終えなければなりません。 そして、swing では paint ではなく paintComponent を上書きしてください。
guest

回答2

0

ベストアンサー

スライダーを左右に動かそうとしても動かない

Swing はシングルスレッドで動作します。
ボタンを押された時にリスナを呼び出したり、画面サイズが変わったら再描画したり等は全てその唯一のスレッドが行っています。
paint もそのスレッドが呼び出しています。
しかし、ご提示のコードでは paint は for 文が終わるまで終わらず、その for 文内では sleep までしています。
ですので、 Swing 唯一のスレッドは paint が終わるまで何も出来ず、結果アプリは反応しなくなります。

GUI プログラムは、単に自分の都合でだけ動作すれば良いわけではありません。
全体としてどう協調しなければならないかも知っている必要があります。

以下は Timer を使って時間をカウントするようにしています。

SlideTimer.java

java

1import java.awt.*; 2import java.awt.geom.Rectangle2D; 3import java.util.Hashtable; 4 5import javax.swing.*; 6 7public class SlideTimer extends JFrame { 8 public static void main(String[] args) { 9 new SlideTimer().setVisible(true); 10 } 11 12 public SlideTimer() { 13 super("スライダー"); 14 setBounds(10, 10, 300, 300); 15 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 16 17 TimePanel timePanel = new TimePanel(); 18 add(timePanel, BorderLayout.CENTER); 19 20 JSlider slider = new JSlider(8, 18, 8); 21 slider.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); 22 slider.addChangeListener(e -> timePanel.start(slider.getValue(), 0, 0)); 23 slider.setLabelTable(createLabelTable(8, 18)); 24 slider.setPaintLabels(true); 25 add(slider, BorderLayout.SOUTH); 26 27 timePanel.start(8, 31, 20); 28 } 29 30 private Hashtable<Integer,JComponent> createLabelTable(int from, int to) { 31 Hashtable<Integer,JComponent> table = new Hashtable<>(); 32 for(int i=from; i<=to; i++) table.put(i, new JLabel(""+i)); 33 return table; 34 } 35} 36 37class TimePanel extends JPanel { 38 private static final Font FONT = new Font("MS Pゴシック", Font.PLAIN, 30); 39 40 private final FontMetrics fontMetrics = getFontMetrics(FONT); 41 42 private class TimeCounter { 43 private int hour, min, sec; 44 TimeCounter(int hour, int min, int sec) { 45 this.sec = sec; 46 this.min = min; 47 this.hour = hour; 48 normalize(); 49 } 50 void countUp() { 51 sec ++; 52 normalize(); 53 } 54 private void normalize() { 55 while(sec < 0) { sec+=60; min--; } 56 while(sec >= 60) { sec-=60; min++; } 57 while(min < 0) { min+=60; hour--; } 58 while(min >= 60) { min-=60; hour++; } 59 while(hour < 0) { hour+=24; } 60 while(hour >= 24) { hour-=24; } 61 } 62 @Override 63 public String toString() { 64 return String.format("%02d:%02d:%02d", hour, min, sec); 65 } 66 } 67 private TimeCounter time; 68 private Object[] counterLock = new Object[0]; 69 private Timer timer; 70 71 TimePanel() { 72 super(null); 73 setBackground(Color.WHITE); 74 } 75 76 void start(int hour, int min, int sec) { 77 stop(); 78 79 synchronized(counterLock) { 80 time = new TimeCounter(hour, min ,sec); 81 } 82 83 if(timer == null) { 84 timer = new Timer(1000, e -> { 85 synchronized(counterLock) { 86 time.countUp(); 87 //System.out.println(time); 88 } 89 repaint(); 90 }); 91 timer.start(); 92 } else { 93 timer.restart(); 94 } 95 repaint(); 96 } 97 98 void stop() { 99 if(timer != null && timer.isRunning()) { 100 timer.stop(); 101 } 102 } 103 104 @Override 105 public void paintComponent(Graphics g) { 106 super.paintComponent(g); 107 108 String str; 109 synchronized(counterLock) { 110 str = time.toString(); 111 } 112 113 g.setColor(Color.black); 114 g.setFont(FONT); 115 Rectangle2D rect = fontMetrics.getStringBounds(str, g); 116 int x = (getWidth() -(int)rect.getWidth() )/2; 117 int y = (getHeight()-(int)rect.getHeight())/2; 118 g.drawString(str, x, y+fontMetrics.getMaxAscent()); //ベースライン 119 120 //Graphics2D g2 = (Graphics2D)g; 121 //g2.drawRect(x, y, (int)rect.getWidth(), (int)rect.getHeight()); 122 } 123}

投稿2022/01/02 06:50

jimbe

総合スコア12632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

asagao0

2022/01/02 15:16 編集

わざわざコードまで書いていただき本当にありがとうございます!! また、2回もコメントを下さり本当にありがとうございました>< 実際に動いてるのを見て感激しました!! paintのなかでfor文を回していたことが動かない原因だったのですね、、、 paintの中になんでも詰め込もうとした考えがだめでした。。 sleepではなくtimerを使うということが全く考えられていなかったのでコードを読み込んで理解していきたいと思います。 本当にありがとうございました!!
jimbe

2022/01/02 18:36 編集

「一秒毎に『足して表示』を繰り返せばいいんだから…」というのは間違っていないんですが、そこから「表示するのは paint だったな」と詰め込んだのが始まりだったようですね。 paint はあくまで表示だけです。その呼び出しは Swing のスレッドが必要に応じて行いますので、いつ呼ばれるかは分かりません。 このプログラムのウインドウに別のプログラム(Java/Swing とは限りません)のウインドウが重なって、それが退いた時等にも呼ばれます。 稀に、その場合には Swing の方で何が表示されていたか覚えていて勝手に表示を戻してくれると考えてしまっている人がいますが、実際はその都度 paint を呼び出されて再表示させられます。 ですので「ある瞬間に表示していて欲しい状態」に関する処理だけを書くようにしなければならないのです。 そして、残りの「一秒毎に『足して…』を繰り返せば」を例えば Timer で行って、『表示』は repaint でお願いする、ということになるわけです。 ちなみに「一秒毎に repaint すれば一秒毎に paint が呼ばれる形になるんだから、 paint で『足して表示』すればいっか」とすると、先のようにウインドウを重ねたり退けたりを繰り返すと必要以上に秒が進んでしまうことになります(^_^;
guest

0

GUIプログラムではThread.sleepは使わないでください。
UIスレッドがとまると、画面の応答ができなくなってしまいます。
こういった場合は、タイマーを使ってください。
Timer (Java Platform SE 8 )

jframeの画面上で動かしている時刻(自分で作成したものでリアルの時刻ではない)を同じく画面上にあるスライダーを使って自由に任意の時刻へ飛べるようにしたいです。

8時から18時の範囲が、0から100ではおおざっぱすぎますよね?(JSliderはintしか扱えず使い勝手が悪いですね^^;

秒まで表示のようですから、トータルの秒で管理してはどうでしょうか。
自分で計算してもいいですが、面倒なのでLocalTimeに計算してもらいました。
LocalTime (Java Platform SE 8 )

Java

1import java.awt.BorderLayout; 2import java.awt.Color; 3import java.awt.Font; 4import java.awt.event.ActionEvent; 5import java.awt.event.ActionListener; 6import java.time.LocalTime; 7import java.time.format.DateTimeFormatter; 8import java.util.Hashtable; 9import javax.swing.JComponent; 10import javax.swing.JFrame; 11import javax.swing.JLabel; 12import javax.swing.JPanel; 13import javax.swing.JSlider; 14import javax.swing.Timer; 15import javax.swing.event.ChangeEvent; 16import javax.swing.event.ChangeListener; 17 18 19public class Windows6 extends JFrame implements ChangeListener, ActionListener { 20 public static void main(String[] args) { 21 new Windows6().setVisible(true); 22 } 23 24 25 private final JSlider slider = new JSlider(); 26 private final JLabel label = new JLabel(); 27 private final DateTimeFormatter format = DateTimeFormatter.ofPattern("HH:mm:ss"); 28 29 private LocalTime time = LocalTime.of(8, 0); 30 31 32 public Windows6() { 33 setTitle("スライダー"); 34 setSize(300, 300); 35 setLocationRelativeTo(null); 36 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 37 38 Hashtable<Integer, JComponent> table = new Hashtable<>(); 39 for (int i = 8; i <= 18; i++) { 40 table.put(LocalTime.of(i, 0).toSecondOfDay(), new JLabel(String.valueOf(i))); 41 } 42 slider.setLabelTable(table); 43 slider.setMinimum(LocalTime.of(8, 0).toSecondOfDay()); // 28800 44 slider.setMaximum(LocalTime.of(18, 0).toSecondOfDay()); // 64800 45 slider.setValue(time.toSecondOfDay()); 46 slider.setPaintLabels(true); 47 slider.addChangeListener(this); 48 JPanel p = new JPanel(); 49 p.add(slider); 50 add(p, BorderLayout.NORTH); 51 52 label.setBounds(50, 50, 120, 100); 53 label.setFont(new Font("MS Pゴシック", Font.PLAIN, 30)); 54 label.setBackground(Color.WHITE); 55 label.setOpaque(true); 56 label.setVerticalAlignment(JLabel.CENTER); 57 label.setHorizontalAlignment(JLabel.CENTER); 58 JPanel p2 = new JPanel(null); 59 p2.add(label); 60 add(p2, BorderLayout.CENTER); 61 62 // 100ms間隔(きっちり100msというわけではない。普通だんだん遅延していく) 63 Timer timer = new Timer(100, this); 64 timer.start(); 65 } 66 67 // タイマーイベント 68 @Override public void actionPerformed(ActionEvent e) { 69 time = time.plusSeconds(1); 70 label.setText(time.format(format)); 71 slider.setValue(time.toSecondOfDay()); 72 } 73 74 // スライダーイベント 75 @Override public void stateChanged(ChangeEvent e) { 76 time = LocalTime.ofSecondOfDay(slider.getValue()); 77 } 78}

投稿2022/01/02 05:24

TN8001

総合スコア9317

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

asagao0

2022/01/02 15:06

たくさんのアドバイス本当にありがとうございます!!! 実際にいただいたコードで動かしてみると想像通りの動きをしていてびっくりしました。。。 sleepにはそんなデメリットがあるのですね、、 時間の計算も自分で計算するものだと思っていますたがlocaltimeを使うとすごく便利ですね 本当に勉強になります。 もっとじっくり読み込み理解したいと思います!! ありがとうございました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問