Skip to content Skip to sidebar Skip to footer

Qml Calendar And Google Calendar Api In Python Events Integration

I'm currently working on creating a QML Calendar that will ideally display events from a Google calendar. This is an example of what I'd like to emulate in python: https://doc.qt.i

Solution 1:

Before modifying any code you must understand the code and understand that it is different with what you want. And in your case there is a difference: The data is not accessed quickly but you have to make a request that is time consuming and can block the GUI.

So before the above it is better to download the events (perhaps save it in a database like sqlite and use the original example) to have it as a cache and thus minimize the amount of downloads.

Then you must separate the logic: Create a class that exports the information to QML, and another class that obtains it.

Since the information will be reloaded every time there is an event, it is better to use a Loader that redraws the GUI every time the cache is updated.

Note: I have used the official example

main.py

import logging
import os
import pickle
import sys
import threading

from PySide2 import QtCore, QtGui, QtQml

from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request


SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"]
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))


logging.basicConfig(level=logging.DEBUG)


classCalendarBackend(QtCore.QObject):
    eventsChanged = QtCore.Signal(list)

    def__init__(self, parent=None):
        super().__init__(parent)
        self._service = None    @propertydefservice(self):
        return self._service

    defupdateListEvents(self, kw):
        threading.Thread(target=self._update_list_events, args=(kw,)).start()

    def_update_list_events(self, kw):
        self._update_credentials()

        events_result = self.service.events().list(**kw).execute()
        events = events_result.get("items", [])

        qt_events = []
        ifnot events:
            logging.debug("No upcoming events found.")
        for event in events:
            start = event["start"].get("dateTime", event["start"].get("date"))
            end = event["end"].get("dateTime", event["end"].get("date"))
            logging.debug(f"From {start} - To {end}:  {event['summary']}")

            start_dt = QtCore.QDateTime.fromString(start, QtCore.Qt.ISODate)
            end_dt = QtCore.QDateTime.fromString(end, QtCore.Qt.ISODate)
            summary = event["summary"]

            e = {"start": start_dt, "end": end_dt, "summary": summary}
            qt_events.append(e)

        self.eventsChanged.emit(qt_events)

    def_update_credentials(self):
        creds = Noneif os.path.exists("token.pickle"):
            withopen("token.pickle", "rb") as token:
                creds = pickle.load(token)
        ifnot creds ornot creds.valid:
            if creds and creds.expired and creds.refresh_token:
                creds.refresh(Request())
            else:
                flow = InstalledAppFlow.from_client_secrets_file(
                    "credentials.json", SCOPES
                )
                creds = flow.run_local_server(port=0)
            withopen("token.pickle", "wb") as token:
                pickle.dump(creds, token)

        self._service = build("calendar", "v3", credentials=creds)


classCalendarProvider(QtCore.QObject):
    loaded = QtCore.Signal()

    def__init__(self, parent=None):
        super().__init__(parent)

        self._cache_events = []
        self._backend = CalendarBackend()
        self._backend.eventsChanged.connect(self._handle_events)

    @QtCore.Slot("QVariant")defupdateListEvents(self, parameters):
        d = dict()
        for k, v in parameters.toVariant().items():
            ifisinstance(v, QtCore.QDateTime):
                v = v.toTimeSpec(QtCore.Qt.OffsetFromUTC).toString(
                    QtCore.Qt.ISODateWithMs
                )
            d[k] = v
        self._backend.updateListEvents(d)

    @QtCore.Slot(QtCore.QDate, result="QVariantList")defeventsForDate(self, date):
        events = []
        for event in self._cache_events:
            start = event["start"]
            if start.date() == date:
                events.append(event)
        return events

    @QtCore.Slot(list)def_handle_events(self, events):
        self._cache_events = events
        self.loaded.emit()
        logging.debug("Loaded")


defmain():
    app = QtGui.QGuiApplication(sys.argv)

    QtQml.qmlRegisterType(CalendarProvider, "MyCalendar", 1, 0, "CalendarProvider")

    engine = QtQml.QQmlApplicationEngine()
    filename = os.path.join(CURRENT_DIR, "main.qml")
    engine.load(QtCore.QUrl.fromLocalFile(filename))

    ifnot engine.rootObjects():
        sys.exit(-1)

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

main.qml

