From acd6ca8db0e59e3bfcb220f901aabaf730ccebfe Mon Sep 17 00:00:00 2001 From: kozhushkojv Date: Mon, 14 Oct 2024 13:55:43 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5?= =?UTF-8?q?=D0=B9=D1=81=20=D0=BF=D0=B5=D1=80=D0=B5=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D0=BD=20=D0=BF=D0=BE=D0=B4=20=D0=B2=D0=BE=D0=B7?= =?UTF-8?q?=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=BF=D0=B0?= =?UTF-8?q?=D0=BA=D0=B5=D1=82=D0=BD=D0=BE=D0=B9=20=D0=BF=D0=B5=D1=87=D0=B0?= =?UTF-8?q?=D1=82=D0=B8=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B0=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=BD=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=BF=D0=B5=D1=87=D0=B0=D1=82=D1=8C=20=D0=A0=D0=B5?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B0=20=D0=B2=D0=B2=D0=BE?= =?UTF-8?q?=D0=B4=D0=B8=D0=BC=D0=BE=D0=B3=D0=BE=20=D0=B8=D0=BD=D0=B2.=20?= =?UTF-8?q?=D0=BD=D0=BE=D0=BC=D0=B5=D1=80=D0=B0=20=D0=BD=D0=B0=20=D0=BA?= =?UTF-8?q?=D0=BE=D1=80=D1=80=D0=B5=D0=BA=D1=82=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=9F=D1=80=D0=BE=D1=87=D0=B8=D0=B5=20=D0=BC=D0=B5?= =?UTF-8?q?=D0=BB=D0=BA=D0=B8=D0=B5=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 0 print-labels-gui.py | 306 +++++++++++++++++++++++++------------------- terminus.pbm | Bin terminus.pil | Bin 4 files changed, 174 insertions(+), 132 deletions(-) mode change 100755 => 100644 README.md mode change 100755 => 100644 print-labels-gui.py mode change 100755 => 100644 terminus.pbm mode change 100755 => 100644 terminus.pil diff --git a/README.md b/README.md old mode 100755 new mode 100644 diff --git a/print-labels-gui.py b/print-labels-gui.py old mode 100755 new mode 100644 index 7aacab8..d51b5a0 --- a/print-labels-gui.py +++ b/print-labels-gui.py @@ -1,122 +1,139 @@ #!/usr/bin/python3 """ - + Скрипт с графическим интерфейсом - для печати этикеток на принтере серий brother p-touch, - на основе https://gitea.basealt.ru/polkovnikovaav/ptouch-print-labels - - + для печати этикеток на принтере серий brother p-touch + + (форк) на основе скрипта Анны Полковниковой (https://gitea.basealt.ru/polkovnikovaav/ptouch-print-labels) подробности и настройки в README.md + зи + """ from PySide6.QtWidgets import QApplication -from PySide6 import QtGui,QtWidgets -from PySide6.QtWidgets import QMainWindow, QWidget, QLabel,QVBoxLayout, QPushButton,QGridLayout,QLineEdit, QComboBox,QMessageBox +from PySide6 import QtGui +from PySide6.QtWidgets import QMainWindow, QWidget, QVBoxLayout, QPushButton, QComboBox, QTableWidget, QHBoxLayout, QMessageBox, QTableWidgetItem import subprocess import time import os import sys +import glob +import re from PIL import Image, ImageOps, ImageDraw, ImageFont from barcode import EAN13 from barcode.writer import ImageWriter -# главное окно + class MainWindow(QMainWindow): - - def __init__(self): super().__init__() - - self.conf="barcode2-gui.ini" + self.version = "v1.3" - self.setWindowTitle('Печать стикеров') - self.q_button_start = QPushButton('печать') - self.q_button_start.clicked.connect(self.start_print) - - self.q_label1 = QLabel() - self.q_label2 = QLabel() - self.q_label3 = QLabel() - + self.device_names = ['компьютер', 'монитор', 'сетевое об.', + 'токен', 'принтер/МФУ', 'флешка', 'HID', 'UPS', 'другое'] - self.q_label1.setText("Введите текст:") - self.q_label2.setText("Введите SN (не вводить - генерация):") - self.q_label3.setText("Выберите тип устройства:") + self.setWindowTitle(f"Печать стикеров инвентаризации {self.version}") + self.resize(700, 500) - self.q_combo = QComboBox(self) - - self.q_combo.addItem("компьютер") - self.q_combo.addItem("монитор") - self.q_combo.addItem("сетевое об.") - self.q_combo.addItem("токен") - self.q_combo.addItem("принтер/МФУ") - self.q_combo.addItem("флешка") - self.q_combo.addItem("HID") - self.q_combo.addItem("UPS") - self.q_combo.addItem("другое") - - self.q_button_start=QPushButton("печать") - self.q_button_start.setMinimumSize(20,80) + # таблица + self.q_table = QTableWidget() + self.init_table() - self.q_button_start.clicked.connect(self.start_print) + # кнопка печати + self.q_print_button = QPushButton() + self.q_print_button.setText("печать") + self.q_print_button.clicked.connect(self.start_print) + self.q_print_button.setMinimumSize(15, 50) - self.grid_layout = QGridLayout() - self.layout1 = QVBoxLayout() - - self.q_edit1=QLineEdit() # текст (над ШК) - self.q_edit2=QLineEdit() # вводимый свой серийник (если не нужна генерациия) - self.q_edit3=QLineEdit() # выводимый SN для справки - self.q_edit3.setReadOnly(True) + # кнопка очистки + self.q_clear_button = QPushButton() + self.q_clear_button.setText("очистка") + self.q_clear_button.clicked.connect(self.init_table) + self.q_clear_button.setMinimumSize(15, 50) - self.layout1.addWidget(self.q_label1) - self.layout1.addWidget(self.q_edit1) - self.layout1.addWidget(self.q_label2) - self.layout1.addWidget(self.q_edit2) - - self.layout1.addWidget(self.q_label3) - self.layout1.addWidget(self.q_combo) - self.layout1.addWidget(self.q_button_start) - self.layout1.addWidget(self.q_edit3) + self.qh_layout2 = QHBoxLayout() + self.qh_layout2.addWidget(self.q_print_button) + self.qh_layout2.addWidget(self.q_clear_button) + # компоновщик1 вертикальный + self.qv_layout1 = QVBoxLayout() + self.qv_layout1.setContentsMargins(15, 15, 15, 15) + self.qv_layout1.setSpacing(15) + self.qv_layout1.addWidget(self.q_table) + self.qv_layout1.addLayout(self.qh_layout2) - self.grid_layout.setRowStretch(5,0) - self.grid_layout.setRowStretch(20,1) - self.grid_layout.setRowStretch(1,2) - self.grid_layout.setRowStretch(1,3) - self.grid_layout.setRowStretch(1,4) - self.grid_layout.setRowStretch(100,5) - self.grid_layout.setRowStretch(1,6) - - self.grid_layout.addWidget(self.q_label1, 0,0) - self.grid_layout.addWidget(self.q_edit1, 1,0) - self.grid_layout.addWidget(self.q_label2, 2,0) - self.grid_layout.addWidget(self.q_edit2, 3,0) - self.grid_layout.addWidget(self.q_label3, 4,0) - self.grid_layout.addWidget(self.q_combo, 5,0) - self.grid_layout.addWidget(self.q_button_start,6,0) - self.grid_layout.addWidget(self.q_edit3,7,0) # шк-код текстом - + # компоновщик горизонтальный + self.qh_layout = QHBoxLayout() + self.qh_layout.addLayout(self.qv_layout1) + + # обобщающий виджет + self.q_central_widget = QWidget() + self.q_central_widget.setLayout(self.qh_layout) + self.setCentralWidget(self.q_central_widget) - self.content_widget = QWidget() - self.content_widget.setLayout(self.grid_layout) - self.setCentralWidget(self.content_widget) - # выпадающий список типов и кодовые соответствия self.combo_type_items = { - - "компьютер":"21", - "монитор":"22", - "сетевое об.":"23", - "токен":"24", - "принтер/МФУ":"25", - "флешка":"26", - "HID":"27", - "UPS":"28", - "другое":"29", - } + "компьютер": "21", + "монитор": "22", + "сетевое об.": "23", + "токен": "24", + "принтер/МФУ": "25", + "флешка": "26", + "HID": "27", + "UPS": "28", + "другое": "29", + } + + def gen_message_box(self, message_str): + msg_box = QMessageBox() + msg_box.setWindowTitle("Внимание") + msg_box.setText(message_str) + msg_box.setIcon(QMessageBox.Information) + msg_box.exec() + + # проверка строки на соответствие строго 12 цифр + def check_inventory_number(self, inventoryN): + pattern = r'^\d{12}$' + if re.match(pattern, inventoryN): + return True + else: + return False + + # инициализация таблицы + + def init_table(self): + self.q_table.clear() + + self.q_table.setColumnCount(3) + self.q_table.setHorizontalHeaderLabels( + ['Текст', 'Тип', 'Инв.Н (пустое - генерация)']) + self.q_table.setRowCount(10) + self.q_table.setColumnWidth(0, 200) + self.q_table.setColumnWidth(1, 110) + self.q_table.setColumnWidth(2, 200) + + # кладем комбобоксы в ячейки + for i in range(0, 10): + self.q_combo = QComboBox(self) + self.q_combo.addItems(self.device_names) + self.q_table.setCellWidget(i, 1, self.q_combo) + + # удаляем временные Png файлы + + def clear_temp_png_files(self): + self.set_current_location() + + fileList = glob.glob('*.png') + # Iterate over the list of filepaths & remove each file. + for filePath in fileList: + try: + os.remove(filePath) + except Exception: + print("Error while deleting file : ", filePath) # получаем текущий каталог и переходим в него def set_current_location(self): @@ -124,21 +141,22 @@ class MainWindow(QMainWindow): os.chdir(path_there) # генерация штрих-кода с контрльной суммой - def gen_ean13(self,product_code: str): - + def gen_ean13(self, product_code: str): + # добавляем псевдослучаное значение (от времени к коду продукта) - digits_s= product_code + str(round(time.time())) - - + # при пакетной генерации между генерациями необходим интервал + time.sleep(1) + digits_s = product_code + str(round(time.time())) + # строка продукта в список чисел digits = [int(i) for i in digits_s] - + # контрольная сумма по алгоритму ЛУна checksum = (10 - (sum(digits[1::2]) * 3 + sum(digits[::2])) % 10) % 10 return "".join(str(i) for i in (digits + [checksum])) # генерация картинки - def create_code_png(self,filename, code, text): + def create_code_png(self, filename, code, text): self.set_current_location() ean13_code = EAN13(code, writer=ImageWriter()) @@ -156,14 +174,15 @@ class MainWindow(QMainWindow): image = image.convert("1", dither=Image.Dither.NONE) image = ImageOps.expand(image, border=17, fill=1) draw = ImageDraw.Draw(image) - + # загружаем шрифт dst = "terminus.pil" font = ImageFont.load(dst) - + text_length = draw.textlength(text, font=font) code_text_length = draw.textlength(code, font=font) - draw.text(((image.width - text_length) / 2, 3), text, fill="black", font=font) + draw.text(((image.width - text_length) / 2, 3), + text, fill="black", font=font) draw.text( ((image.width - code_text_length) / 2, 100), code, @@ -172,44 +191,67 @@ class MainWindow(QMainWindow): ) image.save(filename) - - - #запуск всего процесса (генерация и печать) + # запуск всего процесса (генерация и печать) def start_print(self): - - - # берем ID по типу оборудования - type_device=self.combo_type_items[self.q_combo.currentText()] - - # берем текст подписи - text_data=self.q_edit1.text() - - barcode = self.gen_ean13(type_device) - - # если ввели свой SN, передаем его в создание ШК - if len(self.q_edit2.text())>0: - if len(self.q_edit2.text())==12: - barcode=self.q_edit2.text() - else: - msg = QMessageBox() - msg.setWindowTitle("Внимание") - msg.setText("Должно быть 12 знаков") - msg.setIcon(QMessageBox.Warning) - msg.exec_() - exit(0) - - self.q_edit3.setText(barcode) - - self.create_code_png("temp.png", barcode, text_data) + + # удаляем старые png-файлы + self.clear_temp_png_files() + + for row in range(0, self.q_table.rowCount()): + print(row) + + # проверка Инв. Номера на корректность + if self.q_table.item(row, 2) is not None and self.check_inventory_number(self.q_table.item(row, 2).text()) is False: + self.gen_message_box( + "инвентарный номер должен содержать 12 цифр") + self.q_table.setItem(row, 2, QTableWidgetItem("")) + return None + + # если ТЕКСТ и ИН заполнены + if self.q_table.item(row, 0) is not None and self.q_table.item(row, 2) is not None: + print(self.q_table.item(row, 0).text()) + combo_widget = self.q_table.cellWidget(row, 1) + type_device = self.combo_type_items[combo_widget.currentText()] + barcode = self.q_table.item(row, 2).text() + self.create_code_png( + f"temp-{row}.png", barcode, self.q_table.item(row, 0).text()) + + # если только ТЕКСТ заполнен + if self.q_table.item(row, 0) is not None and self.q_table.item(row, 2) is None: + print(self.q_table.item(row, 0).text()) + combo_widget = self.q_table.cellWidget(row, 1) + type_device = self.combo_type_items[combo_widget.currentText()] + barcode = self.gen_ean13(type_device) + self.create_code_png( + f"temp-{row}.png", barcode, self.q_table.item(row, 0).text()) + + + + # запуск утилиты печати сфомированного изображения self.start_process() - + + # удаляем временные файлы + self.clear_temp_png_files() + - # запуск утилиты печати сфомированного изображения def start_process(self): - subprocess.run(["ptouch-print", "--image", "temp.png"]) - + + # получаем список файлов + file_list_to_print = glob.glob('*.png') + + # подготовка строки параметров для запуска + prepare_cmd = "" + for file_name in file_list_to_print: + prepare_cmd = prepare_cmd+" --image "+file_name+" --pad 5" + prepare_cmd=prepare_cmd[:-8] + print(prepare_cmd) + + + subprocess.run("ptouch-print "+prepare_cmd,shell=True) + + if __name__ == '__main__': app = QApplication(sys.argv) @@ -218,7 +260,7 @@ if __name__ == '__main__': # таблица стилей (задаем размер шрифта) style_sheet01 = """ * { - font-size: 11pt; + font-size: 10pt; } """ @@ -228,14 +270,14 @@ if __name__ == '__main__': window = MainWindow() # Установить размер окна - window.resize(500, 300) + window.resize(600, 500) # Получить допустимое разрешение SrcSize = QtGui.QScreen.availableGeometry(QApplication.primaryScreen()) - + frmX = (SrcSize.width() - window.width())/2 frmY = (SrcSize.height() - window.height())/2 window.move(frmX, frmY) - + window.show() sys.exit(app.exec_()) diff --git a/terminus.pbm b/terminus.pbm old mode 100755 new mode 100644 diff --git a/terminus.pil b/terminus.pil old mode 100755 new mode 100644