From c2427efb422ab61dc13ae50614f0f938feb994f0 Mon Sep 17 00:00:00 2001 From: zhaoyafan Date: Sat, 19 Oct 2024 16:58:07 +0800 Subject: [PATCH] 20241019165800 --- main.py | 112 +++++++++++++++++++++++++++++++++++++++++++---------- rules.json | 96 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 21 deletions(-) diff --git a/main.py b/main.py index e0faa86..58a7bd5 100644 --- a/main.py +++ b/main.py @@ -13,12 +13,12 @@ import pywintypes import hashlib import win32com.client import win32print -from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QLabel, QComboBox, QCheckBox, QLineEdit, QAction, QMenu, QMessageBox, QPushButton, QVBoxLayout, QHBoxLayout, QFileDialog -from PyQt5.QtCore import Qt, QCoreApplication +from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QLabel, QComboBox, QCheckBox, QLineEdit, QAction, QMenu, \ + QMessageBox, QPushButton, QVBoxLayout, QHBoxLayout, QFileDialog, QDialog +from PyQt5.QtCore import Qt, QCoreApplication, QTimer, QPropertyAnimation from PyQt5.QtGui import QPixmap, QIntValidator from threading import RLock - sys.path.append(os.path.dirname(__file__)) clr.AddReference('BarTender') try: @@ -93,12 +93,14 @@ if os.name == 'nt': PVOID = c_void_p + class _OFFSET(Structure): _fields_ = [ ('Offset', DWORD), ('OffsetHigh', DWORD) ] + class _OFFSET_UNION(Union): _fields_ = [ ('_offset', _OFFSET), @@ -106,6 +108,7 @@ if os.name == 'nt': ] _anonymous_ = ['_offset'] + class OVERLAPPED(Structure): _fields_ = [ ('Internal', ULONG_PTR), @@ -115,6 +118,7 @@ if os.name == 'nt': ] _anonymous_ = ['_offset_union'] + LPOVERLAPPED = POINTER(OVERLAPPED) LockFileEx = windll.kernel32.LockFileEx LockFileEx.restype = BOOL @@ -148,6 +152,7 @@ if os.name == 'nt': else: try: import fcntl + LOCK_SH = fcntl.LOCK_SH LOCK_NB = fcntl.LOCK_NB LOCK_EX = fcntl.LOCK_EX @@ -155,6 +160,7 @@ else: except (ImportError, AttributeError): LOCK_EX = LOCK_SH = LOCK_NB = 0 + def flock(f, flags): return flags == LOCK_UN else: @@ -454,10 +460,13 @@ class BarTenderPrint: self.bt_format.PrintOut(False, False) def generate_preview(self): - path = os.path.abspath(os.path.join(tempfile.gettempdir(), '%s%s.png' % ('preview_', int(round(time.time() * 1000))))) + path = os.path.abspath( + os.path.join(tempfile.gettempdir(), '%s%s.png' % ('preview_', int(round(time.time() * 1000))))) if (self.bt_format is not None) == 1: self.logger.i('%s%s' % ('Generate preview to ', path)) - self.bt_format.ExportToFile(path, 'PNG', BarTender.BtColors.btColors24Bit, BarTender.BtResolution.btResolutionPrinter, BarTender.BtSaveOptions.btDoNotSaveChanges) + self.bt_format.ExportToFile(path, 'PNG', BarTender.BtColors.btColors24Bit, + BarTender.BtResolution.btResolutionPrinter, + BarTender.BtSaveOptions.btDoNotSaveChanges) return path def quit(self): @@ -518,7 +527,8 @@ class CustomPushButton(QPushButton): class CustomLabel(QLabel): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.setStyleSheet('font-size: 12px; font-family: \'Microsoft YaHei\'; color: #0C0C0C; border: 1px solid #0C0C0C;') + self.setStyleSheet( + 'font-size: 12px; font-family: \'Microsoft YaHei\'; color: #0C0C0C; border: 1px solid #0C0C0C;') class CustomComboBox(QComboBox): @@ -549,12 +559,17 @@ class MainWindow(QMainWindow): def __init__(self, logger: Logger): super().__init__() self.app_name = '标签打印' - self.app_version = ('1.0.3', '20240810', 'zhaoyafan', 'zhaoyafan@foxmail.com', 'https://www.fanscloud.net/') + self.app_version = ('1.0.4', '20241019', 'zhaoyafan', 'zhaoyafan@foxmail.com', 'https://www.fanscloud.net/') self.logger = logger - self.setting = Setting(os.path.abspath(os.path.join(tempfile.gettempdir(), '%s.config' % self.md5(__file__)[:16])), {}) + self.toast = ToastNotification() + self.setting = Setting( + os.path.abspath(os.path.join(tempfile.gettempdir(), '%s.config' % self.md5(__file__)[:16])), {}) self.bt = BarTenderPrint(logger=self.logger) - self.sv = ScanVerify(logger=self.logger, rule_file=os.path.abspath(os.path.join(os.path.dirname(__file__), 'rules.json'))) - self.ditto = Ditto(db_file=os.path.abspath(os.path.join(tempfile.gettempdir(), '%s.db' % self.md5(__file__)[:16])), class_name='LabelPrint', limit_time=7776000, limit_rows=100000) + self.sv = ScanVerify(logger=self.logger, + rule_file=os.path.abspath(os.path.join(os.path.dirname(__file__), 'rules.json'))) + self.ditto = Ditto( + db_file=os.path.abspath(os.path.join(tempfile.gettempdir(), '%s.db' % self.md5(__file__)[:16])), + class_name='LabelPrint', limit_time=7776000, limit_rows=100000) self.last_opened_template = ['', ''] self.input_convert_letter = 0 self.input_scan_prohibited_enter = 0 @@ -666,7 +681,8 @@ class MainWindow(QMainWindow): r_layout_2.addWidget(self.chkDET) # Scan self.edtSCN = CustomLineEdit('') - self.edtSCN.setStyleSheet('QLineEdit {font-size: 28px; font-family: \'Microsoft YaHei\'; color: #000000; background-color: #FFFFCC;}') + self.edtSCN.setStyleSheet( + 'QLineEdit {font-size: 28px; font-family: \'Microsoft YaHei\'; color: #000000; background-color: #FFFFCC;}') self.edtSCN.setFixedSize(455, 45) r_layout_3.addWidget(self.edtSCN) # Print button @@ -683,7 +699,8 @@ class MainWindow(QMainWindow): self.setFixedSize(self.minimumSizeHint()) screen_rect = QApplication.desktop().availableGeometry() window_rect = self.geometry() - self.move(int((screen_rect.width() - window_rect.width()) * 0.5), int((screen_rect.height() - window_rect.height()) * 0.5)) + self.move(int((screen_rect.width() - window_rect.width()) * 0.5), + int((screen_rect.height() - window_rect.height()) * 0.5)) self.edtSCN.setFocus() self.show() self.load_setting() @@ -696,7 +713,8 @@ class MainWindow(QMainWindow): # load blockRepeat self.blockRepeatAction.setChecked(bool(self.setting['blockRepeat'])) # load printer - self.slcSPT.setCurrentIndex(next((index for index, item in enumerate(self.bt.printer_list) if item == self.setting['printer']), 0)) + self.slcSPT.setCurrentIndex( + next((index for index, item in enumerate(self.bt.printer_list) if item == self.setting['printer']), 0)) # load checker self.slcSVR.setCurrentIndex(self.setting['checker'] or 0) # load printCopies @@ -714,7 +732,7 @@ class MainWindow(QMainWindow): def clearRecordActionFunction(self): count = self.ditto.clear() if (count > 0) == 1: - QMessageBox.information(self, '提示', '打印记录已经清空:%s' % (count,)) + self.toast.show_toast('已成功清空%s条打印记录' % (count,)) def designStateActionFunction(self, checked): if (not self.bt.bt_app) == 1: @@ -745,7 +763,8 @@ class MainWindow(QMainWindow): def aboutWindowActionFunction(self): _c = self.app_version if (not _c) == 0: - QMessageBox.information(self, '关于', "" 'version: %s, build: %s, author: %s, email: %s, site: %s' % (_c[0], _c[1], _c[2], _c[3], '%s' % (_c[4], _c[4]))) + QMessageBox.information(self, '关于', "" 'version: %s, build: %s, author: %s, email: %s, site: %s' % ( + _c[0], _c[1], _c[2], _c[3], '%s' % (_c[4], _c[4]))) @staticmethod def md5(input_data): @@ -792,7 +811,8 @@ class MainWindow(QMainWindow): def set_preview(self, preview_image: str): if (preview_image and os.path.exists(preview_image)) == 1: pixmap = QPixmap(preview_image) - pixmap = pixmap.scaled(self.labPRV.size(), aspectRatioMode=Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation) + pixmap = pixmap.scaled(self.labPRV.size(), aspectRatioMode=Qt.KeepAspectRatio, + transformMode=Qt.SmoothTransformation) self.labPRV.setPixmap(pixmap) if (tempfile.gettempdir() in preview_image) == 1: rm(preview_image) @@ -809,6 +829,7 @@ class MainWindow(QMainWindow): self.set_preview(self.bt.generate_preview()) self.last_opened_template[0] = file self.last_opened_template[1] = self.md5(open(file, 'rb')) + self.toast.show_toast('模板加载成功') except pywintypes.com_error as e: t = str(e.args[1]) m = str(e.args[2][2] if isinstance(e.args[2], tuple) else e.args[2]) @@ -822,7 +843,8 @@ class MainWindow(QMainWindow): QMessageBox.critical(self, '错误', '%s' % e) def on_open_template_file(self): - filename, _ = QFileDialog.getOpenFileName(self, '打开文件', os.path.dirname(self.last_opened_template[0]), 'BarTender 文档 (*.btw)') + filename, _ = QFileDialog.getOpenFileName(self, '打开文件', os.path.dirname(self.last_opened_template[0]), + 'BarTender 文档 (*.btw)') if (filename and os.path.exists(filename)) == 1: self.load_template(filename) self.setting['template'] = filename @@ -833,7 +855,7 @@ class MainWindow(QMainWindow): self.bt.start_printing_template() self.set_preview(self.bt.generate_preview()) return None - QMessageBox.critical(self, '错误', '请先加载模板文件') + self.toast.show_toast('请先加载模板文件') except pywintypes.com_error as e: t = str(e.args[1]) m = str(e.args[2][2] if isinstance(e.args[2], tuple) else e.args[2]) @@ -903,14 +925,18 @@ class MainWindow(QMainWindow): def on_convert_letter_changed(self, checked): if (checked == 2) == 1: self.input_convert_letter = 1 + self.toast.show_toast('强制大写开启') else: self.input_convert_letter = 0 + self.toast.show_toast('强制大写关闭') def on_prohibit_enter_changed(self, checked): if (checked == 2) == 1: self.input_scan_prohibited_enter = 1 + self.toast.show_toast('禁用回车开启') else: self.input_scan_prohibited_enter = 0 + self.toast.show_toast('禁用回车关闭') def on_print_scan_enter(self): self.input_scan_prohibited_enter or self.on_start_printing() @@ -923,13 +949,15 @@ class MainWindow(QMainWindow): text = edit.text().strip() edit.setText(text) if (self.bt.bt_format is None) == 1: + self.toast.show_toast('未加载模板文件') edit.selectAll() return None if (text == '') == 1: + self.toast.show_toast('输入的内容为空') edit.selectAll() return None if (not self.sv.verify(text)) == 1: - QMessageBox.critical(self, '错误', '打印的内容不符合验证规则:\n\n%s' % (text,)) + self.toast.show_toast('输入的内容不符合验证规则') edit.selectAll() return None if (not self.ditto.addit(text) and self.setting['blockRepeat']) == 1: @@ -953,10 +981,52 @@ class MainWindow(QMainWindow): QMessageBox.critical(self, '错误', '%s' % e) +class ToastNotification(QDialog): + def __init__(self): + super().__init__() + self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowType.Tool) + layout = QVBoxLayout() + layout.setContentsMargins(5, 705, 5, 5) + + self.label = QLabel("") + self.label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 24px; color: #ffffff;") + layout.addWidget(self.label) + self.setLayout(layout) + self.setAttribute(Qt.WA_TranslucentBackground) + self.setStyleSheet("background-color: rgba(65, 65, 65, 180); border-radius: 5px; padding: 10px 16px 10px 16px") + + self.adjustSize() + + self.timer = QTimer(self) + self.timer.setInterval(2000) + self.timer.timeout.connect(self.close) + + self.fade_animation = QPropertyAnimation(self, b"windowOpacity") + self.fade_animation.setDuration(500) + + def show_toast(self, message): + self.close() + self.label.setText(message) + self.timer.isActive() and self.timer.stop() + self.timer.start() + self.adjustSize() + self.fade_animation.setStartValue(0.0) + self.fade_animation.setEndValue(1.0) + self.show() + self.fade_animation.start() + + def closeEvent(self, event): + if self.timer.isActive(): + self.timer.stop() + super().closeEvent(event) + + if __name__ == '__main__': if (os.path.basename(__file__).lower().endswith('.int')) == 1: - QCoreApplication.addLibraryPath(os.path.abspath(os.path.join(os.path.dirname(__file__), 'site-packages/PyQt5/Qt5/plugins'))) - f_lock = open(file=os.path.abspath(os.path.join(tempfile.gettempdir(), '%s.lock' % hashlib.md5(bytes(__file__, encoding='utf-8')).hexdigest()[:16])), mode='w', encoding='utf-8') + QCoreApplication.addLibraryPath( + os.path.abspath(os.path.join(os.path.dirname(__file__), 'site-packages/PyQt5/Qt5/plugins'))) + f_lock = open(file=os.path.abspath(os.path.join(tempfile.gettempdir(), '%s.lock' % hashlib.md5( + bytes(__file__, encoding='utf-8')).hexdigest()[:16])), mode='w', encoding='utf-8') if (not flock(f_lock, LOCK_EX | LOCK_NB)) == 1: app = QApplication(sys.argv) msg = QMessageBox() diff --git a/rules.json b/rules.json index 4bb2060..156166d 100644 --- a/rules.json +++ b/rules.json @@ -66,5 +66,101 @@ [ "24位长度", "^.{24}$" + ], + [ + "25位长度", + "^.{25}$" + ], + [ + "26位长度", + "^.{26}$" + ], + [ + "27位长度", + "^.{27}$" + ], + [ + "28位长度", + "^.{28}$" + ], + [ + "29位长度", + "^.{29}$" + ], + [ + "30位长度", + "^.{30}$" + ], + [ + "31位长度", + "^.{31}$" + ], + [ + "32位长度", + "^.{32}$" + ], + [ + "33位长度", + "^.{33}$" + ], + [ + "34位长度", + "^.{34}$" + ], + [ + "35位长度", + "^.{35}$" + ], + [ + "36位长度", + "^.{36}$" + ], + [ + "37位长度", + "^.{37}$" + ], + [ + "38位长度", + "^.{38}$" + ], + [ + "39位长度", + "^.{39}$" + ], + [ + "40位长度", + "^.{40}$" + ], + [ + "41位长度", + "^.{41}$" + ], + [ + "42位长度", + "^.{42}$" + ], + [ + "43位长度", + "^.{43}$" + ], + [ + "44位长度", + "^.{44}$" + ], + [ + "45位长度", + "^.{45}$" + ], + [ + "46位长度", + "^.{46}$" + ], + [ + "47位长度", + "^.{47}$" + ], + [ + "48位长度", + "^.{48}$" ] ]