importQtQuick2.2importQtQuick.Controls1.2importQtQuick.Controls.Private1.0importQtQuick.Controls.Styles1.1importMyCalendar1.0ApplicationWindow {
    visible:truewidth:640height:400minimumWidth:400minimumHeight:300color:"#f4f4f4"title:"Calendar Example"SystemPalette {
        id:systemPalette
    }

    CalendarProvider {
        id:eventModelonLoaded: {
            //reloadloader.sourceComponent=nullloader.sourceComponent=page_component
        }
        Component.onCompleted: {
            eventModel.updateListEvents({
                calendarId:"primary",
                timeMin:newDate(),
                maxResults:10,
                singleEvents:true,
                orderBy:"startTime",
            })
        }
    }

    Loader{
        id:loaderanchors.fill:parentsourceComponent:page_component
    }

    Component{
        id:page_componentFlow {
            id:rowanchors.fill:parentanchors.margins:20spacing:10layoutDirection:Qt.RightToLeftCalendar {
                id:calendarwidth:(parent.width>parent.height?parent.width*0.6 - parent.spacing :parent.width)height:(parent.height>parent.width?parent.height*0.6 - parent.spacing :parent.height)frameVisible:trueweekNumbersVisible:trueselectedDate:newDate()focus:truestyle:CalendarStyle {
                    dayDelegate:Item {
                        readonly property color sameMonthDateTextColor:"#444"readonly property color selectedDateColor:Qt.platform.os==="osx"?"#3778d0":systemPalette.highlightreadonly property color selectedDateTextColor:"white"readonly property color differentMonthDateTextColor:"#bbb"readonly property color invalidDatecolor:"#dddddd"Rectangle {
                            anchors.fill:parentborder.color:"transparent"color:styleData.date!==undefined&&styleData.selected?selectedDateColor :"transparent"anchors.margins:styleData.selected?-1:0
                        }

                        Image {
                            visible:eventModel.eventsForDate(styleData.date).length>0anchors.top:parent.topanchors.left:parent.leftanchors.margins:-1width:12height:widthsource:"images/eventindicator.png"
                        }

                        Label {
                            id:dayDelegateTexttext:styleData.date.getDate()anchors.centerIn:parentcolor: {
                                varcolor=invalidDatecolor;if(styleData.valid) {
                                    //Dateiswithinthevalidrange.color=styleData.visibleMonth?sameMonthDateTextColor :differentMonthDateTextColor;if(styleData.selected) {
                                        color=selectedDateTextColor;
                                    }
                                }
                                color;
                            }
                        }
                    }
                }
            }

            Component {
                id:eventListHeaderRow {
                    id:eventDateRowwidth:parent.widthheight:eventDayLabel.heightspacing:10Label {
                        id:eventDayLabeltext:calendar.selectedDate.getDate()font.pointSize:35
                    }

                    Column {
                        height:eventDayLabel.heightLabel {
                            readonly property var options: { weekday:"long" }
                            text:Qt.locale().standaloneDayName(calendar.selectedDate.getDay(), Locale.LongFormat)font.pointSize:18
                        }
                        Label {
                            text:Qt.locale().standaloneMonthName(calendar.selectedDate.getMonth())+calendar.selectedDate.toLocaleDateString(Qt.locale(), " yyyy")font.pointSize:12
                        }
                    }
                }
            }

            Rectangle {
                width:(parent.width>parent.height?parent.width*0.4 - parent.spacing :parent.width)height:(parent.height>parent.width?parent.height*0.4 - parent.spacing :parent.height)border.color:Qt.darker(color, 1.2)ListView {
                    id:eventsListViewspacing:4clip:trueheader:eventListHeaderanchors.fill:parentanchors.margins:10model:eventModel.eventsForDate(calendar.selectedDate)delegate:Rectangle {
                        width:eventsListView.widthheight:eventItemColumn.heightanchors.horizontalCenter:parent.horizontalCenterImage {
                            anchors.top:parent.topanchors.topMargin:4width:12height:widthsource:"images/eventindicator.png"
                        }

                        Rectangle {
                            width:parent.widthheight:1color:"#eee"
                        }

                        Column {
                            id:eventItemColumnanchors.left:parent.leftanchors.leftMargin:20anchors.right:parent.rightheight:timeLabel.height+nameLabel.height+8Label {
                                id:nameLabelwidth:parent.widthwrapMode:Text.Wraptext:modelData["summary"]
                            }
                            Label {
                                id:timeLabelwidth:parent.widthwrapMode:Text.Wraptext:modelData.start.toLocaleTimeString(calendar.locale, Locale.ShortFormat)+"-"+modelData.end.toLocaleTimeString(calendar.locale, Locale.ShortFormat)color:"#aaa"
                            }
                        }
                    }
                }
            }
        }
    }
}

enter image description here

The full example is here

Post a Comment for "Qml Calendar And Google Calendar Api In Python Events Integration"