0

我创建了一个 GUI 来通过 PyQt QCalendarWidget 显示一些正在运行的锻炼。以下代码基于这些帖子:

我创建了一个子类来覆盖paint方法。当我在 paintCell 方法中硬编码日期时,这可以正常工作。但理想情况下,我想先运行一个函数,它将一组日期/运行距离作为数据框返回。然后,该数据框将用于“填充” QCalendarWidget(例如,通过将运行距离添加为相应日期的文本)。

class MyQtApp(trigui.Ui_MainWindow, QtWidgets.QMainWindow):
    def __init__(self):
        super(MyQtApp, self).__init__()
        self.setupUi(self)
        self.Calendar()
        self.df = pd.DataFrame()
        self.qPlan_Create_btn.clicked.connect(self.draw_running_plan)

    def Calendar(self):
        self.cal = CalendarWidget(self.qPlan_Widget)
        self.cal.resize(1700, 800)

    def draw_running_plan(self):
        self.df = pd.DataFrame([[25-05-2021, 10], [27-05-2021, 12]], columns=['Date', 'Distance'])
       #########
       # how can I pass this dataframe to the paintCell

class CalendarWidget(QtWidgets.QCalendarWidget):
    def paintCell(self, painter, rect, date):
        painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
        if date == QtCore.QDate(2021, 5, 15):
            painter.save()
            painter.drawRect(rect)
            painter.setPen(QtGui.QColor(168, 34, 3))
            painter.drawText(rect, QtCore.Qt.AlignHCenter, 'Hello\nWorld')
            painter.drawText(QtCore.QRectF(rect), 
             QtCore.Qt.TextSingleLine|QtCore.Qt.AlignCenter, str(date.day()))

            painter.restore()
        else:
            QtWidgets.QCalendarWidget.paintCell(self, painter, rect, date)

def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)
    qt_app = MyQtApp()
    qt_app.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

不知何故,我需要从我的__init__. 我试图在我的函数 draw_running_plan 中设置 self.cal = CalendarWidget (self.qPlan_Widget) 但是日历没有显示。对于信息,self.qPlan_Widget 是我通过 QtDesigner 创建的一个简单的 Widget/容器,我通过 Calendar 方法将其初始化为 CalendarWidget。长话短说:初始化 CalendarWidget 后,如何使用中间函数的结果更新它?

编辑:我关于标签的错误是 PySide2 而不是 PyQt

4

1 回答 1

2

一个可能的解决方案是创建一个属性,update()在 setter 中使用内部 QTableView 视口的方法,这将调用 paintEvent 方法,该方法在其逻辑中调用该paintCell()方法:

另一方面,对于过滤,最好将日期字符串列(至少看起来是 OP 提供的)转换为日期时间。然后根据一天的最小日期和第二天的最小日期进行过滤。

import pandas as pd
from PySide2 import QtCore, QtGui, QtWidgets
import datetime


class CalendarWidget(QtWidgets.QCalendarWidget):
    _dataframe = pd.DataFrame()

    @property
    def dataframe(self):
        return self._dataframe

    @dataframe.setter
    def dataframe(self, df):
        self._dataframe = df.copy()
        view = self.findChild(QtWidgets.QTableView, "qt_calendar_calendarview")
        if view is not None:
            view.viewport().update()

    def paintCell(self, painter, rect, date):
        painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
        if self._dataframe.empty:
            QtWidgets.QCalendarWidget.paintCell(self, painter, rect, date)
            return

        if hasattr(date, "toPyDate"):
            dt_start = datetime.datetime.combine(
                date.toPyDate(), datetime.datetime.min.time()
            )
        else:
            dt_start = datetime.datetime.strptime(
                date.toString("yyyy-MM-dd"), "%Y-%m-%d"
            )

        dt_end = dt_start + datetime.timedelta(days=1)

        mask = (dt_start <= self.dataframe["Date"]) & (self.dataframe["Date"] < dt_end)
        res = self.dataframe.loc[mask]
        if res.empty:
            QtWidgets.QCalendarWidget.paintCell(self, painter, rect, date)
        else:
            value = res.iloc[0, res.columns.get_loc("Distance")]

            painter.save()
            painter.drawRect(rect)
            painter.setPen(QtGui.QColor(168, 34, 3))
            painter.drawText(
                QtCore.QRectF(rect),
                QtCore.Qt.TextSingleLine | QtCore.Qt.AlignCenter,
                str(value),
            )
            painter.restore()


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        button = QtWidgets.QPushButton("Change")
        self.calendar_widget = CalendarWidget()

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)

        lay = QtWidgets.QVBoxLayout(central_widget)
        lay.addWidget(button)
        lay.addWidget(self.calendar_widget)

        button.clicked.connect(self.handle_clicked)

    def handle_clicked(self):
        import random

        df = pd.DataFrame(
            [
                ["25-05-2021", random.randint(0, 100)],
                ["27-05-2021", random.randint(0, 100)],
            ],
            columns=["Date", "Distance"],
        )
        df["Date"] = pd.to_datetime(df["Date"])
        self.calendar_widget.dataframe = df


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)

    widget = MainWindow()
    widget.show()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
于 2021-05-04T17:30:01.170 回答