Qt Threading?

I have an app that I wrote using Ruby-Qt2. The main application is
fine, but I want to add something to it. I want a listener thread that
waits for incoming signals. The thread would need to operate as a loop.
For my example I just made a basic closed iterator to test things out.

Here is a sample:

···

-----------------

require "qt2"
include Qt2
require "applicationWindow" # a derived Qt class I made

listener=Thread.new {
  puts "this is a sample of my listener thread!\n"
  10.times do |i|
    sleep 1
    puts "#{i} second(s)...\n"
  end
  }

qtApp = Thread.new {
  a = QApplication.new([$0]+ARGV)
  mw = ApplicationWindow.new
  mw.setCaption( QString.new("Qt App") )
  mw.show
  a.exec
  }

listener.join
qtApp.join

------------------

The problem is that the threads don't seem to work independently. The
listener thread won't advance until the Qt application has processed a
couple of events. So the seconds don't count up in real-time. This
takes place on a Win32 platform, so I don't think I can use a fork
method to split things off independently.

Any suggestions on how my listening thread can work independently on my
Win32 platform? I have read about the QThread object, but am not sure
that this is the way to go...

gregarican wrote:

The problem is that the threads don't seem to work independently. The
listener thread won't advance until the Qt application has processed a
couple of events. So the seconds don't count up in real-time. This
takes place on a Win32 platform, so I don't think I can use a fork
method to split things off independently.

I did stumble across -->
http://lists.trolltech.com/qt-interest/1997-06/thread00137-0.html,
which details how to implement QSocketNotify. I am assume this might be
the way to go?

gregarican wrote:

gregarican wrote:

The problem is that the threads don't seem to work independently. The
listener thread won't advance until the Qt application has processed a
couple of events. So the seconds don't count up in real-time. This
takes place on a Win32 platform, so I don't think I can use a fork
method to split things off independently.

Ruby doesn't use native threads, and so as far as Qt is concerned you have a
single threaded application. Only when the Qt runtime calls say a ruby slot
in your code, will ruby be able to schedule the background thread to run.

I did stumble across -->
http://lists.trolltech.com/qt-interest/1997-06/thread00137-0.html,
which details how to implement QSocketNotify. I am assume this might be
the way to go?

Yes, it is. That way you don't need an extra thread, and you can detect any
input on the socket as part of the normal Qt event loop. But you didn't
describe quite what you wanted to monitor in your original post, I didn't
know what you meant by 'incoming signals'.

-- Richard

Richard Dale wrote:

Yes, it is. That way you don't need an extra thread, and you can detect any
input on the socket as part of the normal Qt event loop. But you didn't
describe quite what you wanted to monitor in your original post, I didn't
know what you meant by 'incoming signals'.

I have a CRM application that I've written. And I am looking to add CTI
screen pops coming from alerting phone calls. This is based off my
recent RubyPhone addition to the RubyForge projects. I want the caller
ID to be pushed into the CRM application's customer lookup window. My
CTI thread is just a loop that listens for the CTI caller ID
information.

Like this:

···

------------------------

require "tsapi"

screenPop=Thread.new {
  puts "screen pop thread started!\n"
  tsession=Tsapi.new("555","AVAYA#MAGIX#CSTA#MERLIN-CTI", "username",
"password", "CTI Test")
  puts "tsession is #{tsession}.\n"

  # this represents the call ID and caller ID of the incoming caller
  caller = 0
  callingNum= 0

  # this represents the result set of the contact database lookup
  contactData =

  puts "trying to invoke tsession.open()...\n"
  results=tsession.open
  puts "tsession open() returned #{results}.\n"
  sleep 1

  puts "trying to invoke tsession.monitorOn()...\n"
  results=tsession.monitorOn(CF_DELIVERED, 0, 0, 0)
  puts "tsession monitorOn() returned #{results}.\n"
  sleep 1

  loop do
    sleep 1
    if tsession.ringing? == true
      caller=tsession.callIdMon
      callingNum=tsession.callDevIdMon
      puts "alerting call #{caller} from #{callingNum}.\n"
      # retrieve the customer contact data associated with the incoming
calling number
      c = XMLRPC::Client.new("10.0.0.200", "/RPC2", 8888)
      contactData = c.call("crm.getContactScreenPop", "#{callingNum}")
      if contactData == 1
        @displayName, @compName, @lastName, @middleName, @firstName,
@street, @city, @state, @zip, @comments, @custNum, @birthday,
@anniversary, @spouseName, @homeCity, @homeZip, @homeState,
@homeStreet, @homeFax, @homePhone, @busFax, @busPhone, @cellPhone = ""
      else
        @displayName = contactData[0]
        @compName = contactData[1]
        @lastName = contactData[2]
        @middleName = contactData[3]
        @firstName = contactData[4]
        @street = contactData[5]
        @city = contactData[6]
        @state = contactData[7]
        @zip = contactData[8]
        @comments = contactData[9]
        @custNum = contactData[10]
        @birthday = contactData[11]
        @anniversary = contactData[12]
        @spouseName = contactData[13]
        @homeCity = contactData[14]
        @homeZip = contactData[15]
        @homeState = contactData[16]
        @homeStreet = contactData[17]
        @homeFax = contactData[18]
        @homePhone = contactData[19]
        @busFax = contactData[20]
        @busPhone = contactData[21]
        @cellPhone = contactData[22]

        puts "Contact data:\n"
        puts "-------------\n"
        puts "Full Name: #{@displayName}\n"
        puts "Street: #{@street}\n"
        puts "City: #{@city}\n"
        puts "State: #{@state}\n"
        puts "ZIP: #{@zip}\n"
        puts "Home Phone: #{@homePhone}\n"
        puts "Bus. Phone: #{@busPhone}\n"
        puts "Cell Phone: #{@cellPhone}\n"
        puts "-------------------------\n"
        puts "Comments: #{@comments}\n"
      end
    sleep 1
    end
  end
  }

