Beispiel für ein Kalender-Backend-Plugin
QCalendar Beispiel zur Veranschaulichung von benutzerdefinierten Kalendern.

Einleitung
Weltweit sind zahlreiche verschiedene Kalendersysteme im Einsatz. Qt bietet für einige davon integrierte Unterstützung (siehe System), kann jedoch aufgrund der großen Anzahl keine allgemeine Unterstützung bereitstellen. Zusätzliche Kalendersysteme können durch die Implementierung eines benutzerdefinierten QCalendarBackend bereitgestellt werden, bei dem es sich um eine private API handelt.
Dieses Beispiel zeigt, wie man ein benutzerdefiniertes Kalender-Backend schreibt und wie man die Low-Level-Plugin-API nutzt, um eine Anwendung um vom Benutzer wählbare Kalender zu erweitern. Viele Länder sind im Laufe ihrer Geschichte vom julianischen zum gregorianischen Kalender übergegangen, und dieses benutzerdefinierte Kalender-Backend wird den jeweiligen Kalender als Beispiel implementieren. Das benutzerdefinierte Backend wird zu einem Plugin kompiliert und zur Laufzeit von der Hauptanwendung geladen. Das genaue Umstellungsdatum, das je nach Region unterschiedlich ist, wird dem Plugin als Zeichenkette übergeben und kann vom Benutzer festgelegt werden.
Kalender-Backend
Die Kalender-Backend-Klasse muss von ` QCalendarBackend ` erben und deren rein virtuelle Funktionen auf eine „ thread-safe “-Weise implementieren. Bei Bedarf kann sie auch einige andere virtuelle Funktionen überschreiben.
Beispielimplementierung
Dieses Beispiel erbt von der bereits vorhandenen Klasse ` QRomanCalendar`, die wiederum von der Klasse ` QCalendarBackend ` erbt und einige ihrer virtuellen Funktionen implementiert. Dies ist sinnvoll, da der Übergangskalender sowohl mit dem julianischen als auch mit dem gregorianischen Kalender Teile gemeinsam hat, die vom römischen Kalender bereitgestellt werden.
Hier ist die Klassendeklaration von ` JulianGregorianCalendar`:
class JulianGregorianCalendar : public QRomanCalendar
{
public:
JulianGregorianCalendar(QDate endJulian, QAnyStringView name);
QString name() const override;
int daysInMonth(int month, int year = QCalendar::Unspecified) const override;
bool isLeapYear(int year) const override;
bool dateToJulianDay(int year, int month, int day, qint64 *jd) const override;
QCalendar::YearMonthDay julianDayToDate(qint64 jd) const override;
private:
static inline const QCalendar julian = QCalendar(QCalendar::System::Julian);
static inline const QCalendar gregorian = QCalendar(QCalendar::System::Gregorian);
QCalendar::YearMonthDay m_julianUntil;
QCalendar::YearMonthDay m_gregorianSince;
QString m_name;
};Die an den Konstruktor übergebene ` QDate ` – ` endJulian ` – ist das Datum des letzten Tages des julianischen Kalenders. Der Kalender berechnet automatisch die Verschiebung für ein bestimmtes Jahr; so wurden beispielsweise im Jahr 1582 10 Tage ausgelassen, im Jahr 1700 hingegen 12 Tage. Das Kalender-Backend ist unter „ name “ registriert, und unter diesem Namen kann eine Kalenderinstanz erstellt werden. Die Klasse überschreibt nur Funktionen, bei denen sich die beiden von ihr kombinierten Kalender vom römischen Basis-Kalender unterscheiden. Sie verfügt über Instanzen des julianischen und des gregorianischen Kalenders, an die diese Funktionen delegiert werden können.
Umrechnungen des julianischen Tages
dateToJulianDay(int year, int month, int day, qint64 *jd) berechnet die julianische Tageszahl, die dem angegebenen „ year “, „ month “ und „ day “ entspricht. Gibt „ true “ zurück und setzt „ jd “, falls ein solches Datum in diesem Kalender vorhanden ist; andernfalls wird „ false “ zurückgegeben.
bool JulianGregorianCalendar::dateToJulianDay(int year, int month, int day, qint64 *jd) const
{
if (year == m_julianUntil.year && month == m_julianUntil.month) {
if (m_julianUntil.day < day && day < m_gregorianSince.day) {
// Requested date is in the gap skipped over by the transition.
*jd = 0;
return false;
}
}
QDate givenDate = gregorian.dateFromParts(year, month, day);
QDate julianUntil = julian.dateFromParts(m_julianUntil);
if (givenDate > julianUntil) {
*jd = givenDate.toJulianDay();
return true;
}
*jd = julian.dateFromParts(year, month, day).toJulianDay();
return true;
}julianDayToDate(qint64 jd) Berechnet Jahr, Monat und Tag in diesem Kalender für die angegebene julianische Tageszahl, jd. Liegt der angegebene Tag außerhalb des Gültigkeitsbereichs dieses Kalenders, ist der Rückgabewert für isValid() false . In diesem Beispiel gilt: Liegt das angegebene Datum in der Lücke, die durch den Übergang vom julianischen zum gregorianischen Kalender übersprungen wurde, liegt es außerhalb des Gültigkeitsbereichs.
QCalendar::YearMonthDay JulianGregorianCalendar::julianDayToDate(qint64 jd) const
{
const qint64 jdForChange = julian.dateFromParts(m_julianUntil).toJulianDay();
if (jdForChange < jd) {
QCalendar gregorian(QCalendar::System::Gregorian);
QDate date = QDate::fromJulianDay(jd);
return gregorian.partsFromDate(date);
} else if (jd <= jdForChange) {
QCalendar julian(QCalendar::System::Julian);
QDate date = QDate::fromJulianDay(jd);
return julian.partsFromDate(date);
}
return QCalendar::YearMonthDay(QCalendar::Unspecified, QCalendar::Unspecified,
QCalendar::Unspecified);
}Unterstützung von Ländereinstellungen
Ein Kalender kann im Allgemeinen eigene Bezeichnungen für die Monate des Jahres und die Wochentage haben. Diese müssen entsprechend lokalisiert werden, damit sie für alle Benutzer verständlich sind. Standardmäßig übernimmt die Backend-Basisklasse die Wochentagsbezeichnungen für uns, was für diese Kalender im Übergang vom julianischen zum gregorianischen Kalender völlig ausreichend ist.
Obwohl ein Backend die Methoden zur Monatsbenennung direkt überschreiben kann, lässt sich die Version der Basisklasse anpassen, indem man die Methoden ` localeMonthData() ` und ` localeMonthIndexData() ` implementiert, um Tabellen mit lokalisierten Monatsnamen bereitzustellen. Da der julianische und der gregorianische Kalender dieselbe Monatsbezeichnung verwenden, erben sie diese Anpassung von einer gemeinsamen Basisklasse, QRomanCalendar. Das bedeutet auch, dass der benutzerdefinierte Kalender dieselben Namen verwenden kann, indem er ebenfalls von dieser Basisklasse erbt. Damit ist die Lokalisierung gewährleistet.
Plugin
Qt-Anwendungen können durch Plugins erweitert werden. Dazu muss die Anwendung Plugins mithilfe von QPluginLoader erkennen und laden.
Ein Plugin erstellen
Um ein Plugin zu schreiben, muss zunächst eine rein virtuelle Klasse erstellt werden, die die Schnittstelle zwischen Plugin und Anwendung definiert.
In diesem Beispiel wurde die folgende Schnittstelle verwendet:
class RequestedCalendarInterface
{
public:
RequestedCalendarInterface() = default;
virtual QCalendar::SystemId loadCalendar(QAnyStringView requested) = 0;
virtual ~RequestedCalendarInterface() = default;
};und diese im Qt-Metaobjektsystem registrieren:
#define RequestedCalendarInterface_iid \
"org.qt-project.Qt.Examples.CalendarBackend.RequestedCalendarInterface/1.0"
Q_DECLARE_INTERFACE(RequestedCalendarInterface, RequestedCalendarInterface_iid)Q_DECLARE_INTERFACEDas Makro () wird verwendet, um die Schnittstelle „ ClassName “ (hier: RequestedCalendarInterface) mit der definierten Schnittstelle „ Identifier “ (hier: RequestedCalendarInterface_iid) zu verknüpfen. Die Schnittstelle „ Identifier “ muss eindeutig sein. Diese Schnittstelle kann von Plugins implementiert werden, die andere Kalender laden und den Zeichenfolgenparameter von „ loadCalendar() “ auf verschiedene Weise interpretieren. Sie ist nicht auf dieses bestimmte Plugin beschränkt, das damit implementiert wird, daher hat sie einen generischen Namen und keinen, der spezifisch für dieses bestimmte Backend ist.
Anschließend wird eine Plugin-Klasse erstellt, die von „ QObject “ und von der Schnittstelle erbt.
class JulianGregorianPlugin : public QObject, public RequestedCalendarInterface
{
Q_OBJECT
Q_INTERFACES(RequestedCalendarInterface)
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples."
"CalendarBackend."
"RequestedCalendarInterface/1.0")
public:
JulianGregorianPlugin();
QCalendar::SystemId loadCalendar(QAnyStringView request) override;
~JulianGregorianPlugin();
};Q_PLUGIN_METADATAMit `()` und ` Q_INTERFACES()` werden Metadaten deklariert, die auch in der Schnittstellenklasse deklariert wurden, und Qt wird mitgeteilt, welche Schnittstelle die Klasse implementiert.
Dieses Plugin instanziiert und registriert ein benutzerdefiniertes Kalender-Backend, das wiederum von der Anwendung jederzeit zur Instanziierung von ` QCalendar ` verwendet werden kann.
Qt-Plugins werden in einer einzigen gemeinsam genutzten Bibliothek (einer DLL) gespeichert, und „ QPluginLoader “ wird zum Erkennen und dynamischen Laden der Plugin-Datei verwendet (weitere Informationen finden Sie unter „So erstellen Sie Qt-Plugins“).
Laden des Plugins
QPluginLoader prüft, ob die Qt-Version des Plugins mit der der Anwendung übereinstimmt, und ermöglicht den direkten Zugriff auf ein Qt-Plugin.
Hier ist die Verwendung von „ QPluginLoader “ im Beispiel:
QPluginLoader loader;
loader.setFileName("../plugin/calendarPlugin");
loader.load();
if (!loader.isLoaded())
return 1;
auto *myplugin = qobject_cast<RequestedCalendarInterface*>(loader.instance());Zunächst muss eine Instanz eines ` QPluginLoader `-Objekts initialisiert werden. Anschließend muss durch Übergabe eines DLL-Dateinamens an ` setFileName()` angegeben werden, welches Plugin geladen werden soll. Dann wird die Plugin-Datei mithilfe von ` load()` dynamisch geladen. Abschließend wird mit einem Aufruf von ` qobject_cast()` geprüft, ob ein Plugin eine bestimmte Schnittstelle implementiert. ` qobject_cast()` nutzt ` instance()`, um auf die Stammkomponente im Plugin zuzugreifen. Wenn das Plugin korrekt geladen wurde, sollten seine Funktionen verfügbar sein.
Instanziierung des Backends
In diesem Beispiel gibt es nur eine Funktion im Plugin. ` loadCalendar() ` ist dafür zuständig, das benutzerdefinierte Kalender-Backend in ` QCalendarRegistry ` mit dem angegebenen Übergangsdatum und den Namen zu registrieren.
QCalendar::SystemId JulianGregorianPlugin::loadCalendar(QAnyStringView request)
{
Q_ASSERT(!request.isEmpty());
QStringList names = request.toString().split(u';');
if (names.size() < 1)
return {};
QString dateString = names.takeFirst();
auto date = QDate::fromString(dateString, u"yyyy-MM-dd",
QCalendar(QCalendar::System::Julian));
if (!date.isValid())
return {};
QString primary = names.isEmpty() ?
QString::fromStdU16String(u"Julian until ") + dateString : names[0];
auto backend = new JulianGregorianCalendar(date, primary);
names.emplaceFront(backend->name());
auto cid = backend->registerCustomBackend(names);
return cid;
}
JulianGregorianPlugin::~JulianGregorianPlugin()
{
}Das String-Argument für ` loadCalendar() ` wird vom Benutzer über Befehlszeilenargumente bereitgestellt. Anschließend wird das Datum des Übergangs vom julianischen zum gregorianischen Kalender durch Aufspalten des angegebenen Strings extrahiert. Nach der Validierung wird ein benutzerdefiniertes Backend-Objekt erstellt. Das Backend muss vor seiner Verwendung in „ QCalendar “ mithilfe der Methode „ registerCustomBackend() “ registriert werden. Sobald ein Backend registriert ist, kann ein „ QCalendar “ mit dem entsprechenden „ SystemId “ oder „ name “ instanziiert werden.
Hier sehen Sie die Verwendung von ` loadCalendar ` in der Datei ` main`:
const auto cid = myplugin->loadCalendar(args.at(0));
if (!cid.isValid()) {
qWarning() << "Invalid ID";
parser.showHelp(1);
}
const QCalendar calendar(cid);Erweiterung von QCalendarWidget
Durch das Erstellen einer ` QCalendar `-Instanz mit einem bestimmten Kalender als Backend ist es möglich, ` QCalendarWidget ` mit diesem Backend zu versorgen und es darzustellen.
QCalendarWidget widget;
widget.setCalendar(calendar);
widget.show();
QCalendar::YearMonthDay when = { 1582, 10, 4 };
QCalendar julian = QCalendar(QCalendar::System::Julian);
auto got = QDate::fromString(args.at(0).left(10), u"yyyy-MM-dd", julian);
if (got.isValid())
when = julian.partsFromDate(got);
widget.setCurrentPage(when.year, when.month);Siehe auch QCalendarWidget, QCalendar, QDate, QLocale, QtPlugin und QPluginLoader.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.