Marble/MarblePythonSignalsSlots: Difference between revisions

From KDE TechBase
(Changed note formatting and re-linked 'signals and slots')
No edit summary
(2 intermediate revisions by the same user not shown)
Line 2: Line 2:
{{TutorialBrowser|
{{TutorialBrowser|


series=Marble C++ Tutorial|
series=Marble Python Tutorial|


name=Basic interaction with MarbleWidget|
name=Basic interaction with MarbleWidget|


pre=[[Projects/Marble/MarblePythonMarbleWidget|Tutorial 2 - Changing basic map properties]]|
pre=[[Projects/Marble/MarblePythonMarbleWidget|Tutorial 2 - Changing basic map properties]]|
next=[[Projects/Marble/Runners/MarblePythonLoadingKML|Tutorial 4 - Loading KML files into Marble]]|
}}
}}


Line 17: Line 19:
We'd like to add other widgets to our Marble window: A '''zoom slider''' and a '''label''' that shows the current zoom level of the map.
We'd like to add other widgets to our Marble window: A '''zoom slider''' and a '''label''' that shows the current zoom level of the map.


In order to achieve this we need to create a vertical layout. The layout must be added as the central widget to the application, and have the map, slider and label added to it. Also we zoom the globe to the slider's default value using the  <tt>MarbleWidget.zoomView(int)</tt> method.
In order to achieve this we need to create a vertical layout. The layout must be added as the central widget to the application, and have the map, slider and label added to it. Also we zoom the globe to the slider's default value using the  <tt>marble.zoomView(int)</tt> method.


We want to center our globe onto South America. So we create a new <tt>GeoDataCoordinates</tt> object that takes the longitude and the latitude as a parameter and we call <tt>MarbleWidget.centerOn(location)</tt>.  
We want to center our globe onto South America. So we create a new <tt>GeoDataCoordinates</tt> object that takes the longitude and the latitude as a parameter and we call <tt>marble.centerOn(location)</tt>.  


As you might have realized already <tt>GeoDataCoordinates</tt> is the geodetic "sister" of <tt>QPoint</tt>. They share a very similar API. Additionally GeoDataCoordinates features a nice set of string conversion methods (<tt>GeoDataCoordinates.fromString()</tt>, <tt>GeoDataCoordinates.lonToString()</tt> and  <tt>GeoDataCoordinates.latToString()</tt>). They are used in various places inside Marble such as the signal <tt>MarbleWidget.mouseMoveGeoPosition(string)</tt> .
As you might have realized already <tt>GeoDataCoordinates</tt> is the geodetic "sister" of <tt>QPoint</tt>. They share a very similar API. Additionally GeoDataCoordinates features a nice set of string conversion methods (<tt>GeoDataCoordinates.fromString()</tt>, <tt>GeoDataCoordinates.lonToString()</tt> and  <tt>GeoDataCoordinates.latToString()</tt>). They are used in various places inside Marble such as the signal <tt>MarbleWidget.mouseMoveGeoPosition(string)</tt> .
Line 29: Line 31:
from PyQt4.QtCore import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtGui import *
from PyKDE4.kdeui import *
from PyKDE4.kdecore import *
from PyKDE4.marble import *
from PyKDE4.marble import *
import sys
import sys


class MainWin (KMainWindow):
 
     def __init__ (self, *args):
class MainWindow():
         KMainWindow.__init__ (self)
     def __init__(self):
# create the marble widget
         # create the app
         self.marble = Marble.MarbleWidget(self)
        app = QApplication(sys.argv)
       
 
        # create the main window and set it's title
        window = QWidget()
        window.setWindowTitle("Marble Map with Controls")
 
        # create the marble widget
         marble = Marble.MarbleWidget()
 
         # Load the OpenStreetMap map
         # Load the OpenStreetMap map
         self.marble.setMapThemeId("earth/plain/plain.dgml")
         marble.setMapThemeId("earth/plain/plain.dgml")
       
 
         # Enable the cloud cover and enable the country borders
         # Enable the cloud cover and enable the country borders
         self.marble.setShowClouds(True)
         marble.setShowClouds(True)
         self.marble.setShowBorders(True)
         marble.setShowBorders(True)
       
 
         # Hide the FloatItems: Compass and StatusBar
         # Hide the FloatItems: Compass and StatusBar
         self.marble.setShowOverviewMap(False)
         marble.setShowOverviewMap(False)
         self.marble.setShowScaleBar(False)
         marble.setShowScaleBar(False)
         self.marble.setShowCompass(False)
         marble.setShowCompass(False)
     
 
         # Change the map to center on Australia
         # Change the map to center on Australia
         home = Marble.GeoDataCoordinates(135.0, -25.0, 0.0, Marble.GeoDataCoordinates.Degree)
         home = Marble.GeoDataCoordinates(135.0, -25.0, 0.0, Marble.GeoDataCoordinates.Degree)
         self.marble.centerOn(home);
         marble.centerOn(home)
       
 
         # create the slider
         # create the slider
         self.zoomSlider = QSlider(Qt.Horizontal)
         zoomSlider = QSlider(Qt.Horizontal)
         # set the limits of the slider
         # set the limits of the slider
         self.zoomSlider.setMinimum(1000)
         zoomSlider.setMinimum(1000)
         self.zoomSlider.setMaximum(2400)
         zoomSlider.setMaximum(2400)
         # set a default zoom value
         # set a default zoom value
         self.zoomSlider.setValue(1200)
         zoomSlider.setValue(1200)
       
 
         # zoom  
         # zoom the map
         self.marble.zoomView(self.zoomSlider.value())
         marble.zoomView(zoomSlider.value())
       
 
         # create the position label
         # create the position label
         self.zoomLabel = QLabel()
         self.zoomLabel = QLabel()
         # show the current zoom level
         # show the current zoom level
         self.setZoomLabel(self.zoomSlider.value())
         self.setZoomLabel(zoomSlider.value())
       
 
         # make elements size correctly
         # make elements size correctly
         self.zoomLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
         self.zoomLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
       
 
         # create the layout
         # create the layout
         self.layout_placeholder = QWidget()
         layout = QVBoxLayout()
        self.layout = QVBoxLayout()
 
       
         # add all the components
         # add all the components
         self.layout.addWidget(self.marble)
         layout.addWidget(marble)
         self.layout.addWidget(self.zoomSlider)
         layout.addWidget(zoomSlider)
         self.layout.addWidget(self.zoomLabel)
         layout.addWidget(self.zoomLabel)
       
 
        # add all the widgets to the layout placeholder
        self.layout_placeholder.setLayout(self.layout)
         # make the layout placeholder the central widget
         # make the layout placeholder the central widget
         self.setCentralWidget(self.layout_placeholder)
         window.setLayout(layout)
       
 
         # connect slider value to map zoom via signal slots
         # connect slider value to map zoom via signal slots
         self.connect(self.zoomSlider, SIGNAL('valueChanged(int)'), self.marble.zoomView)
         app.connect(zoomSlider, SIGNAL('valueChanged(int)'), marble.zoomView)
       
 
         # display the zoom level on the label, but pass it though the
         # display the zoom level on the label, but pass it though the
         # custom self.setZoomLabel function to add prefix text
         # custom self.setZoomLabel function to add prefix text
         self.connect(self.marble, SIGNAL('zoomChanged(int)'), self.setZoomLabel)
         app.connect(marble, SIGNAL('zoomChanged(int)'), self.setZoomLabel)
       
 
         # resize the window
         # resize the window
         self.resize(600, 400)
         window.resize(600, 400)
       
 
         # display the app
         # display the app
         self.show()
         window.show()
    def setZoomLabel(self, value):
      self.zoomLabel.setText("Zoom Level: " + str(value))
       


def main():
        app.exec_()
    # defaults needed for the KApplication to be initialized
    appName    = "marble_map_widget_controls"
    catalog    = ""
    programName = ki18n ("Marble Map with Controls")
    version    = "1.0"
    description = ki18n ("Using Marble API to control map zoom with a slider.")
    license    = KAboutData.License_GPL
    copyright  = ki18n ("(c) 2008 Your Name")
    text        = ki18n ("none")
    homePage    = "www.example.com"
    bugEmail    = "[email protected]"


     aboutData  = KAboutData (appName, catalog, programName, version, description,
     def setZoomLabel(self, value):
                              license, copyright, text, homePage, bugEmail)
        self.zoomLabel.setText("Zoom Level: " + str(value))
 
    KCmdLineArgs.init(sys.argv, aboutData)
   
    app = KApplication()
    # initialize our window, which will call the MainWindow.__init__ function above
    mainWindow = MainWin(None, "main window")
    # quit the application when the last window closes
    app.connect(app, SIGNAL ("lastWindowClosed ()"), app.quit)
    # run the app
    app.exec_()


main()
MainWindow()
</source>
</source>



Revision as of 15:22, 27 December 2013

Basic interaction with MarbleWidget
Tutorial Series   Marble Python Tutorial
Previous   Tutorial 2 - Changing basic map properties
What's Next   Tutorial 4 - Loading KML files into Marble
Further Reading   n/a


Creating a window with controls

Note
the documentation for the Marble Python bindings are currently not available online. They can instead be found in the source code at the location: src/bindings/python/html/marble/Marble.html.


We'd like to add other widgets to our Marble window: A zoom slider and a label that shows the current zoom level of the map.

In order to achieve this we need to create a vertical layout. The layout must be added as the central widget to the application, and have the map, slider and label added to it. Also we zoom the globe to the slider's default value using the marble.zoomView(int) method.

We want to center our globe onto South America. So we create a new GeoDataCoordinates object that takes the longitude and the latitude as a parameter and we call marble.centerOn(location).

As you might have realized already GeoDataCoordinates is the geodetic "sister" of QPoint. They share a very similar API. Additionally GeoDataCoordinates features a nice set of string conversion methods (GeoDataCoordinates.fromString(), GeoDataCoordinates.lonToString() and GeoDataCoordinates.latToString()). They are used in various places inside Marble such as the signal MarbleWidget.mouseMoveGeoPosition(string) .

Finally we connect the signals and slots that MarbleWidget offers to the signals and slots of the slider and the label (and the label, through a custom method that prefixes the string 'Zoom Level:'):

#!/usr/bin/env python
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyKDE4.marble import *
import sys


class MainWindow():
    def __init__(self):
        # create the app
        app = QApplication(sys.argv)

        # create the main window and set it's title
        window = QWidget()
        window.setWindowTitle("Marble Map with Controls")

        # create the marble widget
        marble = Marble.MarbleWidget()

        # Load the OpenStreetMap map
        marble.setMapThemeId("earth/plain/plain.dgml")

        # Enable the cloud cover and enable the country borders
        marble.setShowClouds(True)
        marble.setShowBorders(True)

        # Hide the FloatItems: Compass and StatusBar
        marble.setShowOverviewMap(False)
        marble.setShowScaleBar(False)
        marble.setShowCompass(False)

        # Change the map to center on Australia
        home = Marble.GeoDataCoordinates(135.0, -25.0, 0.0, Marble.GeoDataCoordinates.Degree)
        marble.centerOn(home)

        # create the slider
        zoomSlider = QSlider(Qt.Horizontal)
        # set the limits of the slider
        zoomSlider.setMinimum(1000)
        zoomSlider.setMaximum(2400)
        # set a default zoom value
        zoomSlider.setValue(1200)

        # zoom the map
        marble.zoomView(zoomSlider.value())

        # create the position label
        self.zoomLabel = QLabel()
        # show the current zoom level
        self.setZoomLabel(zoomSlider.value())

        # make elements size correctly
        self.zoomLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)

        # create the layout
        layout = QVBoxLayout()

        # add all the components
        layout.addWidget(marble)
        layout.addWidget(zoomSlider)
        layout.addWidget(self.zoomLabel)

        # make the layout placeholder the central widget
        window.setLayout(layout)

        # connect slider value to map zoom via signal slots
        app.connect(zoomSlider, SIGNAL('valueChanged(int)'), marble.zoomView)

        # display the zoom level on the label, but pass it though the
        # custom self.setZoomLabel function to add prefix text
        app.connect(marble, SIGNAL('zoomChanged(int)'), self.setZoomLabel)

        # resize the window
        window.resize(600, 400)

        # display the app
        window.show()

        app.exec_()

    def setZoomLabel(self, value):
        self.zoomLabel.setText("Zoom Level: " + str(value))

MainWindow()

Save the code above as marble_controls.py and run it:

python marble_controls.py

If things go fine, you end up with a map application along with a slider and label below it. The map should be centered on Australia and have a zoom level of 1200 to start with: