如何在 运行 代码后保持打开 Tkcalendar

How to keep open Tkcalendar after running code

我正在尝试使用 Python 3.8.5 中的 Tkcalendar 和 PyQt5 从网站打印 PDF for Windows 10

我可以在第一次尝试时打印 PDF 文件。但是我不能再打印了,因为 Tkcalendar 关闭了,我想让它保持打开状态。我做错了什么?

谢谢。

import datetime
import requests
import re
import sys
from bs4 import BeautifulSoup
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from PyQt5 import QtWebEngineWidgets
from tkinter import *
from tkinter import messagebox
from tkcalendar import *

def generar_pdf():
    
    fecha = datetime.datetime.strptime(cal.get_date(), "%d-%m-%Y").strftime("%Y-%m-%d")
    day = datetime.datetime.strptime(cal.get_date(), "%d-%m-%Y").strftime("%d")
    month = datetime.datetime.strptime(cal.get_date(), "%d-%m-%Y").strftime("%m")
    year = datetime.datetime.strptime(cal.get_date(), "%d-%m-%Y").strftime("%Y")
    strURL = "https://www.dof.gob.mx/index_111.php?year=" + year + "&month=" + month + "&day=" + day + "&edicion=MAT"

    req = requests.get(strURL)
    soup = BeautifulSoup(req.text, "lxml")

    for sub_heading in soup.find_all("a", href=True):

        if re.sub("[^\w .]", "", sub_heading.text) == "Tipo de cambio para solventar obligaciones denominadas en moneda extranjera pagaderas en la República Mexicana.":

            DOF_URL = "https://www.dof.gob.mx" + sub_heading.get("href")

        else:
            pass
    
    app = QtWidgets.QApplication(sys.argv)
    loader = QtWebEngineWidgets.QWebEngineView()
    loader.page().pdfPrintingFinished.connect(loader.close)
    loader.load(QtCore.QUrl(DOF_URL))

    def emit_pdf(finished):
        loader.page().printToPdf(fecha + ".pdf")
        messagebox.showinfo("PDF Generado", "Se generó el PDF con éxito.")

    loader.loadFinished.connect(emit_pdf)
    app.exec()

root = Tk()
root.geometry("400x400")

fecha_hoy = datetime.datetime.now()
dia_hoy = int(fecha_hoy.strftime("%d"))
mes_hoy = int(fecha_hoy.strftime("%m"))
año_hoy = int(fecha_hoy.strftime("%Y"))

cal = Calendar(root, selectmode="day", year=año_hoy, month=mes_hoy, day=dia_hoy, date_pattern="dd-mm-yyyy")
cal.pack(pady=20, fill="both", expand=True)

my_button = Button(cal, text="Generar PDF", command=generar_pdf)
my_button.pack(pady=20)

root.mainloop()

问题是您使用的是具有 2 个事件循环的 2 个库,一个可能的解决方案是 运行 在不同的进程中分别使用事件循环,但这不必要地使应用程序复杂化。更好的解决方案是使用单个库编写所有逻辑,在这个库中因为在 tkinter 中没有等效的 Qt WebEngine 我将选择使用 pyqt5:

from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets


SCRIPT_FIND_URL = """
var url = ""
var phrase = "Tipo de cambio para solventar obligaciones denominadas en moneda extranjera pagaderas en la República Mexicana."
var elements = document.getElementsByTagName("a");
for(const e of elements){
    if(e.text.includes(phrase))
        url = e.href
}
url
"""


class PageOffline(QtWebEngineWidgets.QWebEnginePage):
    finished = QtCore.pyqtSignal(bool)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.date_url = QtCore.QUrl()
        self.loadFinished.connect(self.handle_loaded)
        self.pdfPrintingFinished.connect(self.handle_pdf)

    def search(self, date):
        self.date = date
        self.date_url = QtCore.QUrl("https://www.dof.gob.mx/index_111.php")
        query = QtCore.QUrlQuery()
        query.addQueryItem("year", self.date.toString("yyyy"))
        query.addQueryItem("month", self.date.toString("MM"))
        query.addQueryItem("day", self.date.toString("dd"))
        query.addQueryItem("edicion", "MAT")
        self.date_url.setQuery(query)
        self.load(self.date_url)

    def handle_loaded(self, ok):
        if ok:
            if self.url() == self.date_url:
                self.runJavaScript(SCRIPT_FIND_URL, self.handle_url)
            else:
                filename = "{}.pdf".format(self.date.toString("yyyy-MM-dd"))
                self.printToPdf(filename)
        else:
            self.finished.emit(False)

    def handle_url(self, url):
        if url:
            pdf_url = QtCore.QUrl.fromUserInput(url)
            self.load(pdf_url)
        else:
            self.finished.emit(False)

    def handle_pdf(self, path, ok):
        self.finished.emit(ok)


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.page = PageOffline()

        self.button = QtWidgets.QPushButton("Generate pdf")
        self.calendar = QtWidgets.QCalendarWidget()

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(self.calendar)
        lay.addWidget(self.button, alignment=QtCore.Qt.AlignCenter)

        self.button.clicked.connect(self.handle_clicked)
        self.page.finished.connect(self.handle_print_finished)

    def handle_clicked(self):
        date = self.calendar.selectedDate()
        self.page.search(date)
        self.button.setEnabled(False)

    def handle_print_finished(self, status):
        QtWidgets.QMessageBox.information(
            self,
            "Generación de PDF",
            "El PDF fue generado con éxito" if status else "La generación de PDF fallo",
        )
        self.button.setEnabled(True)


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)
    QtCore.QLocale.setDefault(QtCore.QLocale(QtCore.QLocale.Spanish))
    w = Widget()
    w.resize(400, 400)
    w.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()