Объединить несколько PDF в один с окном выбора файла

Объединить несколько PDF в один, их количество не постоянное, так же чаще всего находятся в разных директориях

Вот мой код:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fileencoding=utf-8

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import sqlite3
import pyqrcode
import png
import sys
import locale
import fitz
from pathlib import Path
import PyPDF2
from PyPDF2 import PdfFileReader, PdfFileWriter, PdfFileMerger



class Main(tk.Frame):
    def __init__(self, root):
        super().__init__(root)
        self.init_main()
        self.db = db
        self.view_records()

    def init_main(self):
        toolbar = tk.Frame(bg='#d7d8e0', bd=2)
        toolbar.pack(side=tk.TOP, fill=tk.X)
# Добавление кнопок управления
        self.add_img = tk.PhotoImage(file='ADD.png') #ADD
        btn_open_dialog = tk.Button(toolbar, text='Додати', command=self.open_dialog, bg='#d7d8e0', bd=0,
                                    compound=tk.TOP, image=self.add_img)
        btn_open_dialog.pack(side=tk.LEFT)

        self.update_img = tk.PhotoImage(file='red.png') #redach
        btn_edit_dialog = tk.Button(toolbar, text='Редукувати', bg='#d7d8e0', bd=0, image=self.update_img,
                                    compound=tk.TOP, command=self.open_update_dialog)
        btn_edit_dialog.pack(side=tk.LEFT)

        self.delete_img = tk.PhotoImage(file='del.png') #Delete
        btn_delete = tk.Button(toolbar, text='Видалити', bg='#d7d8e0', bd=0, image=self.delete_img,
                               compound=tk.TOP, command=self.delete_records)
        btn_delete.pack(side=tk.LEFT)

        self.search_img = tk.PhotoImage(file='shearh.png') #Shearh
        btn_search = tk.Button(toolbar, text='Пошук', bg='#d7d8e0', bd=0, image=self.search_img,
                               compound=tk.TOP, command=self.open_search_dialog)
        btn_search.pack(side=tk.LEFT)

        self.refresh_img = tk.PhotoImage(file='rel.png') #Obnovit
        btn_refresh = tk.Button(toolbar, text='Обновити', bg='#d7d8e0', bd=0, image=self.refresh_img,
                                compound=tk.TOP, command=self.view_records)
        btn_refresh.pack(side=tk.LEFT)

        self.tree = ttk.Treeview(self, columns=('ID', 'mark', 'name', 'Kol', 'cena', 'polych',  'FIO', 'Adress', 'tel', 'ERDPOU',  'email', 'data', 'shetchik1'), height=15, show='headings')
#Расположение кнопок
        self.tree.column('ID', width=30, anchor=tk.CENTER)
        self.tree.column('shetchik1', width=100, anchor=tk.CENTER)
        self.tree.column('mark', width=150, anchor=tk.CENTER)
        self.tree.column('name', width=150, anchor=tk.CENTER)
        self.tree.column('Kol', width=100, anchor=tk.CENTER)
        self.tree.column('cena', width=100, anchor=tk.CENTER)
        self.tree.column('polych', width=100, anchor=tk.CENTER)
        self.tree.column('FIO', width=100, anchor=tk.CENTER)
        self.tree.column('Adress', width=100, anchor=tk.CENTER)
        self.tree.column('tel', width=100, anchor=tk.CENTER)
        self.tree.column('ERDPOU', width=100, anchor=tk.CENTER)
        self.tree.column('email', width=100, anchor=tk.CENTER)
        self.tree.column('data', width=100, anchor=tk.CENTER)



#Подпись кнопок
        self.tree.heading('ID', text='ID')
        self.tree.heading('shetchik1', text='Индекс')
        self.tree.heading('mark', text='Маркування Стандарту')
        self.tree.heading('name', text='Назва Стандарту')
        self.tree.heading('Kol', text='Кількість сторінок')
        self.tree.heading('cena', text='Цена')
        self.tree.heading('polych', text='ФІО')
        self.tree.heading('FIO', text='Отримувач')
        self.tree.heading('Adress', text='Адреса')
        self.tree.heading('tel', text='Телефон')
        self.tree.heading('ERDPOU', text='ЄРДПОУ')
        self.tree.heading('email', text='Електронна адреса')
        self.tree.heading('data', text='Дата')


        self.tree.pack()
