/
aleksandrazimut
/
TimerCountdownDesktop
Обзор
Документация
Войти
/
aleksandrazimut
/
TimerCountdownDesktop
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/main/java/com/timerapp/TimerApplication.java
189 строк
7 KB
Aleksandr Azimut
init commit
17 дек 2025, 21:59
17 дек 2025, 21:59
3c602f1
Код
Авторство
О чём код?
package com.timerapp; import javafx.application.Application; import javafx.application.Platform; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; import javafx.scene.text.Font; import javax.imageio.ImageIO; import java.io.InputStream; import java.awt.*; import java.net.URL; /** * Главный класс JavaFX приложения таймера */ public class TimerApplication extends Application { private SystemTray tray; private TrayIcon trayIcon; @Override public void start(Stage primaryStage) { // Инициализирует логирование в файл com.timerapp.util.LoggerUtil.initialize(); try { // Отключает неявный выход при закрытии последнего окна Platform.setImplicitExit(false); // Загружает FXML главного окна FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/main-view.fxml")); Parent root = loader.load(); // Загружает кастомные шрифты try { InputStream fontStream = getClass().getResourceAsStream("/fonts/RobotoSlab-Regular.ttf"); if (fontStream != null) { Font.loadFont(fontStream, 14); } InputStream centuryFontStream = getClass() .getResourceAsStream("/fonts/CenturyGothicPaneuropeanRegular.ttf"); if (centuryFontStream != null) { Font.loadFont(centuryFontStream, 14); } } catch (Exception e) { System.out.println("Не удалось загрузить шрифт: " + e.getMessage()); } // Убирает системный заголовок (белую полоску) primaryStage.initStyle(javafx.stage.StageStyle.UNDECORATED); // Создает сцену с заданным размером (360x175) Scene scene = new Scene(root, 360, 175); // Подключает CSS стили String css = getClass().getResource("/css/styles.css").toExternalForm(); scene.getStylesheets().add(css); // Настраивает окно primaryStage.setTitle("Desktop Timer"); primaryStage.setScene(scene); primaryStage.setResizable(false); // Логика перетаскивания окна final Delta dragDelta = new Delta(); scene.setOnMousePressed(mouseEvent -> { dragDelta.x = primaryStage.getX() - mouseEvent.getScreenX(); dragDelta.y = primaryStage.getY() - mouseEvent.getScreenY(); }); scene.setOnMouseDragged(mouseEvent -> { primaryStage.setX(mouseEvent.getScreenX() + dragDelta.x); primaryStage.setY(mouseEvent.getScreenY() + dragDelta.y); }); // Устанавливает иконку приложения try { InputStream iconStream = getClass().getResourceAsStream("/icons/timer-icon.png"); if (iconStream != null) { primaryStage.getIcons().add(new Image(iconStream)); } } catch (Exception e) { // ignore } // Настраивает системный трей if (SystemTray.isSupported()) { createTrayIcon(primaryStage); } // Обработка закрытия окна primaryStage.setOnCloseRequest(event -> { if (SystemTray.isSupported()) { // Отменяет закрытие и скрываем в трей event.consume(); primaryStage.hide(); // Показывает уведомление (опционально) // if (trayIcon != null) trayIcon.displayMessage("Desktop Timer", "Приложение // свернуто в трей", TrayIcon.MessageType.INFO); } else { // Если трей не поддерживается, выходим полностью Platform.exit(); System.exit(0); } }); // Добавляет shutdown hook для корректного закрытия лог файла Runtime.getRuntime().addShutdownHook(new Thread(() -> { com.timerapp.util.LoggerUtil.shutdown(); })); primaryStage.show(); } catch (Exception e) { com.timerapp.util.LoggerUtil.error("Ошибка запуска приложения", e); System.err.println("Ошибка запуска приложения: " + e.getMessage()); e.printStackTrace(); } } private void createTrayIcon(Stage stage) { try { Toolkit.getDefaultToolkit(); tray = SystemTray.getSystemTray(); // Загружает картинку для трея (используем AWT Image) URL imageUrl = getClass().getResource("/icons/timer-icon.png"); if (imageUrl == null) { System.err.println("Иконка для трея не найдена!"); return; } java.awt.Image image = ImageIO.read(imageUrl); // Ресайз иконки для трея (обычно 16x16) int trayIconWidth = new TrayIcon(image).getSize().width; if (trayIconWidth > 0) { // Если удалось определить размер image = image.getScaledInstance(trayIconWidth, -1, java.awt.Image.SCALE_SMOOTH); } else { // Fallback image = image.getScaledInstance(16, 16, java.awt.Image.SCALE_SMOOTH); } trayIcon = new TrayIcon(image, "Desktop Timer"); trayIcon.setImageAutoSize(true); // Действие по двойному клику - открыть trayIcon.addActionListener(e -> Platform.runLater(() -> { stage.show(); stage.toFront(); })); // Меню трея PopupMenu popup = new PopupMenu(); MenuItem openItem = new MenuItem("Открыть"); openItem.addActionListener(e -> Platform.runLater(() -> { stage.show(); stage.toFront(); })); MenuItem exitItem = new MenuItem("Выход"); exitItem.addActionListener(e -> { com.timerapp.util.LoggerUtil.shutdown(); tray.remove(trayIcon); Platform.exit(); System.exit(0); }); popup.add(openItem); popup.addSeparator(); popup.add(exitItem); trayIcon.setPopupMenu(popup); tray.add(trayIcon); } catch (Exception e) { System.err.println("Не удалось создать иконку в трее: " + e.getMessage()); } } public static void main(String[] args) { launch(args); } }