multisil |
2010-04-18 08:40 |
Re: How to compile Qt location example ?
Quote:
Originally Posted by bartenst
(Post 615319)
@multisil: Have you been able to fix your problem with the segmentation fault?
Greetings,
bartenst
|
Yes. I have a solution for having QT Main Loop for UI and GTK+ loop for GPS device. The solution is to create a separate thread for GPS (as a QThread). In your main app you have to initialize the thread, but not actually start it before your QT main loop has started. So you have to post a QTimer event to your QT Main Loop to start the GTK+ loop. Also, you have to take care of closing the thread when your app is closing, so you have to implement a method for this in you main app class.
So my main.py would be (I suppose you have a simple QT Designer created UI file my_ui.py with one button (myBtn) and text label (msgLabel)):
Code:
import sys
from my_ui import *
from GPSConnection import *
class myWindow(QtGui.QMainWindow):
#
# Constructor
#
def __init__(self, parent=None):
super(myWindow, self).__init__()
#
# UI myBtn button click handler.
#
def myBtnClicked(self):
if self.gps.fix:
msg = "Lat: " + str(self.gps.lat) + " Lon: " + str(self.gps.lon)
self.ui.msgLabel.setText(QtGui.QApplication.translate("MainWindow", msg, None, QtGui.QApplication.UnicodeUTF8))
#
# Application is about to close. We have to clean up the GPS related things, namely
# close the GPS device and quit the GPSConnection thread.
#
def closingApp(self):
print "Closing..."
if self.gps.running:
self.gps.control.stop()
self.gps.loop.quit()
#
# Handler for a timer event that should happen when the QT Main Loop has started.
# We can safely start the GPSConnection thread, that has its own GTK+ event loop.
#
def singleUpdate(self):
print "Start timer"
if self.gps.running == False:
self.gps.run()
#****************************************************************#
#* MAIN APPLICATION *#
#****************************************************************#
#
# We instantiate a QApplication
#
app = QtGui.QApplication(sys.argv)
MainWindow = myWindow()
MainWindow.ui = Ui_MainWindow()
MainWindow.ui.setupUi(MainWindow)
MainWindow.gps = GPSConnection(app)
MainWindow.show()
#
# Timer for launching the GPS when app starts. The GPSConnection can not be started
# before the QT Main Loop, so this ensures that it starts after we have started
# processing events in the QT Main Loop. GPSConnection class uses GTK+ main loop
# and that is just ok, since we are running GPSConnection in its own thread.
#
gpsLaunchTimer = QtCore.QTimer()
gpsLaunchTimer.singleShot(1000, MainWindow.singleUpdate)
#
# Signals that enable us to catch the event when app is closing
# so we can close the GPS device and thread. We propably do not need both.
#
QtCore.QObject.connect(app,QtCore.SIGNAL("aboutToQuit()"), MainWindow.closingApp)
#QtCore.QObject.connect(app,QtCore.SIGNAL("lastWindowClosed()"), MainWindow.closingApp)
#
# Now we can start the UI & QT Main Loop.
#
sys.exit(app.exec_())
and GPSConnection class in GPSConnection.py:
Code:
import os
import location
from PyQt4 import QtCore
import gobject
# This class implements a GPS connection class to the gps device.
# The class can be safely used in QT applications, because this
# class is supposed to be running in its own thread. Also, the
# class implements its own GTK+ event loop.
#
# The GPSConnection thread must not be started before the QT Main
# loop. Instead, use QTimer to generate a start event for the
# GPSConnection thread. This way, the even is prosessed
# in the QT Main Loop after the loop has been started.
#
# Also, you should implement closingApp method in your QT main loop
# (in you main window QObject) that takes care of shutting down the
# GPS device and stops the GPSConnection thread.
#
class GPSConnection (QtCore.QThread) :
#
# Constructor
#
def __init__(self, app, parent=None):
super(GPSConnection, self).__init__()
self.control = location.GPSDControl.get_default()
self.GPSDevice = location.GPSDevice()
self.control.set_properties(preferred_method=location.METHOD_USER_SELECTED, preferred_interval=location.INTERVAL_DEFAULT)
self.GPSDevice.connect("changed", self.onChanged, self.control)
self.control.connect("error-verbose", self.onError, self)
self.control.connect("gpsd-stopped", self.onStop, self.control)
self.lat = 0.0
self.lon = 0.0
self.fix = False
self.running = False
self.app = app
self.loop = None
#
# GPS error callback handler
#
def onError (self, control, error, data):
print "location error: %d... quitting" % error
self.running = False
if error == location.ERROR_USER_REJECTED_DIALOG:
print "User didn't enable requested methods"
elif error == location.ERROR_USER_REJECTED_SETTINGS:
print "User changed settings, which disabled location"
elif error == location.ERROR_BT_GPS_NOT_AVAILABLE:
print "Problems with BT GPS"
elif error == location.ERROR_METHOD_NOT_ALLOWED_IN_OFFLINE_MODE:
print "Requested method is not allowed in offline mode"
elif error == location.ERROR_SYSTEM:
print "System error"
#
# Handler for stopping the GPS device.
#
def onStop (self, control, data):
if self.running:
self.running = False
print "In onStop method"
data.stop()
#
# Callback handler for the event when location fix has changed.
#
def onChanged (self, device, data):
print "In inChanged method"
if not device:
return
if device.fix:
if device.fix[1] & location.GPS_DEVICE_LATLONG_SET:
self.lat = device.fix[4]
self.lon = device.fix[5]
self.fix = True
#
# Start the GPS device.
#
def start_location(self, data):
data.start()
return False
#
# Start the GTK+ main loop. The loop initializes the start_location callback which actually
# runs the GPS device.
#
def run(self):
print "In run"
self.running = True
self.loop = gobject.MainLoop()
gobject.idle_add(self.start_location, self.control)
self.loop.run()
Hope this helps!
|