------------------------

So when the loop detects an incoming phone call I throw an XMLRPC call
out and get the CRM data back.

gregarican wrote:

Richard Dale wrote:

Yes, it is. That way you don't need an extra thread, and you can detect
any input on the socket as part of the normal Qt event loop. But you
didn't describe quite what you wanted to monitor in your original post, I
didn't know what you meant by 'incoming signals'.

I have a CRM application that I've written. And I am looking to add CTI
screen pops coming from alerting phone calls. This is based off my
recent RubyPhone addition to the RubyForge projects. I want the caller
ID to be pushed into the CRM application's customer lookup window. My
CTI thread is just a loop that listens for the CTI caller ID
information.

You could use QSocketNotifier if there is something on a socket. You have:

if tsession.ringing? == true

As the condition controlling the loop (btw you don't need '== true' test).
If you can access the underlying socket, you can use QSocketNotifier.

Another way would be to set a QTimer to call a slot in your
ApplicationWindow class once a second. The slot doesn't have to actually do
anything, but it would give the background thread loop below a chance to
run.

-- Richard

···

Like this:
------------------------

require "tsapi"

screenPop=Thread.new {
puts "screen pop thread started!\n"
tsession=Tsapi.new("555","AVAYA#MAGIX#CSTA#MERLIN-CTI", "username",
"password", "CTI Test")
puts "tsession is #{tsession}.\n"

# this represents the call ID and caller ID of the incoming caller
caller = 0
callingNum= 0

# this represents the result set of the contact database lookup
contactData =

puts "trying to invoke tsession.open()...\n"
results=tsession.open
puts "tsession open() returned #{results}.\n"
sleep 1

puts "trying to invoke tsession.monitorOn()...\n"
results=tsession.monitorOn(CF_DELIVERED, 0, 0, 0)
puts "tsession monitorOn() returned #{results}.\n"
sleep 1

loop do
sleep 1
if tsession.ringing? == true
caller=tsession.callIdMon
callingNum=tsession.callDevIdMon
puts "alerting call #{caller} from #{callingNum}.\n"
# retrieve the customer contact data associated with the incoming
calling number
c = XMLRPC::Client.new("10.0.0.200", "/RPC2", 8888)
contactData = c.call("crm.getContactScreenPop", "#{callingNum}")
if contactData == 1
@displayName, @compName, @lastName, @middleName, @firstName,
@street, @city, @state, @zip, @comments, @custNum, @birthday,
@anniversary, @spouseName, @homeCity, @homeZip, @homeState,
@homeStreet, @homeFax, @homePhone, @busFax, @busPhone, @cellPhone = ""
else
@displayName = contactData[0]
@compName = contactData[1]
@lastName = contactData[2]
@middleName = contactData[3]
@firstName = contactData[4]
@street = contactData[5]
@city = contactData[6]
@state = contactData[7]
@zip = contactData[8]
@comments = contactData[9]
@custNum = contactData[10]
@birthday = contactData[11]
@anniversary = contactData[12]
@spouseName = contactData[13]
@homeCity = contactData[14]
@homeZip = contactData[15]
@homeState = contactData[16]
@homeStreet = contactData[17]
@homeFax = contactData[18]
@homePhone = contactData[19]
@busFax = contactData[20]
@busPhone = contactData[21]
@cellPhone = contactData[22]

puts "Contact data:\n"
puts "-------------\n"
puts "Full Name: #{@displayName}\n"
puts "Street: #{@street}\n"
puts "City: #{@city}\n"
puts "State: #{@state}\n"
puts "ZIP: #{@zip}\n"
puts "Home Phone: #{@homePhone}\n"
puts "Bus. Phone: #{@busPhone}\n"
puts "Cell Phone: #{@cellPhone}\n"
puts "-------------------------\n"
puts "Comments: #{@comments}\n"
end
sleep 1
end
end
}

------------------------

So when the loop detects an incoming phone call I throw an XMLRPC call
out and get the CRM data back.

Richard Dale wrote:

Another way would be to set a QTimer to call a slot in your
ApplicationWindow class once a second. The slot doesn't have to actually do
anything, but it would give the background thread loop below a chance to
run.

The QTimer works like a champ. This is a great solution. I just need to
read up on the docs some more to ensure
that the QTimer gets killed off when the QApplication exits. Now when I
exit the GUI the QTimer thread DOS box stays on the Windows taskbar.
Other than that this was a quick fix. It's cool watching my caller ID
screen pops feed into my CRM application. Thanks for your tip!