Development/Tutorials/Kross/Hello World: Difference between revisions

    From KDE TechBase
    (Initial creation of page)
     
    m (Text replace - "<syntaxhighlight lang="make">" to "<syntaxhighlight lang="cmake">")
    (24 intermediate revisions by 6 users not shown)
    Line 6: Line 6:
    }}
    }}


    {{Improve}}
    {{Under Construction}}


    This tutorial is intended to be a simple introduction to kross for the kde4 application writer in multiple scripting languages.
    This tutorial is intended to be a simple introduction to kross for the kde4 application writer in multiple scripting languages.
    Line 12: Line 12:
    == Additional Bindings ==
    == Additional Bindings ==


    If you have already set up your environment as described in [[Getting Started/Build/KDE4]], you can already use kross with the javascript language. You can choose optionally to install support for python and ruby from kdebindings. Either checkout and build kdebindings, or just the kdebindings/python and kdebindings/ruby subdirectories ([[Getting_Started/Build/KDE4#Installing_a_subset_of_a_module|Installing_a_subset_of_a_module]]).
    If you have already set up your environment as described in [[Getting Started/Build]], you can already use kross with the javascript language. You can choose optionally to install support for python and ruby from kdebindings. Either checkout and build kdebindings, or just the kdebindings/python and kdebindings/ruby subdirectories.


    <code bash>
    <syntaxhighlight lang="bash">
    cs KDE
    cd KDE
    svn co -N kdebindings
    svn co -N kdebindings
    cd kdebindings
    cd kdebindings
    Line 21: Line 21:
    svn up ruby
    svn up ruby
    cmakekde
    cmakekde
    </code>
    </syntaxhighlight>


    == Hello World ==
    == Hello World ==
    In this tutorial a simple dialog is created which contains a drop-down list and a label. When an interpreter is selected from the list, some scripting code is executed and the label text is updated in the script.
    In this tutorial a simple dialog is created which contains a drop-down list and a label. When an interpreter is selected from the list, some scripting code is executed and the label text is updated in the script.


    [[Image:krosshello1]]
    [[Image:krosshello1.png]]


    Create a krosshello folder in the kde-devel home directory (or choose another location). Create the following files and run cmakekde:
    Create a krosshello folder in the kde-devel home directory (or choose another location). Create the following files and run cmakekde:
    Line 32: Line 32:
    === main.cpp ===
    === main.cpp ===


    <code cpp>
    The main.cpp contains the entry-point for our sample application.
     
    <syntaxhighlight lang="cpp">
    // First some Qt and KDE includes
    #include <QString>
    #include <QString>
    #include <KApplication>
    #include <KApplication>
    Line 39: Line 42:
    #include <KCmdLineArgs>
    #include <KCmdLineArgs>
    #include <KLocalizedString>
    #include <KLocalizedString>
     
    // Also include the MainWindow class
    #include "mainwindow.h"
    #include "mainwindow.h"


    int main (int argc, char *argv[])
    int main (int argc, char *argv[])
    {
    {
        // Used to store information about a program.
         KAboutData aboutData("krosshello",
         KAboutData aboutData("krosshello",
             0,
             0,
    Line 55: Line 59:
             "[email protected]");
             "[email protected]");


        // Access to the command-line arguments.
         KCmdLineArgs::init( argc, argv, &aboutData );
         KCmdLineArgs::init( argc, argv, &aboutData );
        // Initialize the application.
         KApplication app;
         KApplication app;


        // Create and show the main window.
         MainWindow* window = new MainWindow();
         MainWindow* window = new MainWindow();
         window->show();
         window->show();


        // Finally execute the application.
         return app.exec();
         return app.exec();
    }
    }
    </code>
    </syntaxhighlight>


    === mainwindow.h ===
    === mainwindow.h ===


    <code cpp>
    The main window class that is used to display the combobox which contains a list of available interpreters and the label which we like to change from within scripting code.
     
    <syntaxhighlight lang="cpp">
    #ifndef MAINWINDOW_H
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #define MAINWINDOW_H
    Line 74: Line 84:
    #include <QLabel>
    #include <QLabel>


    // The main window to display our combobox and the label.
    class MainWindow : public QWidget
    class MainWindow : public QWidget
    {
    {
         Q_OBJECT
         Q_OBJECT
       public:
       public:
        // The constructor.
         MainWindow(QWidget *parent=0);
         MainWindow(QWidget *parent=0);
       private Q_SLOTS:
       private Q_SLOTS:
        // This slot is called when the item in the combobox is changed.
         void interpreterActivated(const QString &);
         void interpreterActivated(const QString &);
       private:
       private:
         QLabel* lblHello;
         QLabel* lblHello;
         QComboBox* cmbHello;
         QComboBox* cmbInterpreters;
    };
    };


    #endif
    #endif
    </code>
    </syntaxhighlight>


    === mainwindow.cpp ===
    === mainwindow.cpp ===
    Line 93: Line 106:
    This code creates a simple dialog with a combobox showing available interpreters along with a label for displaying a message. The kross/core/manager.h and kross/core/action.h are included to provide kross functionality, which is invoked when a selection is made on the combobox. The code below makes the lblHello label available to scripts as a MyLabel object, and executes different code depending on the interpreter chosen.
    This code creates a simple dialog with a combobox showing available interpreters along with a label for displaying a message. The kross/core/manager.h and kross/core/action.h are included to provide kross functionality, which is invoked when a selection is made on the combobox. The code below makes the lblHello label available to scripts as a MyLabel object, and executes different code depending on the interpreter chosen.


    <code cpp>
    <syntaxhighlight lang="cpp">
    #include <QVBoxLayout>
    #include <QVBoxLayout>
    #include <QDebug>
    #include <QDebug>
    Line 101: Line 114:
    #include <kross/core/action.h>
    #include <kross/core/action.h>


    // the constructor.
    MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
    MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
    {
    {
       cmbHello = new QComboBox ();
       // Create the combobox where we display a list of
       cmbHello->addItem("Choose Interpreter", "");
      // available interpreters.
     
      cmbInterpreters = new QComboBox (this);
       cmbInterpreters->addItem("Choose Interpreter", "");
      // Now let's add the interpreters. Please note, that all
      // interpreters that are installed are displayed in the list.
      // Per default JavaScript will be always
      // available while Python, Ruby or other interpreters
      // may need to be installed before like explained at the
      // "Additional Bindings" section above.
       foreach(QString s, Kross::Manager::self().interpreters())
       foreach(QString s, Kross::Manager::self().interpreters())
         cmbHello->addItem(s);
         cmbInterpreters->addItem(s);


       connect(cmbHello, SIGNAL(activated(const QString &)), SLOT(interpreterActivated(const QString &)));
      // Connect the combobox signal with our slot to be able to
      // do something if the active item in the combobox changed.
       connect(cmbInterpreters, SIGNAL(activated(const QString &)),
              this, SLOT(interpreterActivated(const QString &)));


       lblHello = new QLabel("Hello");
      // The label we want to manipulate from within scripting
      // code.
       lblHello = new QLabel("Hello", this);


      // Put everything into a layout to have it shown in a
      // nice way.
       QVBoxLayout *layout = new QVBoxLayout;
       QVBoxLayout *layout = new QVBoxLayout;
       layout->addWidget(cmbHello);
       layout->addWidget(cmbInterpreters);
       layout->addWidget(lblHello);
       layout->addWidget(lblHello);
       setLayout(layout);
       setLayout(layout);
    }
    }


    // this slot is called when the active item of the combobox changes
    void MainWindow::interpreterActivated(const QString &strSelectedInterpreter)
    void MainWindow::interpreterActivated(const QString &strSelectedInterpreter)
    {
    {
       if(strSelectedInterpreter.isEmpty())
       if(strSelectedInterpreter.isEmpty())
       {
       {
        // if no interpreter was selected, we display nothing.
         lblHello->setText("-");
         lblHello->setText("-");
         return;
         return;
       }
       }


      // Now let's create a Kross::Action instance which will act
      // as container for our script. You are also able to cache
      // that action, manipulate it on demand or execute it multiple
      // times.
       Kross::Action action(this, "MyScript");
       Kross::Action action(this, "MyScript");
      // Now let's set the scripting code that should be executed
      // depending on the choosen interpreter. You are also able to
      // use action.setFile("/path/scriptfile") here to execute
      // an external scriptfile, as shown later in this tutorial.
       if(strSelectedInterpreter == "python")
       if(strSelectedInterpreter == "python")
         action.setCode("import MyLabel\nMyLabel.text = 'Hello from python!'");
         action.setCode("import MyLabel\nMyLabel.text = 'Hello from python!'");
    Line 136: Line 174:
       else
       else
         return;
         return;
      // Set the name of the interpreter that should be used to
      // evaluate the scripting code above. It's not needed to set
      // it explicitly if we defined an external scripting file via
      // action.setFile() since then Kross will determinate the right
      // one. But since we set the scripting code above manually by using
      // action.setCode() we need to define explicitly what interpreter
      // should be used.
       action.setInterpreter(strSelectedInterpreter);
       action.setInterpreter(strSelectedInterpreter);
      // Now let's add the QLabel instance to let the scripting code
      // access it.
       action.addObject(lblHello, "MyLabel");
       action.addObject(lblHello, "MyLabel");


      // Finally execute the scripting code.
       action.trigger();
       action.trigger();
    }
    }
    </code>
    </syntaxhighlight>
     
    === CMakeLists.txt ===


    This CMakeLists.txt file is used to build our small example using cmake.


    === CMakeLists.txt ===
    <syntaxhighlight lang="cmake">
    <code>
    project (krosshello)
    project (krosshello)


    Line 155: Line 207:
    kde4_add_executable(krosshello ${krosshello_SRCS})
    kde4_add_executable(krosshello ${krosshello_SRCS})
    target_link_libraries(krosshello ${KDE4_KDEUI_LIBS} ${KDE4_KROSSUI_LIBS})
    target_link_libraries(krosshello ${KDE4_KDEUI_LIBS} ${KDE4_KROSSUI_LIBS})
    </code>
    </syntaxhighlight>


    == Using separate script files ==
    == Using separate script files ==
    Line 161: Line 213:
    The next step is to extract the scripts into separate files. This has the obvious advantage of being editable without being recompiled. Edit the <tt>MainWindow::interpreterActivated</tt> in <tt>mainwindow.cpp</tt> to the following:
    The next step is to extract the scripts into separate files. This has the obvious advantage of being editable without being recompiled. Edit the <tt>MainWindow::interpreterActivated</tt> in <tt>mainwindow.cpp</tt> to the following:


    <code cpp>
    <syntaxhighlight lang="cpp">
    void MainWindow::interpreterActivated(const QString &strSelectedInterpreter)
    void MainWindow::interpreterActivated(const QString &strSelectedInterpreter)
    {
    {
    Line 187: Line 239:


       action.trigger();
       action.trigger();
    </code>
    </syntaxhighlight>


    It is no longer neccessary to set the interpreter for the action explicitly. Kross chooses the correct interpreter based on the filename given in <tt>setFile()</tt>.
    It is no longer neccessary to set the interpreter for the action explicitly. Kross chooses the correct interpreter based on the filename given in <tt>setFile()</tt>.
    Line 193: Line 245:
    For example, edit krosshello.py file to include the following:
    For example, edit krosshello.py file to include the following:


    <code python>
    <syntaxhighlight lang="python">
    #!/usr/bin/env kross
    #!/usr/bin/env kross


    Line 199: Line 251:


    MyLabel.text = "Hello from inside a python file."
    MyLabel.text = "Hello from inside a python file."
    </code>
    </syntaxhighlight>
     


    It is also possible to call a function and return the result to the application.
    It is also possible to call a function and return the result to the application.


    <code python>
    <syntaxhighlight lang="python">
    def reverseString(s):
    def reverseString(s):
         s = s[::-1]
         s = s[::-1]
         return s
         return s
    </code>
    </syntaxhighlight>


    <code javascript>
    JavaScript sample that does the same like above but using the JavaScript language rather then Python.
     
    <syntaxhighlight lang="javascript">
    function reverseString(s){
    function reverseString(s){
         return s.split("").reverse().join("");
         return s.split("").reverse().join("");
    }
    }
    </code>
    </syntaxhighlight>


    Add the above to krosshello.js or krosshello.py and edit the mainwindow.cpp again to include the following after action.trigger():
    Add the above to krosshello.js or krosshello.py and edit the mainwindow.cpp again to include the following after action.trigger():


    <code cpp>
    <syntaxhighlight lang="cpp">
    QVariant result = action.callFunction("reverseString", QVariantList() << "Hello World");
    QVariantList arguments;
    arguments << "Hello World";
    QVariant result = action.callFunction("reverseString", arguments);
    lblHello->setText(result.toString());
    lblHello->setText(result.toString());
    </code>
    </syntaxhighlight>
     
     
    Ususally it will not make sense to use callFunction in an application, but instead connect signals and slots directly between the application and the script.
    <!--
    Edit the script code to
     
    <code python>
    import MyLabel
     
    def reverseString(s):
        s = s[::-1]
        MyLabel.Text = s
    </code>
    -->
    {{Box|TODO|Edit this with a simple signals/slots example.}}


    {{Box|TODO|Add note about automatic connection of signals and slots.}}
    Usually it will not make sense to use callFunction in an application, but instead connect signals and slots directly between the application and the script.


    This is the more practical way to use kross, and is described in more detail at [[Development/Tutorials/Kross/Scripts-as-Plugins|Scripts as plugins]].
    This is the more practical way to use kross, and is described in more detail at [[Development/Tutorials/Kross/Connecting_Signals and slots in Kross|Connecting Signals and slots in Kross]].

    Revision as of 10:20, 30 June 2011

    Hello world in kross
    Tutorial Series   Kross tutorials
    Previous   Kross introduction
    What's Next   Scripts as plugins
    Further Reading   n/a


    noframe
    noframe
     
    Under Construction
    This page is under construction. This page is actively being developed and updated with new information, and may be incomplete. You can help by editing this page


    This tutorial is intended to be a simple introduction to kross for the kde4 application writer in multiple scripting languages.

    Additional Bindings

    If you have already set up your environment as described in Getting Started/Build, you can already use kross with the javascript language. You can choose optionally to install support for python and ruby from kdebindings. Either checkout and build kdebindings, or just the kdebindings/python and kdebindings/ruby subdirectories.

    cd KDE
    svn co -N kdebindings
    cd kdebindings
    svn up python
    svn up ruby
    cmakekde
    

    Hello World

    In this tutorial a simple dialog is created which contains a drop-down list and a label. When an interpreter is selected from the list, some scripting code is executed and the label text is updated in the script.

    Create a krosshello folder in the kde-devel home directory (or choose another location). Create the following files and run cmakekde:

    main.cpp

    The main.cpp contains the entry-point for our sample application.

    // First some Qt and KDE includes
    #include <QString>
    #include <KApplication>
    #include <KAboutData>
    #include <KMessageBox>
    #include <KCmdLineArgs>
    #include <KLocalizedString>
    // Also include the MainWindow class
    #include "mainwindow.h"
    
    int main (int argc, char *argv[])
    {
        // Used to store information about a program.
        KAboutData aboutData("krosshello",
            0,
            ki18n("Kross Hello World"),
            "1.0",
            ki18n("Hello World application for Kross"),
            KAboutData::License_GPL,
            ki18n("(c) 2007"),
            ki18n("Some text..."),
            "http://kross.dipe.org",
            "[email protected]");
    
        // Access to the command-line arguments.
        KCmdLineArgs::init( argc, argv, &aboutData );
        // Initialize the application.
        KApplication app;
    
        // Create and show the main window.
        MainWindow* window = new MainWindow();
        window->show();
    
        // Finally execute the application.
        return app.exec();
    }
    

    mainwindow.h

    The main window class that is used to display the combobox which contains a list of available interpreters and the label which we like to change from within scripting code.

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QComboBox>
    #include <QLabel>
    
    // The main window to display our combobox and the label.
    class MainWindow : public QWidget
    {
        Q_OBJECT
      public:
        // The constructor.
        MainWindow(QWidget *parent=0);
      private Q_SLOTS:
        // This slot is called when the item in the combobox is changed.
        void interpreterActivated(const QString &);
      private:
        QLabel* lblHello;
        QComboBox* cmbInterpreters;
    };
    
    #endif
    

    mainwindow.cpp

    This code creates a simple dialog with a combobox showing available interpreters along with a label for displaying a message. The kross/core/manager.h and kross/core/action.h are included to provide kross functionality, which is invoked when a selection is made on the combobox. The code below makes the lblHello label available to scripts as a MyLabel object, and executes different code depending on the interpreter chosen.

    #include <QVBoxLayout>
    #include <QDebug>
    #include "mainwindow.h"
    
    #include <kross/core/manager.h>
    #include <kross/core/action.h>
    
    // the constructor.
    MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
    {
      // Create the combobox where we display a list of
      // available interpreters.
      cmbInterpreters = new QComboBox (this);
      cmbInterpreters->addItem("Choose Interpreter", "");
      // Now let's add the interpreters. Please note, that all
      // interpreters that are installed are displayed in the list.
      // Per default JavaScript will be always
      // available while Python, Ruby or other interpreters
      // may need to be installed before like explained at the
      // "Additional Bindings" section above.
      foreach(QString s, Kross::Manager::self().interpreters())
        cmbInterpreters->addItem(s);
    
      // Connect the combobox signal with our slot to be able to
      // do something if the active item in the combobox changed.
      connect(cmbInterpreters, SIGNAL(activated(const QString &)),
              this, SLOT(interpreterActivated(const QString &)));
    
      // The label we want to manipulate from within scripting
      // code.
      lblHello = new QLabel("Hello", this);
    
      // Put everything into a layout to have it shown in a
      // nice way.
      QVBoxLayout *layout = new QVBoxLayout;
      layout->addWidget(cmbInterpreters);
      layout->addWidget(lblHello);
      setLayout(layout);
    }
    
    // this slot is called when the active item of the combobox changes
    void MainWindow::interpreterActivated(const QString &strSelectedInterpreter)
    {
      if(strSelectedInterpreter.isEmpty())
      {
        // if no interpreter was selected, we display nothing.
        lblHello->setText("-");
        return;
      }
    
      // Now let's create a Kross::Action instance which will act
      // as container for our script. You are also able to cache
      // that action, manipulate it on demand or execute it multiple
      // times.
      Kross::Action action(this, "MyScript");
      // Now let's set the scripting code that should be executed
      // depending on the choosen interpreter. You are also able to
      // use action.setFile("/path/scriptfile") here to execute
      // an external scriptfile, as shown later in this tutorial.
      if(strSelectedInterpreter == "python")
        action.setCode("import MyLabel\nMyLabel.text = 'Hello from python!'");
      else if(strSelectedInterpreter == "ruby")
        action.setCode("require 'MyLabel'\nMyLabel.text = 'Hello from ruby!'");
      else if(strSelectedInterpreter == "javascript")
        action.setCode("MyLabel.setText('Hello from javascript!')");
      else
        return;
    
      // Set the name of the interpreter that should be used to
      // evaluate the scripting code above. It's not needed to set
      // it explicitly if we defined an external scripting file via
      // action.setFile() since then Kross will determinate the right
      // one. But since we set the scripting code above manually by using
      // action.setCode() we need to define explicitly what interpreter
      // should be used.
      action.setInterpreter(strSelectedInterpreter);
    
      // Now let's add the QLabel instance to let the scripting code
      // access it.
      action.addObject(lblHello, "MyLabel");
    
      // Finally execute the scripting code.
      action.trigger();
    }
    

    CMakeLists.txt

    This CMakeLists.txt file is used to build our small example using cmake.

    project (krosshello)
    
    find_package(KDE4 REQUIRED)
    include_directories( ${KDE4_INCLUDES} )
    
    set(krosshello_SRCS main.cpp mainwindow.cpp)
    
    kde4_add_executable(krosshello ${krosshello_SRCS})
    target_link_libraries(krosshello ${KDE4_KDEUI_LIBS} ${KDE4_KROSSUI_LIBS})
    

    Using separate script files

    The next step is to extract the scripts into separate files. This has the obvious advantage of being editable without being recompiled. Edit the MainWindow::interpreterActivated in mainwindow.cpp to the following:

    void MainWindow::interpreterActivated(const QString &strSelectedInterpreter)
    {
      if(strSelectedInterpreter.isEmpty())
      {
        lblHello->setText("-");
        return;
      }
    
      QString filename;
    
      Kross::Action action(this, "MyScript");
      if(strSelectedInterpreter == "python")
        filename = "krosshello.py";
      else if(strSelectedInterpreter == "ruby")
        filename = "krosshello.rb";
      else if(strSelectedInterpreter == "javascript")
        filename = "krosshello.js";
      else
        return;
    
      action.setFile(filename);
      //action.setInterpreter(strSelectedInterpreter);
      action.addObject(lblHello, "MyLabel");
    
      action.trigger();
    

    It is no longer neccessary to set the interpreter for the action explicitly. Kross chooses the correct interpreter based on the filename given in setFile().

    For example, edit krosshello.py file to include the following:

    #!/usr/bin/env kross
    
    import MyLabel
    
    MyLabel.text = "Hello from inside a python file."
    

    It is also possible to call a function and return the result to the application.

    def reverseString(s):
        s = s[::-1]
        return s
    

    JavaScript sample that does the same like above but using the JavaScript language rather then Python.

    function reverseString(s){
        return s.split("").reverse().join("");
    }
    

    Add the above to krosshello.js or krosshello.py and edit the mainwindow.cpp again to include the following after action.trigger():

    QVariantList arguments;
    arguments << "Hello World";
    QVariant result = action.callFunction("reverseString", arguments);
    lblHello->setText(result.toString());
    

    Usually it will not make sense to use callFunction in an application, but instead connect signals and slots directly between the application and the script.

    This is the more practical way to use kross, and is described in more detail at Connecting Signals and slots in Kross.