While I was working on a desktop application that needed to allow users to select dates for event scheduling. The PyQt6 QCalendarWidget was the perfect solution for this task.
In this article, I will walk you through everything you need to know about implementing and customizing the QCalendarWidget in your PyQt6 applications.
So let’s get in!
Basic Implementation of QCalendarWidget
Let’s start with the simplest implementation of a QCalendarWidget in Python PyQt6:
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QCalendarWidget
from PyQt6.QtCore import QDate
class CalendarApp(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Simple Calendar")
self.setGeometry(300, 300, 400, 300)
# Create a calendar widget
self.calendar = QCalendarWidget()
# Set today's date as selected
self.calendar.setSelectedDate(QDate.currentDate())
# Connect signal for date selection
self.calendar.selectionChanged.connect(self.on_date_selected)
# Create layout and add calendar
layout = QVBoxLayout()
layout.addWidget(self.calendar)
self.setLayout(layout)
def on_date_selected(self):
selected_date = self.calendar.selectedDate()
print(f"Selected date: {selected_date.toString('MM/dd/yyyy')}")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = CalendarApp()
window.show()
sys.exit(app.exec())I executed the above example code and added the screenshot below.

This code creates a simple window with a calendar widget. When you click on a date, it will print the selected date in the console in MM/dd/yyyy format.
Customize the Calendar’s Appearance
One of the great things about QCalendarWidget in PyQt6 is how customizable it is. Let’s look at some common ways to customize the appearance:
# Set the first day of the week to Monday
self.calendar.setFirstDayOfWeek(1) # Qt.Monday is 1
# Set the grid visible
self.calendar.setGridVisible(True)
# Set the date format
self.calendar.setDateFormat("yyyy-MM-dd")
# Customize colors
from PyQt6.QtGui import QColor, QTextCharFormat
from PyQt6.QtCore import Qt
fmt = QTextCharFormat()
fmt.setBackground(QColor(0, 255, 0, 50)) # Light green with some transparency
fmt.setForeground(QColor(0, 0, 255)) # Blue text
# Apply this format to a specific date
special_date = QDate(2023, 11, 15)
self.calendar.setDateTextFormat(special_date, fmt)
# Change header format
header_fmt = QTextCharFormat()
header_fmt.setBackground(QColor(100, 150, 250))
header_fmt.setForeground(Qt.GlobalColor.white)
self.calendar.setHeaderTextFormat(header_fmt)I executed the above example code and added the screenshot below.

These customizations allow you to change the appearance of your calendar to match your application’s design.
Handle Calendar Events and Signals
Python QCalendarWidget emits signals when the user interacts with it. Here are the most common signals and how to connect them in PyQt6:
# When the selected date changes
self.calendar.selectionChanged.connect(self.on_date_selected)
# When the user clicks on a date
self.calendar.clicked.connect(self.on_date_clicked)
# When the user double-clicks on a date
self.calendar.activated.connect(self.on_date_activated)
# When the current page (month/year) changes
self.calendar.currentPageChanged.connect(self.on_page_changed)
def on_date_selected(self):
selected_date = self.calendar.selectedDate()
print(f"Date selected: {selected_date.toString()}")
def on_date_clicked(self, date):
print(f"Date clicked: {date.toString()}")
def on_date_activated(self, date):
print(f"Date activated (double-clicked): {date.toString()}")
def on_page_changed(self, year, month):
print(f"Calendar page changed to: {month}/{year}")I executed the above example code and added the screenshot below.

These signals make it easy to respond to user interactions with the calendar.
Read Create a Basic Window in PyQt6
Restrict Date Selection
In many applications, you might want to limit which dates a user can select. For example, in a booking system, you might want to prevent users from selecting dates in the past:
# Set minimum date to today (can't select dates before today)
self.calendar.setMinimumDate(QDate.currentDate())
# Set maximum date to 1 year from now
max_date = QDate.currentDate().addYears(1)
self.calendar.setMaximumDate(max_date)
# Disable specific dates (e.g., holidays)
def update_disabled_dates(self):
# Get the format for disabled dates
fmt = QTextCharFormat()
fmt.setForeground(QColor(200, 200, 200)) # Light gray
fmt.setBackground(QColor(240, 240, 240)) # Even lighter gray
# List of holidays or unavailable dates
holidays = [
QDate(2023, 12, 25), # Christmas
QDate(2023, 11, 23), # Thanksgiving
QDate(2023, 7, 4), # Independence Day
]
# Apply the format to each holiday
for holiday in holidays:
self.calendar.setDateTextFormat(holiday, fmt)This makes it clear to users which dates they can and cannot select.
Check out Create Dynamic Tables with QTableWidget in PyQt6
Integrate with Other Widgets
QCalendarWidget works well with other widgets. Here’s an example of integrating it with QLineEdit to create a date picker:
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QCalendarWidget, QLineEdit, QPushButton
from PyQt6.QtCore import QDate
class DatePickerApp(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Date Picker")
self.setGeometry(300, 300, 400, 400)
# Create a line edit for displaying the selected date
self.date_edit = QLineEdit()
self.date_edit.setReadOnly(True)
self.date_edit.setText(QDate.currentDate().toString("MM/dd/yyyy"))
# Create a button to show/hide the calendar
self.pick_button = QPushButton("Pick a date")
self.pick_button.clicked.connect(self.toggle_calendar)
# Create a calendar widget
self.calendar = QCalendarWidget()
self.calendar.setSelectedDate(QDate.currentDate())
self.calendar.clicked.connect(self.update_date)
self.calendar.setVisible(False) # Hidden by default
# Create layout
layout = QVBoxLayout()
layout.addWidget(self.date_edit)
layout.addWidget(self.pick_button)
layout.addWidget(self.calendar)
self.setLayout(layout)
def toggle_calendar(self):
self.calendar.setVisible(not self.calendar.isVisible())
if self.calendar.isVisible():
self.pick_button.setText("Hide calendar")
else:
self.pick_button.setText("Pick a date")
def update_date(self, date):
self.date_edit.setText(date.toString("MM/dd/yyyy"))
self.calendar.setVisible(False)
self.pick_button.setText("Pick a date")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = DatePickerApp()
window.show()
sys.exit(app.exec())This creates a clean date picker component that shows and hides the calendar as needed.
Practical Examples
Let’s look at a more practical example: an appointment scheduling application for a dental office in New York:
import sys
from PyQt6.QtWidgets import (QApplication, QMainWindow, QCalendarWidget,
QVBoxLayout, QHBoxLayout, QWidget, QLabel,
QPushButton, QComboBox, QMessageBox, QTimeEdit)
from PyQt6.QtCore import QDate, QTime, Qt
from PyQt6.QtGui import QTextCharFormat, QColor
class DentalAppointmentScheduler(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("NYC Dental Clinic - Appointment Scheduler")
self.setGeometry(100, 100, 800, 600)
# Main widget and layout
main_widget = QWidget()
main_layout = QHBoxLayout()
# Calendar section
calendar_layout = QVBoxLayout()
calendar_label = QLabel("Select Appointment Date:")
self.calendar = QCalendarWidget()
self.calendar.setGridVisible(True)
self.calendar.setFirstDayOfWeek(Qt.DayOfWeek.Monday)
# Set dates - clinic not open on weekends
self.update_calendar_availability()
# Time selection
time_layout = QVBoxLayout()
time_label = QLabel("Select Appointment Time:")
self.time_selector = QTimeEdit()
self.time_selector.setDisplayFormat("hh:mm AP")
self.time_selector.setTime(QTime(9, 0)) # 9:00 AM default
# Dentist selection
dentist_label = QLabel("Select Dentist:")
self.dentist_selector = QComboBox()
self.dentist_selector.addItems([
"Dr. Smith - General Dentistry",
"Dr. Johnson - Orthodontics",
"Dr. Williams - Pediatric Dentistry",
"Dr. Brown - Cosmetic Dentistry"
])
# Book button
self.book_button = QPushButton("Book Appointment")
self.book_button.clicked.connect(self.book_appointment)
# Add widgets to layouts
calendar_layout.addWidget(calendar_label)
calendar_layout.addWidget(self.calendar)
time_layout.addWidget(time_label)
time_layout.addWidget(self.time_selector)
time_layout.addWidget(dentist_label)
time_layout.addWidget(self.dentist_selector)
time_layout.addWidget(self.book_button)
time_layout.addStretch()
# Add layouts to main layout
main_layout.addLayout(calendar_layout, 2)
main_layout.addLayout(time_layout, 1)
# Set main layout
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
def update_calendar_availability(self):
today = QDate.currentDate()
self.calendar.setMinimumDate(today)
max_date = today.addMonths(3)
self.calendar.setMaximumDate(max_date)
# Disable weekends visually
weekend_format = QTextCharFormat()
weekend_format.setForeground(QColor("lightgray"))
current_date = QDate(today)
while current_date <= max_date:
if current_date.dayOfWeek() in [Qt.DayOfWeek.Saturday, Qt.DayOfWeek.Sunday]:
self.calendar.setDateTextFormat(current_date, weekend_format)
current_date = current_date.addDays(1)
def book_appointment(self):
selected_date = self.calendar.selectedDate()
selected_time = self.time_selector.time().toString("hh:mm AP")
selected_dentist = self.dentist_selector.currentText()
if selected_date.dayOfWeek() in [Qt.DayOfWeek.Saturday, Qt.DayOfWeek.Sunday]:
QMessageBox.warning(self, "Unavailable", "Appointments cannot be booked on weekends.")
return
QMessageBox.information(
self,
"Appointment Confirmed",
f"Your appointment is booked for:\n"
f"Date: {selected_date.toString('dddd, MMMM d, yyyy')}\n"
f"Time: {selected_time}\n"
f"Dentist: {selected_dentist}"
)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = DentalAppointmentScheduler()
window.show()
sys.exit(app.exec())This dental appointment scheduler demonstrates the practical use of QCalendarWidget, QTimeEdit, and user input widgets in PyQt6. It provides an intuitive way to book appointments while enforcing scheduling rules like weekday availability.
In this QCalendarWidget in PyQt6 tutorial, I explained about basic implementation of QCalendarWidget, customizing the appearance, handling events and signals, integrating with another widget, and a practical example.
You may read:
- Build a Simple Digital Clock with QLCDNumber in PyQt6
- How to Use QSlider Widget in PyQt6
- Use QInputDialog in PyQt6

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.