
with two activated checkboxes autostart and start minimized the program becomes white when unfolding from the tray, help to fix the problem, because autostart works, but start minimized does not work, also tell me how to fix the fact that when closing the program it continues to work, here is the program code
import configparser
import ctypes
import os
import subprocess
import sys
from datetime import datetime
from PySide6.QtCore import QTimer, Qt, QThread, Signal
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QWidget,
QVBoxLayout,
QHBoxLayout,
QLabel,
QLineEdit,
QPushButton,
QTableWidget,
QTableWidgetItem,
QHeaderView,
QCheckBox,
QSystemTrayIcon,
QMenu,
QFileDialog,
QMessageBox,
)
from qdarkstyle import load_stylesheet_pyside6
from screeninfo import get_monitors
class CheckboxUpdateThread(QThread):
checkbox_states_updated = Signal()
def run(self):
while not self.isInterruptionRequested():
self.checkbox_states_updated.emit()
self.msleep(1000)
class WallpaperTimeApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("WallpaperTime")
self.setWindowIcon(QIcon("icon.png"))
self.setGeometry(100, 100, 1280, 720)
# Change the current working directory
os.chdir(os.path.dirname(sys.argv[0]))
self.checkboxes = []
# Tray setup
self.tray_icon = QSystemTrayIcon(self)
self.tray_icon.setIcon(QIcon("icon.png"))
self.tray_menu = QMenu(self)
self.tray_action_show = self.tray_menu.addAction("Show")
self.tray_action_exit = self.tray_menu.addAction("Exit")
self.tray_icon.setContextMenu(self.tray_menu)
self.tray_icon.show()
# Load settings from file
self.config = configparser.ConfigParser()
self.load_settings()
# Start the checkbox update thread
self.checkbox_update_thread = CheckboxUpdateThread(self)
self.checkbox_update_thread.checkbox_states_updated.connect(self.load_settings)
self.checkbox_update_thread.start()
# Tray icon click event
self.tray_icon.activated.connect(self.handle_tray_icon_activated)
# Timer to update wallpaper
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_wallpaper)
# Initialize intervals
self.intervals = []
self.load_intervals()
# UI setup
self.central_widget = QWidget(self)
self.setCentralWidget(self.central_widget)
self.interval_table = QTableWidget(self)
self.interval_table.setColumnCount(3)
self.interval_table.setHorizontalHeaderLabels(
["Start Time", "End Time", "Wallpaper Path"]
)
self.interval_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.interval_table.setEditTriggers(QTableWidget.NoEditTriggers)
self.update_interval_table()
self.start_time_input = QLineEdit(self)
self.end_time_input = QLineEdit(self)
self.wallpaper_path_input = QLineEdit(self)
self.wallpaper_path_button = QPushButton("Select Wallpaper", self)
self.wallpaper_path_button.clicked.connect(self.select_wallpaper)
self.add_button = QPushButton("Add", self)
self.add_button.clicked.connect(self.add_interval)
self.edit_button = QPushButton("Edit", self)
self.edit_button.clicked.connect(self.edit_interval)
self.delete_button = QPushButton("Delete", self)
self.delete_button.clicked.connect(self.delete_interval)
self.autostart_checkbox = QCheckBox("Autostart", self)
self.autostart_checkbox.stateChanged.connect(self.toggle_autostart)
self.checkboxes.append(self.autostart_checkbox)
self.start_minimized_checkbox = QCheckBox("Start Minimized", self)
self.start_minimized_checkbox.stateChanged.connect(self.toggle_start_minimized)
self.checkboxes.append(self.start_minimized_checkbox)
self.minimize_button = QPushButton("Minimize", self)
self.minimize_button.clicked.connect(self.handle_minimize_button_clicked)
self.minimize_button.setEnabled(True)
# Status label for visualization
self.status_label = QLabel(self)
self.status_label.setAlignment(Qt.AlignCenter)
# Rename the method to avoid conflict
self.main_layout = QVBoxLayout(self.central_widget)
self.main_layout.addWidget(self.interval_table)
form_layout = QHBoxLayout()
form_layout.addWidget(QLabel("Start Time:"))
form_layout.addWidget(self.start_time_input)
form_layout.addWidget(QLabel("End Time:"))
form_layout.addWidget(self.end_time_input)
form_layout.addWidget(QLabel("Wallpaper Path:"))
form_layout.addWidget(self.wallpaper_path_input)
form_layout.addWidget(self.wallpaper_path_button)
self.main_layout.addLayout(form_layout)
button_layout = QHBoxLayout()
button_layout.addWidget(self.add_button)
button_layout.addWidget(self.edit_button)
button_layout.addWidget(self.delete_button)
button_layout.addWidget(self.autostart_checkbox)
button_layout.addWidget(self.start_minimized_checkbox)
button_layout.addWidget(self.minimize_button)
self.main_layout.addLayout(button_layout)
self.main_layout.addWidget(self.status_label)
# Set the style sheet
self.setStyleSheet(load_stylesheet_pyside6())
# Show the window
self.show()
def update_checkbox_states(self):
for checkbox in self.checkboxes:
checkbox_name = checkbox.text().replace(" ", "").lower()
if self.config.has_option("General", checkbox_name):
checkbox_state = self.config.getboolean("General", checkbox_name)
checkbox.setChecked(checkbox_state)
def update_interval_table(self):
self.interval_table.clearContents()
self.interval_table.setRowCount(0)
for i, (start_time, end_time, wallpaper_path) in enumerate(self.intervals):
self.interval_table.insertRow(i)
self.interval_table.setItem(i, 0, QTableWidgetItem(start_time))
self.interval_table.setItem(i, 1, QTableWidgetItem(end_time))
self.interval_table.setItem(i, 2, QTableWidgetItem(wallpaper_path))
def load_settings(self):
config = configparser.ConfigParser()
config.read("settings.ini")
if config.has_section("Intervals"):
self.intervals = []
for key, value in config.items("Intervals"):
start_time, end_time, wallpaper_path = value.split(",")
self.intervals.append((start_time, end_time, wallpaper_path))
if config.has_section("General"):
for checkbox in self.checkboxes:
checkbox_name = checkbox.text().replace(" ", "").lower()
if config.has_option("General", checkbox_name):
checkbox_state = config.getboolean("General", checkbox_name)
checkbox.setChecked(checkbox_state)
checkbox.update() # Update the checkbox display
def save_settings(self):
config = configparser.ConfigParser()
if not config.has_section("Intervals"):
config.add_section("Intervals")
for i, (start_time, end_time, wallpaper_path) in enumerate(self.intervals):
config.set(
"Intervals", f"interval{i}", f"{start_time},{end_time},{wallpaper_path}"
)
if not config.has_section("General"):
config.add_section("General")
for checkbox in self.checkboxes:
checkbox_name = checkbox.text().replace(" ", "").lower()
config.set("General", checkbox_name, str(checkbox.isChecked()))
with open("settings.ini", "w") as config_file:
config.write(config_file)
def load_intervals(self):
config = configparser.ConfigParser()
config.read("settings.ini")
if config.has_section("Intervals"):
self.intervals = []
for key in config["Intervals"]:
start_time, end_time, wallpaper_path = config["Intervals"][key].split(
","
)
self.intervals.append((start_time, end_time, wallpaper_path))
def handle_tray_icon_activated(self, reason):
if reason == QSystemTrayIcon.Trigger:
self.showNormal() # Use showNormal() to restore the window
self.tray_icon.hide()
def handle_minimize_button_clicked(self):
self.hide()
self.tray_icon.show()
def add_interval(self):
start_time = self.start_time_input.text()
end_time = self.end_time_input.text()
wallpaper_path = self.wallpaper_path_input.text()
if not start_time or not end_time or not wallpaper_path:
QMessageBox.critical(
self, "Error", "Please fill in all fields before adding an interval."
)
return
if not self.validate_time_format(start_time) or not self.validate_time_format(
end_time
):
QMessageBox.critical(
self, "Error", "Invalid time format. Please use HH:MM format."
)
return
self.intervals.append((start_time, end_time, wallpaper_path))
self.update_interval_table()
self.save_settings()
def validate_time_format(self, time_str):
try:
datetime.strptime(time_str, "%H:%M")
return True
except ValueError:
return False
def edit_interval(self):
selected_row = self.interval_table.currentRow()
if selected_row != -1:
start_time = self.start_time_input.text()
end_time = self.end_time_input.text()
wallpaper_path = self.wallpaper_path_input.text()
if not start_time or not end_time or not wallpaper_path:
QMessageBox.critical(
self,
"Error",
"Please fill in all fields before editing the interval.",
)
return
if not self.validate_time_format(
start_time
) or not self.validate_time_format(end_time):
QMessageBox.critical(
self, "Error", "Invalid time format. Please use HH:MM format."
)
return
self.intervals[selected_row] = (start_time, end_time, wallpaper_path)
self.update_interval_table()
self.save_settings()
def delete_interval(self):
selected_row = self.interval_table.currentRow()
if selected_row != -1:
del self.intervals[selected_row]
self.update_interval_table()
self.save_settings()
def toggle_start_minimized(self):
start_minimized = self.start_minimized_checkbox.isChecked() # noqa: F841
self.save_settings() # Move the save_settings() call here
def create_autostart_entry(self):
script_path = os.path.abspath(sys.argv[0])
key_path = r"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run"
key_name = "WallpaperTime"
value = f'"{script_path}"'
try:
subprocess.run(
["reg", "add", key_path, "/v", key_name, "/d", value, "/f"], check=True
)
except subprocess.CalledProcessError as e:
print("Error creating autostart entry:", e)
def remove_autostart_entry(self):
key_path = r"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run"
key_name = "WallpaperTime"
try:
subprocess.run(
["reg", "delete", key_path, "/v", key_name, "/f"], check=True
)
except subprocess.CalledProcessError as e:
print("Error removing autostart entry:", e)
def toggle_autostart(self):
autostart_enabled = self.autostart_checkbox.isChecked()
if autostart_enabled:
self.create_autostart_entry()
if self.start_minimized_checkbox.isChecked():
self.handle_minimize_button_clicked()
else:
self.remove_autostart_entry()
self.save_settings() # Save settings after creating/removing autostart entry
def showEvent(self, event):
self.tray_icon.hide()
# Start the timer when the application is shown
self.timer.start(6000)
# Check if started from autostart and should be minimized
autostart_enabled = self.autostart_checkbox.isChecked()
start_minimized = self.start_minimized_checkbox.isChecked()
if autostart_enabled and start_minimized:
self.hide()
self.tray_icon.show()
else:
self.showNormal()
def is_between_times(self, current_time, start_time, end_time):
if start_time <= end_time:
return start_time <= current_time <= end_time
else:
return current_time >= start_time or current_time <= end_time
def update_wallpaper(self):
current_time = datetime.now().time()
wallpaper_path = None
for start_time, end_time, path in self.intervals:
start_time = datetime.strptime(start_time, "%H:%M").time()
end_time = datetime.strptime(end_time, "%H:%M").time()
if self.is_between_times(current_time, start_time, end_time):
wallpaper_path = path
break
if wallpaper_path:
try:
self.set_wallpaper(wallpaper_path)
self.status_label.setText(f"Wallpaper updated at {datetime.now().strftime('%H:%M:%S')}")
except Exception as e:
self.status_label.setText(f"Error updating wallpaper: {e}")
else:
self.status_label.setText("No wallpaper set for the current time.")
return
# Convert the wallpaper path to a format compatible with SystemParametersInfo function
wallpaper_path = os.path.abspath(path)
# Set the wallpaper
SPI_SETDESKWALLPAPER = 20
ctypes.windll.user32.SystemParametersInfoW(
SPI_SETDESKWALLPAPER, 0, wallpaper_path, 3
)
def set_wallpaper(self, path):
# Check if the file exists
if not os.path.exists(path):
self.status_label.setText(f"Error: The wallpaper file '{path}' does not exist.")
return
# Convert the wallpaper path to a format compatible with SystemParametersInfo function
wallpaper_path = os.path.abspath(path)
# Set the wallpaper for all monitors
SPI_SETDESKWALLPAPER = 20
for monitor in get_monitors():
ctypes.windll.user32.SystemParametersInfoW(
SPI_SETDESKWALLPAPER, 0, wallpaper_path, 3
)
def select_wallpaper(self):
options = QFileDialog.Options()
file_path, _ = QFileDialog.getOpenFileName(
self,
"Select Wallpaper",
"",
"Images (*.jpg *.png *.jpeg);;All Files (*)",
options=options,
)
if file_path:
self.wallpaper_path_input.setText(file_path)
def closeEvent(self, event):
self.tray_icon.hide()
self.timer.stop()
self.save_settings()
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setStyle("Fusion")
app.setStyleSheet("QMainWindow::title { background-color: rgb(120, 120, 120); }")
os.chdir(os.path.dirname(sys.argv[0]))
if not os.path.exists("icon.png"):
print(
"The icon.png file is missing. Please place it in the same directory as the script."
)
sys.exit(1)
window = WallpaperTimeApp()
window.show()
sys.exit(app.exec())
I've tried many ways, but all of them either fail or make the program window invisible