diff --git a/IPython/frontend/qt/console/frontend_widget.py b/IPython/frontend/qt/console/frontend_widget.py
index 848100f..6ee43f5 100644
--- a/IPython/frontend/qt/console/frontend_widget.py
+++ b/IPython/frontend/qt/console/frontend_widget.py
@@ -5,11 +5,13 @@ import time
 import types
 
 # System library imports
-from IPython.zmq.session import Message, Session
 from pygments.lexers import PythonLexer
 from PyQt4 import QtCore, QtGui
 import zmq
 
+# IPython imports.
+from IPython.zmq.session import Message, Session
+
 # Local imports
 from call_tip_widget import CallTipWidget
 from completion_lexer import CompletionLexer
@@ -100,23 +102,18 @@ class FrontendWidget(HistoryConsoleWidget):
     # 'QWidget' interface
     #---------------------------------------------------------------------------
     
-    def __init__(self, parent=None, session=None, request_socket=None,
-                 sub_socket=None):
+    def __init__(self, kernel_manager, parent=None):
         super(FrontendWidget, self).__init__(parent)
-        self.continuation_prompt = '... '
 
         self._call_tip_widget = CallTipWidget(self)
         self._compile = CommandCompiler()
         self._completion_lexer = CompletionLexer(PythonLexer())
         self._highlighter = FrontendHighlighter(self)
 
-        self.session = Session() if session is None else session
-        self.request_socket = request_socket
-        self.sub_socket = sub_socket
-
         self.document().contentsChange.connect(self._document_contents_change)
 
-        self._kernel_connected() # XXX
+        self.continuation_prompt = '... '
+        self.kernel_manager = kernel_manager
 
     def focusOutEvent(self, event):
         """ Reimplemented to hide calltips.
@@ -216,6 +213,20 @@ class FrontendWidget(HistoryConsoleWidget):
         """
         self.execute_source('run %s' % path, hidden=hidden)
 
+    def _get_kernel_manager(self):
+        """ Returns the current kernel manager.
+        """
+        return self._kernel_manager
+
+    def _set_kernel_manager(self, kernel_manager):
+        """ Sets a new kernel manager, configuring its channels as necessary.
+        """
+        self._kernel_manager = kernel_manager
+        self._sub_channel = kernel_manager.get_sub_channel()
+        self._xreq_channel = kernel_manager.get_xreq_channel()
+
+    kernel_manager = property(_get_kernel_manager, _set_kernel_manager)
+
     #---------------------------------------------------------------------------
     # 'FrontendWidget' protected interface
     #---------------------------------------------------------------------------
diff --git a/IPython/frontend/qt/kernelmanager.py b/IPython/frontend/qt/kernelmanager.py
new file mode 100644
index 0000000..8868f55
--- /dev/null
+++ b/IPython/frontend/qt/kernelmanager.py
@@ -0,0 +1,79 @@
+""" A KernelManager that provides channels that use signals and slots.
+"""
+
+# System library imports.
+from PyQt4 import QtCore
+
+# IPython imports.
+from IPython.zmq.kernel_manager import KernelManager, SubSocketChannel, \
+    XReqSocketChannel, RepSocketChannel
+
+
+class QtKernelManager(KernelManager):
+    """ A KernelManager that provides channels that use signals and slots.
+    """
+
+    sub_channel_class = QtSubSocketChannel
+    xreq_channel_class = QtXReqSocketChannel
+    rep_channel_class = QtRepSocketChannel
+
+
+class QtSubSocketChannel(SubSocketChannel, QtCore.QObject):
+
+    # Emitted when any message is received.
+    message_received = QtCore.pyqtSignal(dict)
+
+    # Emitted when a message of type 'pyout' or 'stdout' is received.
+    output_received = QtCore.pyqtSignal(dict)
+
+    # Emitted when a message of type 'pyerr' or 'stderr' is received.
+    error_received = QtCore.pyqtSignal(dict)
+
+    #---------------------------------------------------------------------------
+    # 'SubSocketChannel' interface
+    #---------------------------------------------------------------------------
+    
+    def call_handlers(self, msg):
+        """ Reimplemented to emit signals instead of making callbacks.
+        """
+        # Emit the generic signal.
+        self.message_received.emit(msg)
+        
+        # Emit signals for specialized message types.
+        msg_type = msg['msg_type']
+        if msg_type in ('pyout', 'stdout'):
+            self.output_received.emit(msg)
+        elif msg_type in ('pyerr', 'stderr'):
+            self.error_received.emit(msg)
+
+
+class QtXReqSocketChannel(XReqSocketChannel, QtCore.QObject):
+
+    # Emitted when any message is received.
+    message_received = QtCore.pyqtSignal(dict)
+
+    # Emitted when a reply has been received for the corresponding request type.
+    execute_reply = QtCore.pyqtSignal(dict)
+    complete_reply = QtCore.pyqtSignal(dict)
+    object_info_reply = QtCore.pyqtSignal(dict)
+    
+    #---------------------------------------------------------------------------
+    # 'XReqSocketChannel' interface
+    #---------------------------------------------------------------------------
+    
+    def call_handlers(self, msg):
+        """ Reimplemented to emit signals instead of making callbacks.
+        """
+        # Emit the generic signal.
+        self.message_received.emit(msg)
+        
+        # Emit signals for specialized message types.
+        msg_type = msg['msg_type']
+        signal = getattr(self, msg_type, None)
+        if signal:
+            signal.emit(msg)
+
+
+class QtRepSocketChannel(RepSocketChannel, QtCore.QObject):
+
+    pass
diff --git a/IPython/zmq/kernelmanager.py b/IPython/zmq/kernelmanager.py
index 5dad5c0..2308c92 100644
--- a/IPython/zmq/kernelmanager.py
+++ b/IPython/zmq/kernelmanager.py
@@ -1,9 +1,6 @@
 """Kernel frontend classes.
 
-To do:
-
-1. Create custom channel subclasses for Qt.
-2. Create logger to handle debugging and console messages.
+TODO: Create logger to handle debugging and console messages.
 
 """
 
