Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions textshot/history_window.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""
历史记录侧边窗:保存最近 N 条 OCR 文本
"""
from collections import deque
from PyQt5.QtWidgets import QMainWindow, QListWidget, QListWidgetItem
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
import pyperclip
from .result_dialog import ResultDialog

MAX_HISTORY = 20


class HistoryWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("OCR 历史")
self.resize(300, 400)
self.list_widget = QListWidget()
self.setCentralWidget(self.list_widget)
self.history = deque(maxlen=MAX_HISTORY) # 左边索引 0 是最新

# 双击查看
self.list_widget.itemDoubleClicked.connect(self.open_record)

# 美化
font = QFont()
font.setPointSize(10)
self.list_widget.setFont(font)

# ------ 对外接口 ------
def add_record(self, text: str):
self.history.appendleft(text)
self.refresh_ui()

# ------ 私有 ------
def refresh_ui(self):
self.list_widget.clear()
for idx, t in enumerate(self.history):
preview = (t[:40] + "…") if len(t) > 40 else t
self.list_widget.addItem(f"{idx + 1}. {preview}")

def open_record(self, item: QListWidgetItem):
idx = int(item.text().split(".")[0]) - 1
full_text = self.history[idx]
pyperclip.copy(full_text)
dlg = ResultDialog(full_text, self.add_record, self)
dlg.exec()
64 changes: 64 additions & 0 deletions textshot/result_dialog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""
结果弹窗:显示 OCR 文本 + 复制 / 翻译 / 朗读
"""
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QTextEdit,
QPushButton, QHBoxLayout, QMessageBox, QApplication)
from PyQt5.QtCore import Qt
import pyperclip
from googletrans import Translator
import pyttsx3


class ResultDialog(QDialog):
def __init__(self, text: str, history_cb, parent=None):
super().__init__(parent)
self.setWindowTitle("TextShot – OCR 结果")
self.resize(500, 340)
self.setWindowModality(Qt.WindowModality.ApplicationModal)

self.text = text
self.history_cb = history_cb # 回调:写入历史

# ========= UI =========
edit = QTextEdit(readOnly=True)
edit.setPlainText(text)

btn_copy = QPushButton("复制")
btn_copy.clicked.connect(self.copy_text)

btn_translate = QPushButton("翻译")
btn_translate.clicked.connect(self.translate_text)

btn_speak = QPushButton("朗读")
btn_speak.clicked.connect(self.speak_text)

h = QHBoxLayout()
for b in (btn_copy, btn_translate, btn_speak):
h.addWidget(b)
h.addStretch()

v = QVBoxLayout(self)
v.addWidget(edit)
v.addLayout(h)

# 首次打开即写入历史
self.history_cb(text)

# ---------- 功能 ----------
def copy_text(self):
pyperclip.copy(self.text)

def translate_text(self):
try:
res = Translator().translate(self.text, dest="zh-cn").text
QMessageBox.information(self, "翻译结果", res)
except Exception as e:
QMessageBox.warning(self, "翻译失败", str(e))

def speak_text(self):
try:
engine = pyttsx3.init()
engine.say(self.text)
engine.runAndWait()
except Exception as e:
QMessageBox.warning(self, "朗读失败", str(e))
16 changes: 16 additions & 0 deletions textshot/textshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
import sys

import pyperclip
from .history_window import HistoryWindow
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QTimer

from .logger import log_copied, log_ocr_failure
from .notifications import notify_copied, notify_ocr_failure
from .ocr import ensure_tesseract_installed, get_ocr_result

_history_win = None # 单例历史窗口

class Snipper(QtWidgets.QWidget):
def __init__(self, parent, langs=None, flags=Qt.WindowFlags()):
Expand Down Expand Up @@ -100,7 +102,21 @@ def mouseReleaseEvent(self, event):
return super().mouseReleaseEvent(event)

ocr_result = self.snipOcr()
# if ocr_result:
# pyperclip.copy(ocr_result)
# log_copied(ocr_result)
# notify_copied(ocr_result)
if ocr_result:
# ---------- 弹窗 ----------
from .result_dialog import ResultDialog
global _history_win # 单例
if _history_win is None:
_history_win = HistoryWindow()
_history_win.show() # 模态外常驻
dlg = ResultDialog(ocr_result, _history_win.add_record)
dlg.exec()

# ---------- 原有逻辑 ----------
pyperclip.copy(ocr_result)
log_copied(ocr_result)
notify_copied(ocr_result)
Expand Down