From 14df1969c97c9caba4b1dfce168c47ee038e2aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=A8=E5=B0=8F=E9=80=8F=E6=98=8E=E3=83=BB=E5=AE=B8?= =?UTF-8?q?=E2=9C=A8?= <47057319+TransparentLC@users.noreply.github.com> Date: Fri, 23 Feb 2024 16:54:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9A=82=E5=81=9C=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Close #64 --- i18n.ini | 8 ++++++++ main.py | 34 ++++++++++++++++++++++++++++++---- task.py | 3 +++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/i18n.ini b/i18n.ini index 0ed8ecd..79e24eb 100644 --- a/i18n.ini +++ b/i18n.ini @@ -8,6 +8,8 @@ ResizeModeRatio = 固定倍率 ResizeModeWidth = 等比放大到宽度 ResizeModeHeight = 等比放大到高度 StartProcessing = 开始 +PauseProcessing = 暂停 +ContinueProcessing = 继续 DownsampleMode = 降采样方式 UsedGPUID = 使用的 GPU ID(-1 为自动选择) TileSize = 拆分大小 @@ -50,6 +52,8 @@ ResizeModeRatio = 固定倍率 ResizeModeWidth = 等比放大到寬度 ResizeModeHeight = 等比放大到高度 StartProcessing = 開始 +PauseProcessing = 暫停 +ContinueProcessing = 繼續 DownsampleMode = 降採樣方式 UsedGPUID = 使用的 GPU ID(-1 為自動選擇) TileSize = 拆分大小 @@ -92,6 +96,8 @@ ResizeModeRatio = 固定倍率 ResizeModeWidth = 等比放大到寬度 ResizeModeHeight = 等比放大到高度 StartProcessing = 開始 +PauseProcessing = 暫停 +ContinueProcessing = 繼續 DownsampleMode = 降採樣方式 UsedGPUID = 使用的 GPU ID(-1 為自動選擇) TileSize = 拆分大小 @@ -134,6 +140,8 @@ ResizeModeRatio = Ratio ResizeModeWidth = Scale to width ResizeModeHeight = Scale to height StartProcessing = Start +PauseProcessing = Pause +ContinueProcessing = Continue DownsampleMode = Downsampling algorithm UsedGPUID = GPU ID (Use -1 for auto select) TileSize = Tile size diff --git a/main.py b/main.py index e5868c2..d212438 100644 --- a/main.py +++ b/main.py @@ -105,6 +105,8 @@ def __init__(self, parent: tk.Tk, config: configparser.ConfigParser, modelFiles: self.progressValue: list[int | float] = [0, 0, 1] # 初始值/结束值/进度/after ID self.progressAnimation: list[float | str] = [0, 0, 0, None] + # 控制是否暂停 + self.pauseEvent = threading.Event() self.setupVars() self.setupWidgets() @@ -136,6 +138,8 @@ def outputPathTraceCallback(var: tk.IntVar | tk.StringVar, index: str, mode: str self.varboolOptimizeGIF = tk.BooleanVar(value=self.config['Config'].getboolean('OptimizeGIF')) self.varboolLossyMode = tk.BooleanVar(value=self.config['Config'].getboolean('LossyMode')) self.varboolIgnoreError = tk.BooleanVar(value=self.config['Config'].getboolean('IgnoreError')) + self.varboolProcessing = tk.BooleanVar(value=False) + self.varboolProcessingPaused = tk.BooleanVar(value=False) self.varstrCustomCommand = tk.StringVar(value=self.config['Config'].get('CustomCommand')) self.varintLossyQuality = tk.IntVar(value=self.config['Config'].getint('LossyQuality')) self.vardoubleProgress = tk.DoubleVar(value=0) @@ -149,7 +153,7 @@ def outputPathTraceCallback(var: tk.IntVar | tk.StringVar, index: str, mode: str self.varstrLabelResizeModeRatio = tk.StringVar(value=i18n.getTranslatedString('ResizeModeRatio')) self.varstrLabelResizeModeWidth = tk.StringVar(value=i18n.getTranslatedString('ResizeModeWidth')) self.varstrLabelResizeModeHeight = tk.StringVar(value=i18n.getTranslatedString('ResizeModeHeight')) - self.varstrLabelStartProcessing = tk.StringVar(value=i18n.getTranslatedString('StartProcessing')) + self.varstrLabelStartProcessing = tk.StringVar(value=i18n.getTranslatedString(('ContinueProcessing' if self.varboolProcessingPaused.get() else 'PauseProcessing') if self.varboolProcessing.get() else 'StartProcessing')) self.varstrLabelDownsampleMode = tk.StringVar(value=i18n.getTranslatedString('DownsampleMode')) self.varstrLabelTileSize = tk.StringVar(value=i18n.getTranslatedString('TileSize')) self.varstrLabelTileSizeAuto = tk.StringVar(value=i18n.getTranslatedString('TileSizeAuto')) @@ -324,7 +328,7 @@ def change_app_lang(self, event: tk.Event): self.varstrLabelResizeModeRatio.set(i18n.getTranslatedString('ResizeModeRatio')) self.varstrLabelResizeModeWidth.set(i18n.getTranslatedString('ResizeModeWidth')) self.varstrLabelResizeModeHeight.set(i18n.getTranslatedString('ResizeModeHeight')) - self.varstrLabelStartProcessing.set(i18n.getTranslatedString('StartProcessing')) + self.varstrLabelStartProcessing.set(i18n.getTranslatedString(('ContinueProcessing' if self.varboolProcessingPaused.get() else 'PauseProcessing') if self.varboolProcessing.get() else 'StartProcessing')) self.varstrLabelDownsampleMode.set(i18n.getTranslatedString('DownsampleMode')) self.varstrLabelTileSize.set(i18n.getTranslatedString('TileSize')) @@ -393,6 +397,17 @@ def comboTileSize_click(self, event: tk.Event): self.varintTileSizeIndex.set(self.comboTileSize.current()) def buttonProcess_click(self): + if self.varboolProcessing.get(): + if self.varboolProcessingPaused.get(): + self.varboolProcessingPaused.set(False) + self.pauseEvent.set() + else: + self.varboolProcessingPaused.set(True) + self.pauseEvent.clear() + self.writeToOutput('Will pause after current task is completed.\n') + self.buttonProcess.config(style='' if self.varboolProcessing.get() and not self.varboolProcessingPaused.get() else 'Accent.TButton') + self.varstrLabelStartProcessing.set(i18n.getTranslatedString(('ContinueProcessing' if self.varboolProcessingPaused.get() else 'PauseProcessing') if self.varboolProcessing.get() else 'StartProcessing')) + return try: inputPath = self.varstrInputPath.get() outputPath = self.varstrOutputPath.get() @@ -461,7 +476,11 @@ def buttonProcess_click(self): queue.append(task.RESpawnTask(self.writeToOutput, self.progressValue, inputPath, outputPath, initialConfigParams)) else: return messagebox.showwarning(define.APP_TITLE, i18n.getTranslatedString('WarningInvalidFormat')) - self.buttonProcess.config(state=tk.DISABLED) + self.varboolProcessing.set(True) + self.varboolProcessingPaused.set(False) + self.pauseEvent.set() + self.buttonProcess.config(style='' if self.varboolProcessing.get() and not self.varboolProcessingPaused.get() else 'Accent.TButton') + self.varstrLabelStartProcessing.set(i18n.getTranslatedString(('ContinueProcessing' if self.varboolProcessingPaused.get() else 'PauseProcessing') if self.varboolProcessing.get() else 'StartProcessing')) self.textOutput.config(state=tk.NORMAL) self.textOutput.delete(1.0, tk.END) self.textOutput.config(state=tk.DISABLED) @@ -496,10 +515,17 @@ def failCallback(ex: Exception): target=task.taskRunner, args=( queue, + self.pauseEvent, self.writeToOutput, completeCallback, failCallback, - lambda: (self.buttonProcess.config(state=tk.NORMAL), self.logFile.close()), + lambda: ( + self.varboolProcessing.set(False), + self.pauseEvent.set(), + self.buttonProcess.config(style='' if self.varboolProcessing.get() and not self.varboolProcessingPaused.get() else 'Accent.TButton'), + self.varstrLabelStartProcessing.set(i18n.getTranslatedString(('ContinueProcessing' if self.varboolProcessingPaused.get() else 'PauseProcessing') if self.varboolProcessing.get() else 'StartProcessing')), + self.logFile.close(), + ), self.varboolIgnoreError.get(), ) ) diff --git a/task.py b/task.py index 58fd672..127469c 100644 --- a/task.py +++ b/task.py @@ -8,6 +8,7 @@ import shutil import tempfile import time +import threading import traceback import typing from PIL import Image @@ -308,6 +309,7 @@ def run(self) -> None: def taskRunner( queue: collections.deque[AbstractTask], + pauseEvent: threading.Event, outputCallback: typing.Callable[[str], None], completeCallback: typing.Callable[[bool], None], failCallback: typing.Callable[[Exception], None], @@ -318,6 +320,7 @@ def taskRunner( withError = False while queue: try: + pauseEvent.wait() ts = time.perf_counter() queue.popleft().run() te = time.perf_counter()