填充 QCalendarWidget
Populating a QCalendarWidget
我创建了一个 GUI 来通过 PyQt QCalendarWidget 显示一些 运行ning 锻炼。以下代码基于这些帖子:
- How to add text to PyQt QcalendarWidget
我创建了一个子类来覆盖 paint 方法。当我在 paintCell 方法中硬编码了一个日期时,这很好用。但理想情况下,我想先 运行 一个函数,它将 return 一组 dates/running 距离作为数据帧。然后,该数据框将用于“填充”QCalendarWidget(例如,通过添加 运行ning 距离作为相应日期的文本)。
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 是一个简单的 Widget/container,它是我通过 QtDesigner 创建的,我通过 Calendar 方法将其初始化为 CalendarWidget。长话短说:在初始化 CalendarWidget 之后,如何使用中间函数的结果更新它?
编辑:我对标签的错误是 PySide2 而不是 PyQt
一个可能的解决方案是创建一个属性,在setter中使用内部QTableView视口的update()
方法,这将调用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()
我创建了一个 GUI 来通过 PyQt QCalendarWidget 显示一些 运行ning 锻炼。以下代码基于这些帖子:
- How to add text to PyQt QcalendarWidget
我创建了一个子类来覆盖 paint 方法。当我在 paintCell 方法中硬编码了一个日期时,这很好用。但理想情况下,我想先 运行 一个函数,它将 return 一组 dates/running 距离作为数据帧。然后,该数据框将用于“填充”QCalendarWidget(例如,通过添加 运行ning 距离作为相应日期的文本)。
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 是一个简单的 Widget/container,它是我通过 QtDesigner 创建的,我通过 Calendar 方法将其初始化为 CalendarWidget。长话短说:在初始化 CalendarWidget 之后,如何使用中间函数的结果更新它?
编辑:我对标签的错误是 PySide2 而不是 PyQt
一个可能的解决方案是创建一个属性,在setter中使用内部QTableView视口的update()
方法,这将调用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()