# Функции кнопок
    def records(self, mark, name_standart, kilkiststr, cena, FIO, polych, Adress, tel, ERDPOU, email, data, shetchik1):  #Запись
        self.db.insert_data(mark, name_standart, kilkiststr, cena, FIO, polych, Adress, tel, ERDPOU, email, data, shetchik1)
        self.view_records()

    def update_record(self, mark, name_standart, kilkiststr, cena, FIO, polych, Adress, tel, ERDPOU, email, data, shetchik1): #Обновить
        self.db.c.execute('''UPDATE work SET mark=?, name_standart=?, kilkiststr=?, cena=?, FIO=?, polych=?, Adress=?, tel=?, ERDPOU=?, email=?, data=?, shetchik1=? WHERE ID=?''',
                          (mark, name_standart, kilkiststr, cena, FIO, polych, Adress, tel, ERDPOU, email, data, shetchik1, self.tree.set(self.tree.selection()[0], '#1')))
        self.db.conn.commit()
        self.view_records()

    def view_records(self): #Просмотреть
        self.db.c.execute('''SELECT * FROM work''')
        [self.tree.delete(i) for i in self.tree.get_children()]
        [self.tree.insert('', 'end', values=row) for row in self.db.c.fetchall()]

    def delete_records(self): #Удалить
        for selection_item in self.tree.selection():
            self.db.c.execute('''DELETE FROM work WHERE id=?''', (self.tree.set(selection_item, '#1'),))
        self.db.conn.commit()
        self.view_records()

    def search_records(self, polych):   #Поиск
        polych = ('%' + polych + '%',)
        self.db.c.execute('''SELECT * FROM work WHERE polych LIKE ?''', polych)
        [self.tree.delete(i) for i in self.tree.get_children()]
        [self.tree.insert('', 'end', values=row) for row in self.db.c.fetchall()]


# Открытие окон
    def open_dialog(self):
        Child()

    def open_update_dialog(self):
        Update()

    def open_search_dialog(self):
        Search()


