Results 1 to 2 of 2

Thread: Python + PyQt IRC Client

  1. #1
    Join Date
    Oct 2008
    Posts
    11
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Python + PyQt IRC Client

    Hi all, I've been pulling my hair out for a while now and I hope someone here can help me. I'm working with PyQt (4) and Python 2.5, in a Linux environment. My aim is to have a basic Qt based IRC client. I'm aware of the IRC RFC and the ins and outs of that etc, so I'm not to worried there.

    I thought the best way to do it would be like: [IRC framework/API]--->[something that links the two]<---[Qt GUI code], although I'm starting to have my doubts now.

    The GUI I've built with Qt Designer, and isn't much of a problem. The API type module for IRC I've started mainly works (infact as a starting point I've borrowed it from elsewhere on the net and tweaked it to my needs), as in I can have an IRC object connect to a server, send messages, etc via the command line. It's the linking of the two I'm worried about - I was going for total seperation between presentation and underlying mechanics as far as is possible. I have many versions of the above scenario from hours of trying, but I'll go ahead and paste the code for the 3 main files described so far.

    This is the 'API':

    Qt Code:
    1. import sys
    2. import socket
    3. import string
    4. import threading
    5. import time
    6. import Queue
    7.  
    8. """
    9. class ReadFromServer():
    10.  
    11. def loop(self):
    12. while 1:
    13. try:
    14. data = self.irc.recv(4096)
    15. if data.find('PING') != -1:
    16. self.irc.send('PONG ' + data.split() [1] + '\r\n')
    17. if len(data) > 0:
    18. print data
    19. time.sleep(0.1)
    20. except:
    21. print 'Error: Possible interupt.'
    22. break
    23. """
    24.  
    25. """ Set up buffer for incoming data """
    26. incomingBuffer = Queue.Queue(5000)
    27.  
    28. class IRC:
    29.  
    30. recv_function = ''
    31. irc = ''
    32.  
    33. def __init__(self):
    34. self.irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    35. self.recv_function = self.recv
    36.  
    37. def recvLoop(self):
    38. while 1:
    39. try:
    40. data = self.irc.recv(4096)
    41. if data.find('PING') != -1:
    42. self.irc.send('PONG ' + data.split() [1] + '\r\n')
    43. #if data.find('hi') != -1:
    44. #client.channelSend('#crasp', 'hai2u :)')
    45. if len(data) > 0:
    46. incomingBuffer.put(data)
    47. print data
    48. time.sleep(0.1)
    49. except:
    50. print 'Error: Possible interupt.'
    51. break
    52.  
    53. def newConnection(self, server, port, nick, ident, realName):
    54. self.server = server
    55. self.port = port
    56. self.nick = nick
    57. self.ident = ident
    58. self.realName = realName
    59.  
    60. self.irc.connect ( ( self.server, self.port ) )
    61. self.rawSend("NICK %s\r\n" % self.nick)
    62. self.rawSend("USER %s %s unused :%s\r\n" % (self.ident, self.server, self.realName))
    63.  
    64. def quit(self):
    65. self.rawSend('QUIT :')
    66.  
    67. def part(self):
    68. self.rawSend('PART :')
    69.  
    70. def join(self, channel):
    71. self.rawSend('JOIN ' + channel)
    72.  
    73. def channelSend(self, channel, text):
    74. self.rawSend('PRIVMSG ' + channel + ' :' + text)
    75.  
    76. def set_recv_function(self, f):
    77. self.recv_function = f
    78.  
    79. def recv(self, s):
    80. # default receive function
    81. print s
    82.  
    83. def rawSend(self, s):
    84. self.irc.send(s + '\r\n');
    85.  
    86. def my_receive(s):
    87. print s
    88. """
    89. client = IRC()
    90. client.newConnection('irc.oftc.net', 6667, 'crispycream', 'crisp', 'crisp')
    91. client.join('#crasp')
    92. client.channelSend('#crasp', 'blah')
    93. client.set_recv_function(my_receive)
    94. client.recvLoop()
    95.  
    96. while 1:
    97. if client.incomingBuffer.qsize() > 0:
    98. item = client.incomingBuffer.get()
    99. print item
    100. client.incomingBuffer.task_done()
    101. """
    To copy to clipboard, switch view to plain text mode 
    This is the Qt Designed code:

    Qt Code:
    1. # -*- coding: utf-8 -*-
    2.  
    3. # Form implementation generated from reading ui file 'crispircmainwindow.ui'
    4. #
    5. # Created: Sun Jan 25 04:03:58 2009
    6. # by: PyQt4 UI code generator 4.4.4
    7. #
    8. # WARNING! All changes made in this file will be lost!
    9.  
    10. from PyQt4 import QtCore, QtGui
    11.  
    12. class Ui_CrispIRCMainWindow(object):
    13. def setupUi(self, CrispIRCMainWindow):
    14. CrispIRCMainWindow.setObjectName("CrispIRCMainWindow")
    15. CrispIRCMainWindow.resize(531, 479)
    16. sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
    17. sizePolicy.setHorizontalStretch(0)
    18. sizePolicy.setVerticalStretch(0)
    19. sizePolicy.setHeightForWidth(CrispIRCMainWindow.sizePolicy().hasHeightForWidth())
    20. CrispIRCMainWindow.setSizePolicy(sizePolicy)
    21. self.centralwidget = QtGui.QWidget(CrispIRCMainWindow)
    22. self.centralwidget.setObjectName("centralwidget")
    23. self.widget = QtGui.QWidget(self.centralwidget)
    24. self.widget.setGeometry(QtCore.QRect(0, 0, 531, 431))
    25. self.widget.setObjectName("widget")
    26. self.gridLayout = QtGui.QGridLayout(self.widget)
    27. self.gridLayout.setObjectName("gridLayout")
    28. self.displayBrowser = QtGui.QTextBrowser(self.widget)
    29. self.displayBrowser.setObjectName("displayBrowser")
    30. self.gridLayout.addWidget(self.displayBrowser, 0, 0, 1, 2)
    31. self.connectButton = QtGui.QPushButton(self.widget)
    32. self.connectButton.setObjectName("connectButton")
    33. self.gridLayout.addWidget(self.connectButton, 1, 0, 1, 1)
    34. self.disconnectButton = QtGui.QPushButton(self.widget)
    35. self.disconnectButton.setObjectName("disconnectButton")
    36. self.gridLayout.addWidget(self.disconnectButton, 1, 1, 1, 1)
    37. CrispIRCMainWindow.setCentralWidget(self.centralwidget)
    38. self.statusbar = QtGui.QStatusBar(CrispIRCMainWindow)
    39. self.statusbar.setObjectName("statusbar")
    40. CrispIRCMainWindow.setStatusBar(self.statusbar)
    41. self.menubar = QtGui.QMenuBar(CrispIRCMainWindow)
    42. self.menubar.setGeometry(QtCore.QRect(0, 0, 531, 25))
    43. self.menubar.setObjectName("menubar")
    44. self.menuFile = QtGui.QMenu(self.menubar)
    45. self.menuFile.setObjectName("menuFile")
    46. self.menu_Edit = QtGui.QMenu(self.menubar)
    47. self.menu_Edit.setObjectName("menu_Edit")
    48. CrispIRCMainWindow.setMenuBar(self.menubar)
    49. self.actionBlah = QtGui.QAction(CrispIRCMainWindow)
    50. self.actionBlah.setObjectName("actionBlah")
    51. self.actionBlaaah = QtGui.QAction(CrispIRCMainWindow)
    52. self.actionBlaaah.setObjectName("actionBlaaah")
    53. self.action_Preferences = QtGui.QAction(CrispIRCMainWindow)
    54. self.action_Preferences.setObjectName("action_Preferences")
    55. self.menuFile.addAction(self.actionBlah)
    56. self.menuFile.addSeparator()
    57. self.menuFile.addAction(self.actionBlaaah)
    58. self.menu_Edit.addAction(self.action_Preferences)
    59. self.menubar.addAction(self.menuFile.menuAction())
    60. self.menubar.addAction(self.menu_Edit.menuAction())
    61.  
    62. self.retranslateUi(CrispIRCMainWindow)
    63. QtCore.QMetaObject.connectSlotsByName(CrispIRCMainWindow)
    64.  
    65. def retranslateUi(self, CrispIRCMainWindow):
    66. CrispIRCMainWindow.setWindowTitle(QtGui.QApplication.translate("CrispIRCMainWindow", "Crisp IRC", None, QtGui.QApplication.UnicodeUTF8))
    67. self.connectButton.setText(QtGui.QApplication.translate("CrispIRCMainWindow", "Connect", None, QtGui.QApplication.UnicodeUTF8))
    68. self.disconnectButton.setText(QtGui.QApplication.translate("CrispIRCMainWindow", "Disconnect", None, QtGui.QApplication.UnicodeUTF8))
    69. self.menuFile.setTitle(QtGui.QApplication.translate("CrispIRCMainWindow", "&File", None, QtGui.QApplication.UnicodeUTF8))
    70. self.menu_Edit.setTitle(QtGui.QApplication.translate("CrispIRCMainWindow", "&Edit", None, QtGui.QApplication.UnicodeUTF8))
    71. self.actionBlah.setText(QtGui.QApplication.translate("CrispIRCMainWindow", "Blah", None, QtGui.QApplication.UnicodeUTF8))
    72. self.actionBlaaah.setText(QtGui.QApplication.translate("CrispIRCMainWindow", "Blaaah", None, QtGui.QApplication.UnicodeUTF8))
    73. self.action_Preferences.setText(QtGui.QApplication.translate("CrispIRCMainWindow", "&Preferences", None, QtGui.QApplication.UnicodeUTF8))
    To copy to clipboard, switch view to plain text mode 
    And finally, crucially, this is the code that attempts to link the two together.

    Qt Code:
    1. from PyQt4.QtCore import *
    2. from PyQt4.QtGui import *
    3.  
    4. import time
    5.  
    6. import ui_crispircmainwindow
    7. import crisp_irc
    8.  
    9. MAC = "qt_mac_set_native_menubar" in dir()
    10.  
    11. class CrispIRCMainWindow(QMainWindow, ui_crispircmainwindow.Ui_CrispIRCMainWindow, crisp_irc.IRC):
    12.  
    13. def __init__(self, parent=None):
    14. super(CrispIRCMainWindow, self).__init__(parent)
    15. self.__index = 0
    16. self.setupUi(self)
    17.  
    18. @pyqtSignature("")
    19. def on_connectButton_clicked(self):
    20. self.displayBrowser.append('Connecting...')
    21. client = crisp_irc.IRC()
    22. client.newConnection('irc.oftc.net', 6667, 'crispycream', 'crisp', 'crisp')
    23. client.join('#crasp')
    24. client.channelSend('#crasp', 'blah')
    25. client.set_recv_function(crisp_irc.my_receive)
    26. client.recvLoop()
    27.  
    28. if crisp_irc.incomingBuffer.qsize() > 0:
    29. item = crisp_irc.incomingBuffer.get()
    30. print item
    31. crisp_irc.incomingBuffer.task_done()
    32.  
    33. #if irc._incomingBuffer.qsize() > 0:
    34. # self.displayBrowser.append('BUFFER LARGER THAN ZERO')
    35.  
    36. @pyqtSignature("")
    37. def on_disconnectButton_clicked(self):
    38. self.displayBrowser.append('(Not really) Quitting...')
    39.  
    40. if __name__ == "__main__":
    41. import sys
    42.  
    43. app = QApplication(sys.argv)
    44. form = CrispIRCMainWindow()
    45.  
    46. form.show()
    47. app.exec_()
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Oct 2008
    Posts
    11
    Thanks
    4
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Python + PyQt IRC Client

    Apologies for all that. Admitedly my understanding of OOP could be a little stronger, but the main problem I'm running into is that when I run that last lot of code, stuff connects in the background, but then the Connect button isn't 'released' and the GUI feeezes, forcing me to kill the process. I believe the root cause of this is the infinite loop I have intentionally created to keep checking the socket for incoming data. I'm not really sure of a better way to go about this.

    What I'm really after is when I hit connect, all of the stuff that happens in the console in the background, happens in the main textBrowser in the GUI. Hitting disconnect to disconnect would be an added bonus If I can get over this barrier, I believe I'll be able to get a lot further with this. This is the first time I've done any meaningful GUI programming (I got my feet wet with a PyQt calculator app) so there may be something/s I've overlooked.

    If anyone has a better suggestion as to how to do things then I'm all ears. I've tried using threads too. If it's not clear what I mean, then this image might help you visualise the problem: http://www.drivers-som.com/Qt/pyqt_irc.png Stuff in the console should go in the GUI

    Apologies for the long post, but if you need any more information just ask and I'll provide. Thanks.

Similar Threads

  1. Qt, Python and pop-ups
    By bashamehboob in forum Qt Programming
    Replies: 1
    Last Post: 29th September 2007, 19:33
  2. synching client readings to server output
    By OnionRingOfDoom in forum Qt Programming
    Replies: 14
    Last Post: 28th January 2006, 18:15

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.