Development/Tutorials/Plasma4/GettingStarted (de): Difference between revisions

    From KDE TechBase
    m (Text replace - "<code cppqt>" to "<syntaxhighlight lang="cpp-qt">")
    Line 52: Line 52:


    '''plasma-tutorial1.h'''
    '''plasma-tutorial1.h'''
    <code cppqt>
    <syntaxhighlight lang="cpp-qt">
    // Hiermit wird vermieden, dass der header mehrmals eingelesen wird
    // Hiermit wird vermieden, dass der header mehrmals eingelesen wird
    #ifndef Tutorial1_HEADER
    #ifndef Tutorial1_HEADER
    Line 111: Line 111:


    '''plasma-tutorial1.cpp'''
    '''plasma-tutorial1.cpp'''
    <code cppqt>
    <syntaxhighlight lang="cpp-qt">
    #include "plasma-tutorial1.h"
    #include "plasma-tutorial1.h"
    #include <QPainter>
    #include <QPainter>

    Revision as of 20:29, 29 June 2011


    Development/Tutorials/Plasma/GettingStarted


    Programmiere Dein erstes Plasmoid
    Tutorial Series   Plasma Tutorial
    Previous   C++, Qt, KDE4 development environment
    What's Next  
    Further Reading   CMake

    Übersicht

    Dieses Tutorial setzt KDE 4.2 voraus. Wir werden ein einfaches Plasmoid erstellen. Um es einfach zu halten, programmieren wir lediglich ein statisches Plasmoid, welches folgende Eigenschaften mitbringt:

    • Eine SVG-Grafik
    • ein Icon
    • einen freudlichen Text

    Der Code

    Die .desktop Datei

    Für jedes Plasmoid wird eine .desktop Datei benötigt, die Plasma beschreibt, wie es zu starten ist und welchen Namen es besitzt.

    plasma-applet-tutorial1.desktop [Desktop Entry] Name=Tutorial 1 Comment=Plasma Tutorial 1 Type=Service ServiceTypes=Plasma/Applet

    X-KDE-Library=plasma_applet_tutorial1 X-KDE-PluginInfo-Author=Bas Grolleman [email protected] X-KDE-PluginInfo-Name=plasma_applet_tutorial1 X-KDE-PluginInfo-Version=0.1 X-KDE-PluginInfo-Website=http://plasma.kde.org/ X-KDE-PluginInfo-Category=Examples X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true

    Die wichtigsten Einträge sind X-KDE-Library und X-KDE-PluginInfo-Name, diese beiden stellen die Nahtstelle zwischen deiner Klasse und Plasma dar. Ohne diese Einträge würde nichts funktionieren. Weitere Infos zu X-KDE-PluginInfo-Category siehe PIG.

    Die Header-Datei

    plasma-tutorial1.h <syntaxhighlight lang="cpp-qt"> // Hiermit wird vermieden, dass der header mehrmals eingelesen wird

    1. ifndef Tutorial1_HEADER
    2. define Tutorial1_HEADER

    // Laden der Plasma Applet Header

    1. include <KIcon>
    1. include <Plasma/Applet>
    2. include <Plasma/Svg>

    class QSizeF;

    // Unser Plasma Applet class PlasmaTutorial1 : public Plasma::Applet {

       Q_OBJECT
       public:
           // Konstruktor / Destruktor
           PlasmaTutorial1(QObject *parent, const QVariantList &args);
           ~PlasmaTutorial1();
    
           // paintInterface zeichnet das Applet auf den Bildschirm
           void paintInterface(QPainter *painter,
                   const QStyleOptionGraphicsItem *option,
                   const QRect& contentsRect);
    

    void init();

       private:
           Plasma::Svg m_svg;
           KIcon m_icon;
    

    };

    // Mit diesem Befehl wird das Applet mit dem .desktop-File verbunden K_EXPORT_PLASMA_APPLET(tutorial1, PlasmaTutorial1)

    1. endif

    QRectF boundingRect()

    Die Funktion boundingRect() teilt Plasma die aktuelle Größe des Plasmoid mit. Das ist notwendig, weil wir wissen müssen, wieviel Platz auf dem Bildschirm verwendet wird.

    Tip
    Wenn Probleme mit bleibenden Pixeln nach dem Verschieben des Plasmoid auftreten, ist dies gewöhnlich ein Resultat einer nicht korrekten boundingRect().


    void paintInterface(QRectF contentsRect)

    Diese Funktion kann als Hauptroutine angesehen werden, weil sie das Plasmoid auf den Bildschirm zeichnet. Hier wird bestimmt, wie dein Plasmoid aussieht. Du solltest nur innerhalb der Grenzen, die durch contentsRect bestimmt sind, zeichnen, geometry() sollte hier vermieden werden. Wenn ein Plasmoid keinen Standard-Hintergrund besitzt, z.B. weil es mit einem Aufruf von setBackgroundHints() deaktiviert wurde oder es sich im Panel befindet, verhalten sich geometry() und boundingRect() identisch. Wenn der Standard-Hintergrund jedoch aktiviert ist, also der Normalfall, soll das Applet im Randbereich nicht gezeichnet werden.

    K_EXPORT_PLASMA_APPLET ( <name>, <class> )

    Dieser kleine, aber doch wichtige Teil, ist essentiell, denn er verknüpft den Klassennamen mit dem Applet-Namen, der im .desktop-File definiert wurde. Wenn das Applet anscheinend nicht geladen wird, könnte hier das Problem liegen.

    Tip
    K_EXPORT_PLASMA_APPLET fügt automatisch "plasma_applet_" zum Namen hinzu. Dies muss beachtet werden, wenn das .desktop-File verändert wird.


    Das eigentliche Programm

    Hier die Implementiertug der Funktionen, wieder mit einigen Kommentaren versehen

    plasma-tutorial1.cpp <syntaxhighlight lang="cpp-qt">

    1. include "plasma-tutorial1.h"
    2. include <QPainter>
    3. include <QFontMetrics>
    4. include <QSizeF>
    1. include <plasma/svg.h>
    2. include <plasma/theme.h>

    PlasmaTutorial1::PlasmaTutorial1(QObject *parent, const QVariantList &args)

       : Plasma::Applet(parent, args),
       m_svg(this),
       m_icon("document")
    

    {

       m_svg.setImagePath("widgets/background");
       // Den Standard-Applet-Hintergrund verwenden
       setBackgroundHints(DefaultBackground);
       resize(200, 200);
    

    }


    PlasmaTutorial1::~PlasmaTutorial1() {

       if (hasFailedToLaunch()) {
           // Hier wird aufgeräumt
       } else {
           // Einstellungen speichern
       }
    

    }

    void PlasmaTutorial1::init() {

       // Eine kleine Demonstration der Funktion setFailedToLaunch
       if (m_icon.isNull()) {
           setFailedToLaunch(true, "No world to say hello");
       }
    

    }


    void PlasmaTutorial1::paintInterface(QPainter *p,

           const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
    

    {

       p->setRenderHint(QPainter::SmoothPixmapTransform);
       p->setRenderHint(QPainter::Antialiasing);
    
       // Jetzt kann das Applet gezeichnet werden, zuerst das SVG
       m_svg.resize((int)contentsRect.width(), (int)contentsRect.height());
       m_svg.paint(p, (int)contentsRect.left(), (int)contentsRect.top());
    
       // Icon und Text einfügen
       p->drawPixmap(7, 0, m_icon.pixmap((int)contentsRect.width(),(int)contentsRect.width()-14));
       p->save();
       p->setPen(Qt::white);
       p->drawText(contentsRect,
                   Qt::AlignBottom | Qt::AlignHCenter,
                   "Hello Plasmoid!");
       p->restore();
    

    }

    1. include "plasma-tutorial1.moc"

    Plasma/Svg

    Wie du im Code gesehen hast, verwenden wir das Objekt Plasma::Svg. Hierzu sollte man folgendes wissen:

    Wir verwenden einen relativen Pfad widgets/background, was dazu führt, dass Plasma::Svg Plasma::Theme verwendet, um die SVG-Datei zu finden. Plasma::Svg lädt beliebige Dateien, wenn ein absoluter Pfad übergeben wird. Um den unterschiedlichen Plasmoids ein einheitliches Aussehen zu geben anstatt wie eine zusammengewürfelte Sammlung von unabhängigen Programmen zu wirken, sollten daher so oft wie möglich relative Pfadangaben verwendet werden. Eine Übersicht der verfügbaren Image-Komponenten findest du unter Plasma Theme page.

    Plasma::Svg kann auch dazu verwendet werden, um ein Subset der SVG-Datei zu zeichnen, wenn man eine entsprechend in der SVG hinterlegte ID übergibt. Ein gutes Beispiel hierfür ist die clock.svg, welche im Standardtheme enthalten ist. Sie enthält einen Hintergrund, drei Handles für Stunden, Minuten und Sekunden, sowie den Vordergrund (das Glas). Durch die Möglichkeit, alle in eine Datei zu stecken, zeigt das File eine komplette Uhr. Das ist wesentlich einfacher zu handhaben, als 5 verschiedene Dateien editieren zu müssen. Außerdem steigt die Verarbeitungsgeschwindigkeit, da nur ein SVG-Renderer arbeiten muss.

    setBackgroundHints(DefaultBackground)

    Einen Hintergrund zu zeichnen, ist eine Standard-Funktionalität. Daher gibt es einen einfacheren und schneller Weg, dies zu bewerkstelligen, indem man einfach setBackgroundHints(DefaultBackground) zu seinem Code hinzufügt. Dadurch wird der Standard-Plasma-Hintergrund hinter dein Plasmoid gezeichnet. Dies spart nicht nur Zeit und Codezeilen, es hilft auch, dem Benutzer ein konsistentes Aussehen zu präsentieren.

    Die init()-Methode

    Im Konstruktor teilen wir Plasma Informationen über den Hintergrund und ggf. Konfigurationdateien mit. Auch die Startgröße wird im Konstruktor gesetzt. Danach wird jede Größenänderung von Plasma selbst übernommen. In der Methode init() wird alles initialisiert, was irgendwie initialisiert werden muss, wie z.B. Konfigurationsdaten lesen.

    hasFailedToLaunch()

    Diese Methode liefert den Wert true zurück, falls, aus welchem Grund auch immer, das Applet nicht korrekt starten kann (z.B. weil die Bibliothek nicht geladen werden kann, nowendige Hardwareunterstützung nicht gefunden wird, ...). Nutze die Methode, um vor dem Beenden noch Aufräumarbeiten zu erledigen.

    setFailedToLaunch(bool, QString)

    Wenn dein Programm nicht gestartet werden kann, kann mit Hilfe dieser Methode Plasma darüber informiert werden. mit einem optionalen String kann auch der Grund angegeben werden. Plasma wird dann eine standardisierte Fehlermeldung anzeigen, die den Benutzer über die Situation informiert. Dein Applet wird ab diesem Zeitpunkt nicht mehr aufgerufen, irgendetwas zu zeichnen. Bei komplexeren Plasmoids, deren korrekte Anzeige von mehreren Faktoren abhängt, ist das ist der eleganteste Weg, aufzuräumen.

    dataUpdated

    Wenn du dein Plasmoid an eine von Plasmas Data Engine anschließen willst, musst du diese Methode implementieren. Sie wird aufgerufen, wenn die Data Engine dir Daten sendet. Hier würdest du z.B. implementieren, dass dein Plasmoid aufgrund der aktuellen Daten neu gezeichnet wird.

    Bestimmen von Größe und Geometrie: geometry() and contentsRect()

    Wenn du in deinem Applet-Code die Größe und Geometrie wissen musst, dann rufe contentsRect() und contentsRect().size() auf. Vermeide den Aufruf von geometry() und size(), weil diese den Randbereich des Applet nicht berücksichtigen. Vermeide genauso, Objekte im Applet mit absoluten Werten zu platzieren, wie z.B. QPoint(0, 0). Verwende stattdessen contentsRect().topLeft().

    Building it all, the CMakeLists.txt

    Zu guter Letzt musst du jetzt noch alles zusammenfügen, was zum Kompilieren notwendig ist. Um cmake mitzuteilen, was es machen soll, benötigen wir die Datei CMakeLists.txt.

    Weitere Infos zu cmake siehe Development/Tutorials/CMake

    1. Das Projekt benötigt natürlich einen Namen

    project(plasma-tutorial1)

    1. Die benötigten Bibliotheken suchen

    find_package(KDE4 REQUIRED) include(KDE4Defaults)

    add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) include_directories(

      ${CMAKE_SOURCE_DIR}
      ${CMAKE_BINARY_DIR}
      ${KDE4_INCLUDES}
      )
    
    1. Hier fürden wir den Sourcecode ein

    set(tutorial1_SRCS plasma-tutorial1.cpp)

    1. Jetzt noch sicherstellen, dass alles an den richtigen Platz installiert wird

    kde4_add_plugin(plasma_applet_tutorial1 ${tutorial1_SRCS}) target_link_libraries(plasma_applet_tutorial1

                         ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS})
    

    install(TARGETS plasma_applet_tutorial1

           DESTINATION ${PLUGIN_INSTALL_DIR})
    

    install(FILES plasma-applet-tutorial1.desktop

           DESTINATION ${SERVICES_INSTALL_DIR})
    

    Das Applet testen

    Wenn deine aktuelle Desktop-Umgebung von der Testinstallation abweicht, musst du cmake mit der Option -DCMAKE_INSTALL_PREFIX=/usr/lib/kde4/ (ersetzen mit deinem $KDEDIR) aufrufen. Danach make starten. Wenn alles geklappt hat, kann das Applet mit sudo make install oder

    • cp ./lib/plasma_applet_tutorial1.so $KDEDIR/lib
    • cp ./plasma-applet-tutorial1.desktop $KDEDIR/share/kde4/services/

    installiert werden.

    Anschließend kbuildsycoca4 starten, damit KDE-Programme etwas von den neuen Dateien wissen. Um dein Applet zu testen, kannst du das Programm plasmoidviewer verwenden: plasmoidviewer applet_name Du kannst dein Applet sogar in einem eigenen kleinen Desktop starten: plasmoidviewer -c desktop applet_name


    applet_name ist natürlich der Name, der in der .desktop-Datei unter dem Schlüsselwort X-KDE-PluginInfo-Name eingetragen ist.

    Ansonsten kannst du Plasma auch einfach neu starten, dann wird das neue Applet im Applet-Browser angezeigt: kbuildsycoca4 kquitapp plasma # in trunk (KDE4.3): kquitapp plasma-desktop plasma # in trunk (KDE4.3): plasma-desktop

    Wenn das auch nicht funktioniert, solltest du KDE neu starten, indem du dich ab- und wieder anmeldest.