class Child(tk.Toplevel):
    def __init__(self):
        super().__init__(root)
        self.init_child()
        self.view = app

    def init_child(self):
        self.title('Додати')
        self.geometry('400x620+250+100')
        self.resizable(False, False)

        def get_file_name():
            input_file = Path(filedialog.askopenfilename())
            barcode_file = "qrtest"
            output_file = filedialog.asksaveasfilename(initialfile=input_file.name, defaultextension=('.pdf'), filetypes=(("pdf file", "*.pdf"),("All Files", "*.*")) )
            # определить позицию (верхний правый угол)
            image_rectangle = fitz.Rect(500, 0, 600, 100)
            # retrieve the first page of the PDF
            file_handle = fitz.open(input_file)
            first_page = file_handle[0]
            # добавить изображение
            first_page.insertImage(image_rectangle, filename=barcode_file)
            file_handle.save(output_file)

        def GenerateQR():
            qr2 = ('Індекс запису: ' + self.entry_shetchik1.get() + '\nПозначення НД: ' + self.entry_mark.get() + '\nКількість сторінок: ' + self.entry_kilkiststr.get() + ' \nНазва одержувача: ' + self.entry_polych.get() + '\nЄРДПОУ одержувача: ' + self.entry_ERDPOU.get() + '\nДата: ' + self.entry_data.get())


            qr = pyqrcode.create(qr2, encoding='UTF-8')
            qr.png('qrtest', scale = 6)

        def Gotov():
            entry_update()
            GenerateQR()
            get_file_name()

        def Dodatok():





        self.btn1 = ttk.Button(self, text='Создать файл', command=Gotov)
        self.btn1.place(x=50, y=480)

        entry_shetchik1_var = tk.StringVar()
        self.entry_shetchik1 = ttk.Entry(self, textvariable=entry_shetchik1_var)
        self.entry_shetchik1.place(x=200, y=50)

        self.btn1 = ttk.Button(self, text='Додатки', command=Dodatok)
        self.btn1.place(x=140, y=480)

        def entry_update():
            text = entry_shetchik1_var.get().rstrip('\n')
            if '\t' in text:
                parts = text.split('\t')
                try:
                    self.entry_shetchik1.delete(0, tk.END)
                    self.entry_shetchik1.insert(0, parts[0])

                    self.entry_kilkiststr.delete(0, tk.END)
                    self.entry_kilkiststr.insert(0, parts[1])

                    self.entry_name_standart.delete(0, tk.END)
                    self.entry_name_standart.insert(0, parts[2])

                    self.entry_mark.delete(0, tk.END)
                    self.entry_mark.insert(0, parts[3])

                    self.entry_cena.delete(0, tk.END)
                    self.entry_cena.insert(0, parts[4])

                    self.entry_FIO.delete(0, tk.END)
                    self.entry_FIO.insert(0, parts[5])

                    self.entry_polych.delete(0, tk.END)
                    self.entry_polych.insert(0, parts[6])

                    self.entry_Adress.delete(0, tk.END)
                    self.entry_Adress.insert(0, parts[7])

                    self.entry_tel.delete(0, tk.END)
                    self.entry_tel.insert(0, parts[8])

                    self.entry_ERDPOU.delete(0, tk.END)
                    self.entry_ERDPOU.insert(0, parts[9])

                    self.entry_email.delete(0, tk.END)
                    self.entry_email.insert(0, parts[10])

                    self.entry_data.delete(0, tk.END)
                    self.entry_data.insert(0, parts[11])
                except IndexError:
                    # Если количество элементов в списке меньше чем текстовых полей, просто выходим
                    pass


        label_shetchik1 = tk.Label(self, text='Индекс:')
        label_shetchik1.place(x=50, y=50)
        label_mark = tk.Label(self, text='Маркування Стандарту:')
        label_mark.place(x=50, y=80)
        label_name_standart = tk.Label(self, text='Назва Стандарту:')
        label_name_standart.place(x=50, y=110)
        label_kilkiststr = tk.Label(self, text='Кількість сторінок:')
        label_kilkiststr.place(x=50, y=140)
        label_cena = tk.Label(self, text='Цена:')
        label_cena.place(x=50, y=170)
        label_FIO = tk.Label(self, text='ФІО:')
        label_FIO.place(x=50, y=200)
        label_polych = tk.Label(self, text='Отримувач:')
        label_polych.place(x=50, y=230)
        label_Adress = tk.Label(self, text='Адреса:')
        label_Adress.place(x=50, y=260)
        label_tel = tk.Label(self, text='Телефон:')
        label_tel.place(x=50, y=290)
        label_ERDPOU = tk.Label(self, text='ЄРДПОУ:')
        label_ERDPOU.place(x=50, y=320)
        label_email = tk.Label(self, text='Електронна адреса:')
        label_email.place(x=50, y=350)
        label_data = tk.Label(self, text='Дата:')
        label_data.place(x=50, y=380)



        self.entry_kilkiststr = ttk.Entry(self)
        self.entry_kilkiststr.place(x=200, y=80)

        self.entry_name_standart = ttk.Entry(self)
        self.entry_name_standart.place(x=200, y=110)

        self.entry_mark = ttk.Entry(self)
        self.entry_mark.place(x=200, y=140)

        self.entry_cena = ttk.Entry(self)
        self.entry_cena.place(x=200, y=170)

        self.entry_FIO = ttk.Entry(self)
        self.entry_FIO.place(x=200, y=200)

        self.entry_polych = ttk.Entry(self)
        self.entry_polych.place(x=200, y=230)

        self.entry_Adress = ttk.Entry(self)
        self.entry_Adress.place(x=200, y=260)

        self.entry_tel = ttk.Entry(self)
        self.entry_tel.place(x=200, y=290)

        self.entry_ERDPOU = ttk.Entry(self)
        self.entry_ERDPOU.place(x=200, y=320)

        self.entry_email = ttk.Entry(self)
        self.entry_email.place(x=200, y=350)

        self.entry_data = ttk.Entry(self)
        self.entry_data.place(x=200, y=380)




        btn_cancel = ttk.Button(self, text='Закрити', command=self.destroy)
        btn_cancel.place(x=300, y=480)

        self.btn_ok = ttk.Button(self, text='Додати')
        self.btn_ok.place(x=220, y=480)
        self.btn_ok.bind('<Button-1>', lambda event: self.view.records(self.entry_kilkiststr.get(),
                                                                       self.entry_name_standart.get(),
                                                                       self.entry_mark.get(),
                                                                       self.entry_cena.get(),
                                                                       self.entry_FIO.get(),
                                                                       self.entry_polych.get(),
                                                                       self.entry_Adress.get(),
                                                                       self.entry_tel.get(),
                                                                       self.entry_ERDPOU.get(),
                                                                       self.entry_email.get(),
                                                                       self.entry_data.get(),
                                                                       self.entry_shetchik1.get()))





        self.grab_set()
        self.focus_set()





































