Интерфейс переработан под возможность пакетной печати

Реализована пакетная печать
Реализована проверка вводимого инв. номера на корректность
Прочие мелкие правки
This commit is contained in:
Юрий Кожушко 2024-10-14 13:55:43 +03:00
parent 9f36f2bbb8
commit acd6ca8db0
4 changed files with 174 additions and 132 deletions

0
README.md Executable file → Normal file
View File

242
print-labels-gui.py Executable file → Normal file
View File

@ -2,106 +2,77 @@
"""
Скрипт с графическим интерфейсом
для печати этикеток на принтере серий 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.version = "v1.3"
self.conf="barcode2-gui.ini"
self.device_names = ['компьютер', 'монитор', 'сетевое об.',
'токен', 'принтер/МФУ', 'флешка', 'HID', 'UPS', 'другое']
self.setWindowTitle('Печать стикеров')
self.q_button_start = QPushButton('печать')
self.q_button_start.clicked.connect(self.start_print)
self.setWindowTitle(f"Печать стикеров инвентаризации {self.version}")
self.resize(700, 500)
self.q_label1 = QLabel()
self.q_label2 = QLabel()
self.q_label3 = QLabel()
# таблица
self.q_table = QTableWidget()
self.init_table()
# кнопка печати
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.q_label1.setText("Введите текст:")
self.q_label2.setText("Введите SN (не вводить - генерация):")
self.q_label3.setText("Выберите тип устройства:")
# кнопка очистки
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.q_combo = QComboBox(self)
self.qh_layout2 = QHBoxLayout()
self.qh_layout2.addWidget(self.q_print_button)
self.qh_layout2.addWidget(self.q_clear_button)
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("другое")
# компоновщик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.q_button_start=QPushButton("печать")
self.q_button_start.setMinimumSize(20,80)
# компоновщик горизонтальный
self.qh_layout = QHBoxLayout()
self.qh_layout.addLayout(self.qv_layout1)
self.q_button_start.clicked.connect(self.start_print)
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.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.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.content_widget = QWidget()
self.content_widget.setLayout(self.grid_layout)
self.setCentralWidget(self.content_widget)
# обобщающий виджет
self.q_central_widget = QWidget()
self.q_central_widget.setLayout(self.qh_layout)
self.setCentralWidget(self.q_central_widget)
# выпадающий список типов и кодовые соответствия
self.combo_type_items = {
@ -117,6 +88,52 @@ class MainWindow(QMainWindow):
"другое": "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):
@ -127,9 +144,10 @@ class MainWindow(QMainWindow):
def gen_ean13(self, product_code: str):
# добавляем псевдослучаное значение (от времени к коду продукта)
# при пакетной генерации между генерациями необходим интервал
time.sleep(1)
digits_s = product_code + str(round(time.time()))
# строка продукта в список чисел
digits = [int(i) for i in digits_s]
@ -163,7 +181,8 @@ class MainWindow(QMainWindow):
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,
@ -173,42 +192,65 @@ class MainWindow(QMainWindow):
image.save(filename)
# запуск всего процесса (генерация и печать)
def start_print(self):
# удаляем старые png-файлы
self.clear_temp_png_files()
# берем ID по типу оборудования
type_device=self.combo_type_items[self.q_combo.currentText()]
for row in range(0, self.q_table.rowCount()):
print(row)
# берем текст подписи
text_data=self.q_edit1.text()
# проверка Инв. Номера на корректность
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)
# если ввели свой 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)
self.start_process()
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__':
@ -218,7 +260,7 @@ if __name__ == '__main__':
# таблица стилей (задаем размер шрифта)
style_sheet01 = """
* {
font-size: 11pt;
font-size: 10pt;
}
"""
@ -228,7 +270,7 @@ if __name__ == '__main__':
window = MainWindow()
# Установить размер окна
window.resize(500, 300)
window.resize(600, 500)
# Получить допустимое разрешение
SrcSize = QtGui.QScreen.availableGeometry(QApplication.primaryScreen())

0
terminus.pbm Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

0
terminus.pil Executable file → Normal file
View File