Интерфейс переработан под возможность пакетной печати
Реализована пакетная печать Реализована проверка вводимого инв. номера на корректность Прочие мелкие правки
This commit is contained in:
parent
9f36f2bbb8
commit
acd6ca8db0
242
print-labels-gui.py
Executable file → Normal file
242
print-labels-gui.py
Executable file → Normal 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
0
terminus.pbm
Executable file → Normal file
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
0
terminus.pil
Executable file → Normal file
0
terminus.pil
Executable file → Normal file
Loading…
Reference in New Issue
Block a user