@@ -23,6 +20,10 @@ class MissingHandlerError(Exception):
 
 class KernelManager(object):
 
+    sub_channel_class = SubSocketChannel
+    xreq_channel_class = XReqSocketChannel
+    rep_channel_class = RepSocketChannel
+
     def __init__(self, xreq_addr, sub_addr, rep_addr, 
                  context=None, session=None):
         self.context = zmq.Context() if context is None else context
@@ -55,15 +56,16 @@ class KernelManager(object):
 
     def get_sub_channel(self):
         """Get the SUB socket channel object."""
-        return SubSocketChannel(self.context, self.session, self.sub_addr)
+        return self.sub_channel_class(self.context, self.session, self.sub_addr)
     
     def get_xreq_channel(self):
         """Get the REQ socket channel object to make requests of the kernel."""
-        return XReqSocketChannel(self.context, self.session, self.xreq_addr)
+        return self.xreq_channel_class(self.context, self.session, 
+                                       self.xreq_addr)
     
     def get_rep_channel(self):
         """Get the REP socket channel object to handle stdin (raw_input)."""
-        return RepSocketChannel(self.context, self.session, self.rep_addr)
+        return self.rep_channel_class(self.context, self.session, self.rep_addr)
 
 
 class ZmqSocketChannel(Thread):
@@ -186,14 +188,7 @@ class XReqSocketChannel(ZmqSocketChannel):
 
     def _handle_recv(self):
         msg = self.socket.recv_json()
-        print "Got reply:", msg
-        try:
-            handler = self.handler_queue.get(False)
-        except Empty:
-            print "Message received with no handler!!!"
-            print msg
-        else:
-            self.call_handler(handler, msg)
+        self.call_handlers(msg)
 
     def _handle_send(self):
         try:
@@ -222,13 +217,13 @@ class XReqSocketChannel(ZmqSocketChannel):
     def complete(self, text, line, block=None, callback=None):
         content = dict(text=text, line=line)
         msg = self.session.msg('complete_request', content)
-        return self._queue_request(msg, callback)
+        self._queue_request(msg, callback)
         return msg['header']['msg_id']
 
     def object_info(self, oname, callback=None):
         content = dict(oname=oname)
         msg = self.session.msg('object_info_request', content)
-        return self._queue_request(msg, callback)
+        self._queue_request(msg, callback)
         return msg['header']['msg_id']
 
     def _find_handler(self, name, callback):
@@ -255,6 +250,15 @@ class XReqSocketChannel(ZmqSocketChannel):
         assert callable(func), "not a callable: %r" % func
         self._overriden_call_handler = func
 
+    def call_handlers(self, msg):
+        try:
+            handler = self.handler_queue.get(False)
+        except Empty:
+            print "Message received with no handler!!!"
+            print msg
+        else:
+            self.call_handler(handler, msg)
+
     def call_handler(self, handler, msg):
         if self._overriden_call_handler is not None:
             self._overriden_call_handler(handler, msg)