我试图在Python 2.7中使用扭曲的小型GTK 3 irc客户端。目前,我有一个非常基本的客户端,可以成功连接到irc网络并在主文本区域显示一些东西。我目前正在努力实现多渠道支持,但是当一个频道加入时,用一个包含频道的条目填充GtkListBox似乎不起作用。
python代码如下:
main.py
from twisted.internet import gtk3reactor
gtk3reactor.install()
from twisted.internet import reactor
from gi.repository import Gtk, GObject
import time
from ConnectDialog import ConnectDialog
# twisted imports
from twisted.words.protocols import irc
from twisted.internet import protocol
class Client(irc.IRCClient):
def __init__(self):
self.channels = []
def _get_nickname(self):
return self.factory.username
def _get_password(self):
return self.factory.password
nickname = property(_get_nickname)
password = property(_get_password)
def connectionMade(self):
irc.IRCClient.connectionMade(self)
self.log("[Connected established at %s]" %
time.asctime(time.localtime(time.time())))
def connectionLost(self, reason):
irc.IRCClient.connectionLost(self, reason)
self.log("[Disconnected at %s]" %
time.asctime(time.localtime(time.time())))
# callbacks for events
def signedOn(self):
"""Called when bot has succesfully signed on to server."""
self.log("Successfuly connected!")
self.join(self.factory.channel)
def joined(self, channel):
self.addChannel(channel)
self.log("[You have joined %s]" % channel)
def privmsg(self, user, channel, msg):
"""This will get called when the bot receives a message."""
if not any(channel in s for s in self.channels):
self.addChannel(channel) # multiple channels for znc
user = user.split('!', 1)[0]
self.log("<%s> %s" % (user, msg))
def action(self, user, channel, msg):
"""This will get called when the bot sees someone do an action."""
user = user.split('!', 1)[0]
self.log("* %s %s" % (user, msg))
# irc callbacks
def irc_NICK(self, prefix, params):
"""Called when an IRC user changes their nickname."""
old_nick = prefix.split('!')[0]
new_nick = params[0]
self.log("%s is now known as %s" % (old_nick, new_nick))
# For fun, override the method that determines how a nickname is changed on
# collisions. The default method appends an underscore.
def alterCollidedNick(self, nickname):
"""
Generate an altered version of a nickname that caused a collision in an
effort to create an unused related name for subsequent registration.
"""
return nickname + '_'
def log(self, message):
end_iter = self.factory.messages_buffer.get_end_iter()
timestamp = time.strftime("[%H:%M:%S]", time.localtime(time.time()))
self.factory.messages_buffer.insert(end_iter, '%s %s\n' % (timestamp, message))
def addChannel(self, channel):
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
label1 = Gtk.Label(channel, xalign=0)
label2 = Gtk.Label("Some more info text here", xalign=0)
vbox.pack_start(label1, True, True, 0)
vbox.pack_start(label2, True, True, 0)
button = Gtk.Button("Close")
button.props.valign = Gtk.Align.CENTER
hbox.pack_start(button, False, True, 0)
GObject.idle_add(self.add_to_chan_list, row)
#self.factory.chan_list.add(row)
self.channels.append(channel)
def add_to_chan_list(self, row):
self.factory.chan_list.add(row)
return False
class IRCFactory(protocol.ClientFactory):
"""A factory for Clients.
A new protocol instance will be created each time we connect to the server.
"""
# the class of the protocol to build when new connection is made
protocol = Client
def __init__(self, username, channel, password, messages_buffer, chan_list, parent):
self.channel = channel
self.username = username
self.password = password
self.chan_list = chan_list
self.messages_buffer = messages_buffer
self.parent = parent
def clientConnectionLost(self, connector, reason):
"""If we get disconnected, reconnect to server."""
connector.connect()
def clientConnectionFailed(self, connector, reason):
print "connection failed:", reason
reactor.stop()
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Gnome IRC")
self.set_border_width(10)
self.set_default_size(800, 600)
hb = Gtk.HeaderBar()
hb.set_show_close_button(True)
hb.props.title = "Gnome IRC"
self.set_titlebar(hb)
button = Gtk.Button("Connect")
button.connect("clicked", self.on_connect_clicked)
hb.pack_start(button)
builder = Gtk.Builder()
builder.add_from_file("main_view.glade")
self.message_entry = builder.get_object("message_entry")
self.messages_view = builder.get_object("messages")
self.ircview = builder.get_object("ircviewpane") # GtkBox
self.chan_list = builder.get_object("channel_list") # GtkListBox
self.add(self.ircview)
self.connect("delete_event", self.on_quit)
def on_connect_clicked(self, widget):
dialog = ConnectDialog(self)
dialog.connect('response', self.dialog_response_cb)
dialog.show()
def dialog_response_cb(self, dialog, response):
if response == Gtk.ResponseType.OK:
server = dialog.address_entry.get_text()
port = int(dialog.port_entry.get_text())
nickname = dialog.nick_entry.get_text()
password = dialog.password.get_text()
channel = "#rymate"
dialog.destroy()
factory = IRCFactory(nickname, channel, password,
self.messages_view.get_buffer(),
self.chan_list, self)
# connect factory to this host and port
reactor.connectTCP(server, port, factory)
# run bot
# reactor.run()
elif response == Gtk.ResponseType.CANCEL:
dialog.destroy()
def on_quit(self, *args):
Gtk.main_quit()
reactor.callFromThread(reactor.stop)
win = MainWindow()
win.show_all()
#Gtk.main()
reactor.run()
ConnectDialog.py
from gi.repository import Gtk
class ConnectDialog(Gtk.Dialog):
def __init__(self, parent):
Gtk.Dialog.__init__(self, "Connect to a Server", parent, 0,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK), use_header_bar=1)
builder = Gtk.Builder()
builder.add_from_file("server.glade")
self.address_entry = builder.get_object("address")
self.port_entry = builder.get_object("port")
self.nick_entry = builder.get_object("username")
self.password = builder.get_object("password")
self.get_content_area().add(builder.get_object("ServerForm"))
server.glade
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkGrid" id="ServerForm">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="hexpand">True</property>
<property name="row_spacing">10</property>
<property name="column_spacing">10</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Address</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Port</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">IRC Password</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Username</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Real Name</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="address">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="input_purpose">url</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="input_purpose">number</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="password">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="visibility">False</property>
<property name="invisible_char">*</property>
<property name="placeholder_text" translatable="yes">Optional</property>
<property name="input_purpose">password</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="username">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="realname">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
</object>
</interface>
main_view.glade
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkBox" id="ircviewpane">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">4</property>
<property name="margin_right">4</property>
<property name="margin_top">4</property>
<property name="margin_bottom">4</property>
<property name="spacing">5</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow2">
<property name="width_request">310</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkListBox" id="channel_list">
<property name="width_request">290</property>
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="vexpand">True</property>
<property name="border_width">2</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="messages">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="pixels_above_lines">2</property>
<property name="pixels_below_lines">2</property>
<property name="pixels_inside_wrap">2</property>
<property name="editable">False</property>
<property name="wrap_mode">word</property>
<property name="left_margin">2</property>
<property name="right_margin">2</property>
<property name="cursor_visible">False</property>
<property name="accepts_tab">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="message_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>
据我所知,添加到GtkListBox的代码可以在窗口中工作,但不能在扭曲的ircclient类中工作。
任何帮助表示赞赏!
答案 0 :(得分:1)
事实证明,这只是我需要调用row.show_all()
以便在UI中显示listboxitem的情况