mini clock tool

This commit is contained in:
J.Henezi
2025-01-08 15:09:57 +01:00
commit 26bd00e7f3
14 changed files with 995 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
### IntelliJ IDEA ###
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
+8
View File
@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+8
View File
@@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="WatchTheClock:jar">
<output-path>$PROJECT_DIR$/out/artifacts/WatchTheClock_jar</output-path>
<root id="archive" name="WatchTheClock.jar">
<element id="module-output" name="WatchTheClock" />
</root>
</artifact>
</component>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/WatchTheClock.iml" filepath="$PROJECT_DIR$/WatchTheClock.iml" />
</modules>
</component>
</project>
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+3
View File
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: Main
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

+131
View File
@@ -0,0 +1,131 @@
import javax.sound.sampled.*;
import javax.swing.*;
import java.awt.*;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class AlarmLogic {
private JTextField hoursField;
private JTextField minutesField;
private JButton activateButton;
private JCheckBox soundCheckbox;
private Timer timer;
private boolean isActive;
private Clip alertSound;
public AlarmLogic(JTextField hours, JTextField minutes,
JButton activateBtn, JCheckBox soundCb) {
this.hoursField = hours;
this.minutesField = minutes;
this.activateButton = activateBtn;
this.soundCheckbox = soundCb;
this.isActive = false;
// Sound laden
try {
AudioInputStream audioStream = AudioSystem.getAudioInputStream(
getClass().getResource("/alert.wav"));
alertSound = AudioSystem.getClip();
alertSound.open(audioStream);
} catch (Exception e) {
e.printStackTrace();
}
// Timer für Überprüfung jede Sekunde
timer = new Timer(1000, e -> checkAlarm());
}
public void toggleActivation() {
if (!isActive) {
// Überprüfe Eingaben
try {
int hours = Integer.parseInt(hoursField.getText());
int minutes = Integer.parseInt(minutesField.getText());
if (hours >= 0 && hours <= 23 && minutes >= 0 && minutes <= 59) {
isActive = true;
activateButton.setText("Deactivate");
activateButton.setBackground(new Color(244, 67, 54));
setFieldsEditable(false);
timer.start();
} else {
JOptionPane.showMessageDialog(null,
"Bitte gültige Zeit eingeben!\nStunden: 0-23\nMinuten: 0-59",
"Ungültige Zeit",
JOptionPane.ERROR_MESSAGE);
}
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(null,
"Bitte nur Zahlen eingeben!",
"Ungültige Eingabe",
JOptionPane.ERROR_MESSAGE);
}
} else {
deactivateAlarm();
}
}
private void checkAlarm() {
LocalTime now = LocalTime.now();
int currentHour = now.getHour();
int currentMinute = now.getMinute();
int targetHour = Integer.parseInt(hoursField.getText());
int targetMinute = Integer.parseInt(minutesField.getText());
if (currentHour == targetHour && currentMinute == targetMinute) {
// Alarm auslösen
if (soundCheckbox.isSelected() && alertSound != null) {
alertSound.loop(Clip.LOOP_CONTINUOUSLY);
}
String currentTime = now.format(DateTimeFormatter.ofPattern("HH:mm"));
Object[] options = {"OK", "+5 min"};
int choice = JOptionPane.showOptionDialog(null,
"Es ist " + currentTime + "!",
"Alarm",
JOptionPane.DEFAULT_OPTION,
JOptionPane.INFORMATION_MESSAGE,
null,
options,
options[0]);
if (choice == 0) { // OK
deactivateAlarm();
} else if (choice == 1) { // +5 min
if (alertSound != null) {
alertSound.stop();
alertSound.setFramePosition(0);
}
// Neue Alarmzeit berechnen (+5 Minuten)
LocalTime newAlarmTime = LocalTime.of(targetHour, targetMinute).plusMinutes(5);
hoursField.setText(String.valueOf(newAlarmTime.getHour()));
minutesField.setText(String.format("%02d", newAlarmTime.getMinute()));
// Zeige neue Alarmzeit an
JOptionPane.showMessageDialog(null,
"Neuer Alarm um " + newAlarmTime.format(DateTimeFormatter.ofPattern("HH:mm")),
"Schlummerfunktion",
JOptionPane.INFORMATION_MESSAGE);
}
}
}
private void deactivateAlarm() {
isActive = false;
timer.stop();
if (alertSound != null) {
alertSound.stop();
alertSound.setFramePosition(0);
}
activateButton.setText("Activate");
activateButton.setBackground(new Color(76, 175, 80));
setFieldsEditable(true);
}
private void setFieldsEditable(boolean editable) {
hoursField.setEditable(editable);
minutesField.setEditable(editable);
}
}
+119
View File
@@ -0,0 +1,119 @@
import javax.swing.*;
import javax.sound.sampled.*;
import java.awt.*;
public class CountdownLogic {
private JTextField hoursField;
private JTextField minutesField;
private JTextField secondsField;
private JButton startButton;
private JCheckBox soundCheckbox;
private Timer timer;
private long remainingTime;
private boolean isRunning;
private Clip alertSound;
public CountdownLogic(JTextField hours, JTextField minutes, JTextField seconds,
JButton startBtn, JCheckBox soundCb) {
this.hoursField = hours;
this.minutesField = minutes;
this.secondsField = seconds;
this.startButton = startBtn;
this.soundCheckbox = soundCb;
this.isRunning = false;
// Sound laden
try {
AudioInputStream audioStream = AudioSystem.getAudioInputStream(
getClass().getResource("/alert.wav"));
alertSound = AudioSystem.getClip();
alertSound.open(audioStream);
} catch (Exception e) {
e.printStackTrace();
}
timer = new Timer(1000, e -> updateCountdown());
}
public void toggleStartStop() {
if (!isRunning) {
// Startzeit berechnen
long hours = Long.parseLong(hoursField.getText());
long minutes = Long.parseLong(minutesField.getText());
long seconds = Long.parseLong(secondsField.getText());
remainingTime = hours * 3600 + minutes * 60 + seconds;
if (remainingTime > 0) {
isRunning = true;
startButton.setText("Pause");
startButton.setBackground(new Color(255, 152, 0));
timer.start();
setFieldsEditable(false);
}
} else {
isRunning = false;
startButton.setText("Start");
startButton.setBackground(new Color(76, 175, 80));
timer.stop();
setFieldsEditable(true);
}
}
private void updateCountdown() {
if (remainingTime > 0) {
remainingTime--;
updateDisplay();
} else {
timer.stop();
isRunning = false;
startButton.setText("Start");
startButton.setBackground(new Color(76, 175, 80));
setFieldsEditable(true);
// Sound in Schleife starten wenn aktiviert
if (soundCheckbox.isSelected() && alertSound != null) {
alertSound.loop(Clip.LOOP_CONTINUOUSLY);
}
// Benachrichtigung anzeigen und danach Sound stoppen
JOptionPane.showMessageDialog(null,
"Countdown beendet!",
"Zeit abgelaufen",
JOptionPane.INFORMATION_MESSAGE);
// Sound stoppen nach OK-Klick
if (alertSound != null) {
alertSound.stop();
alertSound.setFramePosition(0);
}
}
}
private void updateDisplay() {
long hours = remainingTime / 3600;
long minutes = (remainingTime % 3600) / 60;
long seconds = remainingTime % 60;
hoursField.setText(String.valueOf(hours));
minutesField.setText(String.format("%02d", minutes));
secondsField.setText(String.format("%02d", seconds));
}
private void setFieldsEditable(boolean editable) {
hoursField.setEditable(editable);
minutesField.setEditable(editable);
secondsField.setEditable(editable);
}
public void reset() {
timer.stop();
isRunning = false;
startButton.setText("Start");
startButton.setBackground(new Color(76, 175, 80));
hoursField.setText("0");
minutesField.setText("0");
secondsField.setText("0");
setFieldsEditable(true);
}
}
+471
View File
@@ -0,0 +1,471 @@
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.AbstractDocument;
import javax.swing.event.HyperlinkEvent;
import java.awt.Desktop;
public class Main {
private static JFrame frame;
private static String baseTitle = "WatchTheClock";
private static String currentTitle = "";
public static void main(String[] args) {
// Setze den Anwendungsnamen für Windows
System.setProperty("sun.java.command", baseTitle);
frame = new JFrame(baseTitle);
// Icon setzen
try {
Image icon = new ImageIcon(Main.class.getResource("/clock.png")).getImage();
frame.setIconImage(icon);
} catch (Exception e) {
System.err.println("Icon konnte nicht geladen werden: " + e.getMessage());
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(450, 300);
frame.setMinimumSize(new Dimension(400, 280));
frame.setLocationRelativeTo(null);
// Erstellt JTabbedPane für die verschiedenen Funktionen
JTabbedPane tabbedPane = new JTabbedPane();
frame.add(tabbedPane);
// Fügt die Tabs hinzu
tabbedPane.addTab("Stopwatch", createStopwatchPanel());
tabbedPane.addTab("Countdown", createCountdownPanel());
tabbedPane.addTab("Alarm", createAlarmPanel());
tabbedPane.addTab("Notes", createNotesPanel());
tabbedPane.addTab("ToDo", createTodoPanel());
// Menüleiste erstellen
JMenuBar menuBar = new JMenuBar();
JMenu settingsMenu = new JMenu("");
JMenu helpMenu = new JMenu("?");
// Settings-Menü Items
JCheckBoxMenuItem alwaysOnTopItem = new JCheckBoxMenuItem("Always on Top");
alwaysOnTopItem.addActionListener(e -> frame.setAlwaysOnTop(alwaysOnTopItem.isSelected()));
settingsMenu.add(alwaysOnTopItem);
// Titel-Menüpunkt
JMenuItem titleItem = new JMenuItem("Titel ändern");
titleItem.addActionListener(e -> changeTitleDialog());
settingsMenu.add(titleItem);
// Info-Menüpunkt
JMenuItem aboutItem = new JMenuItem("About");
aboutItem.addActionListener(e -> {
JEditorPane editorPane = new JEditorPane("text/html",
"<html><div style='font-family: Arial; font-size: 10px;'>" +
"WatchTheClock v0.1<br><br>" +
"This tool is free to use and portable!<br><br>" +
"Made by Jordan Henézi<br><br>" +
"Last time updated: 08.01.2025<br><br>" +
"Website: <a href='https://henezi.de'>henezi.de</a><br>" +
"Support: watchtheclock@henezi.de<br><br>" +
"Copyright © 2025" +
"</div></html>");
editorPane.setEditable(false);
editorPane.setBackground(new JLabel().getBackground());
// Links klickbar machen
editorPane.addHyperlinkListener(event -> {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
try {
String url = event.getURL().toString();
if (!url.startsWith("mailto:")) {
Desktop.getDesktop().browse(event.getURL().toURI());
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
JOptionPane.showMessageDialog(frame,
editorPane,
"About WatchTheClock",
JOptionPane.INFORMATION_MESSAGE);
});
helpMenu.add(aboutItem);
menuBar.add(settingsMenu);
menuBar.add(helpMenu);
frame.setJMenuBar(menuBar);
frame.setVisible(true);
}
private static JPanel createStopwatchPanel() {
JPanel panel = new JPanel(new BorderLayout());
// Zeitanzeige mit mehr Platz
JLabel timeLabel = new JLabel("00:00:00");
timeLabel.setFont(new Font("Arial", Font.BOLD, 72));
timeLabel.setHorizontalAlignment(SwingConstants.CENTER);
// Extra Panel für die Zeitanzeige mit weniger Padding oben
JPanel timeLabelPanel = new JPanel(new BorderLayout());
timeLabelPanel.add(timeLabel, BorderLayout.CENTER);
timeLabelPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 20, 0)); // Reduziertes Top-Padding
panel.add(timeLabelPanel, BorderLayout.CENTER);
// Buttons Panel
JPanel buttonPanel = new JPanel(new FlowLayout());
JButton startButton = new JButton("Start");
JButton resetButton = new JButton("Reset");
startButton.setBackground(new Color(76, 175, 80));
resetButton.setBackground(new Color(244, 67, 54));
buttonPanel.add(startButton);
buttonPanel.add(resetButton);
panel.add(buttonPanel, BorderLayout.SOUTH);
// Timeline Panel mit angepasster Größe
JPanel timelinePanel = new JPanel();
timelinePanel.setLayout(null);
JScrollPane scrollPane = new JScrollPane(timelinePanel,
JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBorder(BorderFactory.createTitledBorder("Timeline"));
scrollPane.setPreferredSize(new Dimension(430, 85)); // Breite und Höhe angepasst
// Mausrad-Scrolling
timelinePanel.addMouseWheelListener(e -> {
JScrollBar horizontalBar = scrollPane.getHorizontalScrollBar();
int delta = e.getWheelRotation() * 50; // Scroll-Geschwindigkeit
int newValue = horizontalBar.getValue() + delta;
newValue = Math.max(0, Math.min(newValue, horizontalBar.getMaximum()));
horizontalBar.setValue(newValue);
});
// Fügt den MouseWheelListener auch zum ScrollPane hinzu
scrollPane.addMouseWheelListener(e -> {
JScrollBar horizontalBar = scrollPane.getHorizontalScrollBar();
int delta = e.getWheelRotation() * 50;
int newValue = horizontalBar.getValue() + delta;
newValue = Math.max(0, Math.min(newValue, horizontalBar.getMaximum()));
horizontalBar.setValue(newValue);
});
panel.add(scrollPane, BorderLayout.NORTH);
// Stopwatch Logik
StopwatchLogic stopwatch = new StopwatchLogic(timeLabel, timelinePanel, startButton);
startButton.addActionListener(e -> stopwatch.toggleStartStop());
resetButton.addActionListener(e -> stopwatch.reset());
return panel;
}
private static JPanel createCountdownPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
// Zeit-Eingabe Panel
JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 0));
// Stunden Input
JPanel hoursPanel = new JPanel(new BorderLayout());
JLabel hoursLabel = new JLabel("Hours", SwingConstants.CENTER);
JTextField hoursField = new JTextField("0", 3);
hoursField.setHorizontalAlignment(SwingConstants.CENTER);
hoursField.setFont(new Font("Arial", Font.BOLD, 24));
hoursPanel.add(hoursLabel, BorderLayout.NORTH);
hoursPanel.add(hoursField, BorderLayout.CENTER);
// Minuten Input
JPanel minutesPanel = new JPanel(new BorderLayout());
JLabel minutesLabel = new JLabel("Minutes", SwingConstants.CENTER);
JTextField minutesField = new JTextField("0", 3);
minutesField.setHorizontalAlignment(SwingConstants.CENTER);
minutesField.setFont(new Font("Arial", Font.BOLD, 24));
minutesPanel.add(minutesLabel, BorderLayout.NORTH);
minutesPanel.add(minutesField, BorderLayout.CENTER);
// Sekunden Input
JPanel secondsPanel = new JPanel(new BorderLayout());
JLabel secondsLabel = new JLabel("Seconds", SwingConstants.CENTER);
JTextField secondsField = new JTextField("0", 3);
secondsField.setHorizontalAlignment(SwingConstants.CENTER);
secondsField.setFont(new Font("Arial", Font.BOLD, 24));
secondsPanel.add(secondsLabel, BorderLayout.NORTH);
secondsPanel.add(secondsField, BorderLayout.CENTER);
// Trennpunkte zwischen den Feldern
JLabel separator1 = new JLabel(":", SwingConstants.CENTER);
JLabel separator2 = new JLabel(":", SwingConstants.CENTER);
separator1.setFont(new Font("Arial", Font.BOLD, 24));
separator2.setFont(new Font("Arial", Font.BOLD, 24));
inputPanel.add(hoursPanel);
inputPanel.add(separator1);
inputPanel.add(minutesPanel);
inputPanel.add(separator2);
inputPanel.add(secondsPanel);
// Control Panel
JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10));
// Start Button
JButton startButton = new JButton("Start");
startButton.setBackground(new Color(76, 175, 80));
startButton.setPreferredSize(new Dimension(100, 35));
// Reset Button
JButton resetButton = new JButton("Reset");
resetButton.setBackground(new Color(244, 67, 54));
resetButton.setPreferredSize(new Dimension(100, 35));
// Sound Checkbox
JCheckBox soundCheckbox = new JCheckBox("Play sound");
soundCheckbox.setSelected(true);
controlPanel.add(startButton);
controlPanel.add(resetButton);
controlPanel.add(soundCheckbox);
panel.add(inputPanel, BorderLayout.CENTER);
panel.add(controlPanel, BorderLayout.SOUTH);
// Nur Zahlen in den Textfeldern erlauben
DocumentFilter numberFilter = new DocumentFilter() {
@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
if (string.matches("\\d*")) {
super.insertString(fb, offset, string, attr);
}
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
if (text.matches("\\d*")) {
super.replace(fb, offset, length, text, attrs);
}
}
};
// FocusListener für automatische Null
FocusAdapter focusAdapter = new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
JTextField field = (JTextField) e.getComponent();
if (field.getText().trim().isEmpty()) {
field.setText("0");
}
}
};
// Anwenden auf alle Felder
hoursField.addFocusListener(focusAdapter);
minutesField.addFocusListener(focusAdapter);
secondsField.addFocusListener(focusAdapter);
((AbstractDocument) hoursField.getDocument()).setDocumentFilter(numberFilter);
((AbstractDocument) minutesField.getDocument()).setDocumentFilter(numberFilter);
((AbstractDocument) secondsField.getDocument()).setDocumentFilter(numberFilter);
// Countdown Logik
CountdownLogic countdown = new CountdownLogic(hoursField, minutesField, secondsField,
startButton, soundCheckbox);
startButton.addActionListener(e -> countdown.toggleStartStop());
resetButton.addActionListener(e -> countdown.reset());
return panel;
}
private static JPanel createAlarmPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
// Zeit-Eingabe Panel
JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 0));
// Stunden Input
JPanel hoursPanel = new JPanel(new BorderLayout());
JLabel hoursLabel = new JLabel("Hours", SwingConstants.CENTER);
JTextField hoursField = new JTextField("0", 3);
hoursField.setHorizontalAlignment(SwingConstants.CENTER);
hoursField.setFont(new Font("Arial", Font.BOLD, 24));
hoursPanel.add(hoursLabel, BorderLayout.NORTH);
hoursPanel.add(hoursField, BorderLayout.CENTER);
// Minuten Input
JPanel minutesPanel = new JPanel(new BorderLayout());
JLabel minutesLabel = new JLabel("Minutes", SwingConstants.CENTER);
JTextField minutesField = new JTextField("0", 3);
minutesField.setHorizontalAlignment(SwingConstants.CENTER);
minutesField.setFont(new Font("Arial", Font.BOLD, 24));
minutesPanel.add(minutesLabel, BorderLayout.NORTH);
minutesPanel.add(minutesField, BorderLayout.CENTER);
// Trennpunkte
JLabel separator = new JLabel(":", SwingConstants.CENTER);
separator.setFont(new Font("Arial", Font.BOLD, 24));
inputPanel.add(hoursPanel);
inputPanel.add(separator);
inputPanel.add(minutesPanel);
// Control Panel
JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10));
JButton activateButton = new JButton("Activate");
activateButton.setBackground(new Color(76, 175, 80));
activateButton.setPreferredSize(new Dimension(100, 35));
JCheckBox soundCheckbox = new JCheckBox("Play sound");
soundCheckbox.setSelected(true);
controlPanel.add(activateButton);
controlPanel.add(soundCheckbox);
panel.add(inputPanel, BorderLayout.CENTER);
panel.add(controlPanel, BorderLayout.SOUTH);
// Nur Zahlen in den Textfeldern erlauben
DocumentFilter numberFilter = new DocumentFilter() {
@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
if (string.matches("\\d*")) {
super.insertString(fb, offset, string, attr);
}
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
if (text.matches("\\d*")) {
super.replace(fb, offset, length, text, attrs);
}
}
};
((AbstractDocument) hoursField.getDocument()).setDocumentFilter(numberFilter);
((AbstractDocument) minutesField.getDocument()).setDocumentFilter(numberFilter);
// Alarm Logik
AlarmLogic alarm = new AlarmLogic(hoursField, minutesField, activateButton, soundCheckbox);
activateButton.addActionListener(e -> alarm.toggleActivation());
return panel;
}
private static JPanel createNotesPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
// Erstellt das Textfeld
JTextArea notesArea = new JTextArea();
notesArea.setLineWrap(true);
notesArea.setWrapStyleWord(true);
notesArea.setFont(new Font("Arial", Font.PLAIN, 12));
// Fügt Scrollbalken hinzu
JScrollPane scrollPane = new JScrollPane(notesArea);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private static JPanel createTodoPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
// ToDo Liste
DefaultListModel<JCheckBox> todoListModel = new DefaultListModel<>();
JList<JCheckBox> todoList = new JList<>(todoListModel);
todoList.setCellRenderer(new CheckboxListCellRenderer());
todoList.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int index = todoList.locationToIndex(e.getPoint());
if (index >= 0) {
JCheckBox cb = todoListModel.getElementAt(index);
cb.setSelected(!cb.isSelected());
todoList.repaint();
}
}
});
// Input Panel für neue ToDos
JPanel inputPanel = new JPanel(new BorderLayout());
JTextField todoInput = new JTextField();
JButton addButton = new JButton("Add");
addButton.setPreferredSize(new Dimension(60, 25));
// Optional: Tooltip hinzufügen
addButton.setToolTipText("Add new todo item");
// Button zum Hinzufügen neuer ToDos
ActionListener addTodo = e -> {
String text = todoInput.getText().trim();
if (!text.isEmpty()) {
JCheckBox newTodo = new JCheckBox(text);
todoListModel.addElement(newTodo);
todoInput.setText("");
}
};
addButton.addActionListener(addTodo);
todoInput.addActionListener(addTodo); // Erlaubt Enter-Taste
inputPanel.add(todoInput, BorderLayout.CENTER);
inputPanel.add(addButton, BorderLayout.EAST);
// Button zum Entfernen erledigter ToDos
JButton clearButton = new JButton("Clear completed");
clearButton.addActionListener(e -> {
for (int i = todoListModel.size() - 1; i >= 0; i--) {
if (todoListModel.getElementAt(i).isSelected()) {
todoListModel.removeElementAt(i);
}
}
});
// Layout zusammensetzen
panel.add(new JScrollPane(todoList), BorderLayout.CENTER);
panel.add(inputPanel, BorderLayout.NORTH);
panel.add(clearButton, BorderLayout.SOUTH);
return panel;
}
private static class CheckboxListCellRenderer extends JCheckBox implements ListCellRenderer<JCheckBox> {
@Override
public Component getListCellRendererComponent(JList<? extends JCheckBox> list, JCheckBox value,
int index, boolean isSelected, boolean cellHasFocus) {
setSelected(value.isSelected());
setText(value.getText());
setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
return this;
}
}
private static void changeTitleDialog() {
String newTitle = JOptionPane.showInputDialog(frame,
"Neuen Titel eingeben:",
currentTitle);
if (newTitle != null) {
currentTitle = newTitle.trim();
updateWindowTitle();
}
}
private static void updateWindowTitle() {
if (currentTitle.isEmpty()) {
frame.setTitle(baseTitle);
} else {
frame.setTitle(baseTitle + " - " + currentTitle);
}
}
}
+200
View File
@@ -0,0 +1,200 @@
import javax.swing.*;
import java.util.List;
import java.util.ArrayList;
import java.awt.Color;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.awt.Font;
import java.awt.Dimension;
public class StopwatchLogic {
private JLabel timeLabel;
private JPanel timelinePanel;
private JButton startButton;
private Timer timer;
private long startTime;
private long elapsedTime;
private boolean isRunning;
private List<TimeMarker> timeMarkers;
// Angepasste Konstanten für kompakteres Layout
private static final int MIN_MARKER_DISTANCE = 70;
private static final int START_X = 20;
private static final int TIMELINE_HEIGHT = 65; // Reduziert von 75
private static final int LINE_Y = 25; // Höher positioniert (war 30)
private static final int ACTION_LABEL_Y = 3; // Höher positioniert (war 5)
private static final int TIME_LABEL_Y = 40; // Höher positioniert (war 48)
public StopwatchLogic(JLabel timeLabel, JPanel timelinePanel, JButton startButton) {
this.timeLabel = timeLabel;
this.timelinePanel = timelinePanel;
this.startButton = startButton;
this.timeMarkers = new ArrayList<>();
timer = new Timer(10, e -> {
if (isRunning) {
elapsedTime = System.currentTimeMillis() - startTime;
updateDisplay();
}
});
}
public void toggleStartStop() {
if (isRunning) {
timer.stop();
addTimeMarker("Pause");
startButton.setText("Start");
startButton.setBackground(new Color(76, 175, 80)); // Grün
} else {
if (elapsedTime == 0) {
startTime = System.currentTimeMillis();
addTimeMarker("Start");
} else {
startTime = System.currentTimeMillis() - elapsedTime;
addTimeMarker("Resume");
}
timer.start();
startButton.setText("Pause");
startButton.setBackground(new Color(255, 152, 0)); // Orange
}
isRunning = !isRunning;
}
public void reset() {
timer.stop();
isRunning = false;
elapsedTime = 0;
timeMarkers.clear();
startButton.setText("Start");
startButton.setBackground(new Color(76, 175, 80));
updateDisplay();
updateTimeline();
}
private void updateDisplay() {
long hours = (elapsedTime / 3600000);
long minutes = (elapsedTime / 60000) % 60;
long seconds = (elapsedTime / 1000) % 60;
timeLabel.setText(String.format("%02d:%02d:%02d", hours, minutes, seconds));
}
private void addTimeMarker(String action) {
TimeMarker marker = new TimeMarker(action, elapsedTime);
timeMarkers.add(marker);
updateTimeline();
}
private void updateTimeline() {
timelinePanel.removeAll();
int markerCount = timeMarkers.size();
int minWidth = timelinePanel.getParent().getWidth() - 40;
int requiredWidth = Math.max(minWidth, markerCount * MIN_MARKER_DISTANCE + 100);
int lastX = START_X;
for (int i = 0; i < timeMarkers.size(); i++) {
TimeMarker currentMarker = timeMarkers.get(i);
int x = START_X + (int)((currentMarker.time * (requiredWidth - 70)) / Math.max(elapsedTime, 1000));
if (x - lastX < MIN_MARKER_DISTANCE) {
x = lastX + MIN_MARKER_DISTANCE;
}
if (i % 2 == 0 && i < timeMarkers.size() - 1) {
TimeMarker nextMarker = timeMarkers.get(i + 1);
int nextX = START_X + (int)((nextMarker.time * (requiredWidth - 70)) / Math.max(elapsedTime, 1000));
nextX = Math.max(nextX, x + MIN_MARKER_DISTANCE);
// Grüner Block
JPanel timeBlock = new JPanel();
timeBlock.setBackground(new Color(76, 175, 80, 50));
timeBlock.setBounds(x, LINE_Y - 5, nextX - x, 10);
timelinePanel.add(timeBlock);
// Dauer-Label
long durationSeconds = (nextMarker.time - currentMarker.time) / 1000;
String durationText = formatDurationDetailed(durationSeconds);
JLabel durationLabel = new JLabel(durationText);
durationLabel.setHorizontalAlignment(SwingConstants.CENTER);
durationLabel.setFont(new Font("Arial", Font.PLAIN, 10));
int labelWidth = 70;
int labelX = x + (nextX - x) / 2 - labelWidth / 2;
durationLabel.setBounds(labelX, LINE_Y + 5, labelWidth, 15);
timelinePanel.add(durationLabel);
}
// Aktion-Label (über der Linie)
JLabel actionLabel = new JLabel(currentMarker.action);
actionLabel.setHorizontalAlignment(SwingConstants.CENTER);
actionLabel.setFont(new Font("Arial", Font.PLAIN, 11));
actionLabel.setBounds(x - 30, ACTION_LABEL_Y, 60, 20);
timelinePanel.add(actionLabel);
// Zeitstempel-Label (unter der Linie)
JLabel timeLabel = new JLabel(currentMarker.getClockTime());
timeLabel.setHorizontalAlignment(SwingConstants.CENTER);
timeLabel.setFont(new Font("Arial", Font.PLAIN, 11));
timeLabel.setBounds(x - 35, TIME_LABEL_Y, 70, 20);
timelinePanel.add(timeLabel);
// Vertikaler Strich
JPanel tick = new JPanel();
tick.setBackground(Color.BLACK);
tick.setBounds(x, LINE_Y - 5, 1, 10);
timelinePanel.add(tick);
lastX = x;
}
// Horizontale Linie
JPanel line = new JPanel();
line.setBackground(Color.GRAY);
line.setBounds(START_X, LINE_Y, requiredWidth - 40, 1);
timelinePanel.add(line);
timelinePanel.setPreferredSize(new Dimension(requiredWidth, TIMELINE_HEIGHT));
timelinePanel.revalidate();
timelinePanel.repaint();
}
// Neue detaillierte Formatierungsmethode
private String formatDurationDetailed(long seconds) {
if (seconds >= 3600) {
long hours = seconds / 3600;
long minutes = (seconds % 3600) / 60;
long secs = seconds % 60;
if (minutes > 0 || secs > 0) {
return String.format("%dh %02d:%02d", hours, minutes, secs);
}
return hours + "h";
} else if (seconds >= 60) {
long minutes = seconds / 60;
long secs = seconds % 60;
if (secs > 0) {
return String.format("%d:%02dmin", minutes, secs);
}
return minutes + "min";
} else {
return seconds + "s";
}
}
private static class TimeMarker {
private String action;
private long time;
private String clockTime;
public TimeMarker(String action, long time) {
this.action = action;
this.time = time;
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
this.clockTime = sdf.format(new Date());
}
public String getClockTime() {
return clockTime;
}
}
}