class Update(Child):
    def __init__(self):
        super().__init__()
        self.init_edit()
        self.view = app
        self.db = db
        self.default_data()

    def init_edit(self):
        self.title('Редукувати')
        btn_edit = ttk.Button(self, text='Редукувати')
        btn_edit.place(x=205, y=480)
        btn_edit.bind('<Button-1>', lambda event: self.view.update_record(self.entry_kilkiststr.get(),
                                                                       self.entry_name_standart.get(),
                                                                       self.entry_mark.get(),
                                                                       self.entry_cena.get(),
                                                                       self.entry_FIO.get(),
                                                                       self.entry_polych.get(),
                                                                       self.entry_Adress.get(),
                                                                       self.entry_tel.get(),
                                                                       self.entry_ERDPOU.get(),
                                                                       self.entry_email.get(),
                                                                       self.entry_data.get(),
                                                                       self.entry_shetchik1.get()))

        self.btn_ok.destroy()

    def default_data(self):
        self.db.c.execute('''SELECT * FROM work WHERE id=?''',
                          (self.view.tree.set(self.view.tree.selection()[0], '#1'),))
        row = self.db.c.fetchone()
        self.entry_mark.insert(0, row[3])
        self.entry_name_standart.insert(0, row[2])
        self.entry_kilkiststr.insert(0, row[1])
        self.entry_cena.insert(0, row[4])
        self.entry_FIO.insert(0, row[5])
        self.entry_polych.insert(0, row[6])
        self.entry_Adress.insert(0, row[7])
        self.entry_tel.insert(0, row[8])
        self.entry_ERDPOU.insert(0, row[9])
        self.entry_email.insert(0, row[10])
        self.entry_data.insert(0, row[11])
        self.entry_shetchik1.insert(0, row[12])




class Search(tk.Toplevel):
    def __init__(self):
        super().__init__()
        self.init_search()
        self.view = app

    def init_search(self):
        self.title('Пошук')
        self.geometry('300x100+400+300')
        self.resizable(False, False)

        label_search = tk.Label(self, text='Пошук')
        label_search.place(x=50, y=20)

        self.entry_search = ttk.Entry(self)
        self.entry_search.place(x=105, y=20, width=150)

        btn_cancel = ttk.Button(self, text='Закрити', command=self.destroy)
        btn_cancel.place(x=185, y=50)

        btn_search = ttk.Button(self, text='Пошук')
        btn_search.place(x=105, y=50)
        btn_search.bind('<Button-1>', lambda event: self.view.search_records(self.entry_search.get()))
        btn_search.bind('<Button-1>', lambda event: self.destroy(), add='+')


class DB:
    def __init__(self):
        self.conn = sqlite3.connect('work.db')
        self.c = self.conn.cursor()
        self.c.execute(
            '''CREATE TABLE IF NOT EXISTS work (id integer primary key, mark text, name_standart text, kilkiststr real,cena integer, FIO text, polych text, Adress text, tel integer, ERDPOU text, email text, data text, shetchik1 integer)''')
        self.conn.commit()

    def insert_data(self, mark, name_standart, kilkiststr, cena, FIO, polych, Adress, tel, ERDPOU, email, data, shetchik1):
        self.c.execute('''INSERT INTO work(mark, name_standart, kilkiststr, cena, FIO, polych, Adress, tel, ERDPOU, email, data, shetchik1) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
                       (mark, name_standart, kilkiststr, cena, FIO, polych, Adress, tel, ERDPOU, email, data, shetchik1))
        self.conn.commit()


if __name__ == "__main__":
    root = tk.Tk()
    db = DB()
    app = Main(root)
    app.pack()
    root.title("Робота")
    root.geometry("1450x450+0+0")
    root.resizable(False, False)
    root.mainloop()

Использовал варианты с pypdf2 но там не удобно надо сразу прописовать либо путь либо название файла

Пробовал таким способом, что бы открывалось окно выбора файла и разрешало выбирать сразу несколько файлов

merger = PdfFileMerger()
doc1 = merger.append(Path(filedialog.askopenfilename()))
merger.append(filedialog.askopenfilenames()) merger.write(filedialog.asksaveasfilename(initialfile=doc1.name, defaultextension=('.pdf'), filetypes=(("pdf file", "*.pdf"),("All Files", "*.*")) ))
merger.close()

Но появляется данная ошибка

AttributeError: 'WindowsPath' object has no attribute 'seek'

Пробовал еще таким способом

merger = PdfFileMerger()
doc1 = merger.append(FileIO(Path(filedialog.askopenfilename())))
            
merger.append(FileIO(filedialog.askopenfilenames()))
            merger.write(filedialog.asksaveasfilename(initialfile=doc1.name, defaultextension=('.pdf'), filetypes=(("pdf file", "*.pdf"),("All Files", "*.*")) ))
            merger.close()

в этом случае появляется уже такая ошибка

TypeError: expected str, bytes or os.PathLike object, not tuple

Ответы (0 шт):