From 5dae37a260c7e4b6399b96567dfd247d930dca12 Mon Sep 17 00:00:00 2001 From: Anna Date: Thu, 8 Apr 2010 16:39:56 -0400 Subject: [PATCH] Saw the error of my ways, now using pyGtk with libglade --- README | 3 +- default.glade | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++ mytwitter.py | 161 ++++++++++--------------------- 3 files changed, 310 insertions(+), 115 deletions(-) create mode 100644 default.glade diff --git a/README b/README index 2415c25..1ec4fc7 100644 --- a/README +++ b/README @@ -7,8 +7,7 @@ mytwitter is a simple python twitter application. I wrote it for two reasons: While I doubt it will be terribly useful for anyone other than me, feel free to take it for a spin and let me know how it goes. You'll need the following python modules: -* Pmw -* Tkinter +* pyGTK * dateutil * twitter (the dev version, not 0.6), along with my patch (included here) diff --git a/default.glade b/default.glade new file mode 100644 index 0000000..c62476b --- /dev/null +++ b/default.glade @@ -0,0 +1,261 @@ + + + + + + + True + MyTwitter + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 400 + 600 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + GTK_PACK_DIRECTION_LTR + GTK_PACK_DIRECTION_LTR + + + + True + _File + True + + + + + + + True + gtk-quit + True + + + + + + + + + + + True + _Help + True + + + + + + + True + _About + True + + + + + + + + + + 0 + False + False + + + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_ALWAYS + GTK_SHADOW_NONE + GTK_CORNER_TOP_LEFT + + + + True + GTK_SHADOW_IN + + + + True + False + 0 + + + + + + + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + True + Refresh + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + + True + Friends + False + True + True + + + + 0 + False + False + + + + + + + + + 0 + False + True + + + + + + True + False + 0 + + + + True + True + True + True + 140 + + True + + False + + + + 0 + True + True + + + + + + True + True + Update + True + GTK_RELIEF_NORMAL + True + + + + 0 + False + False + + + + + + True + 0/140 + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + False + True + + + + + + True + True + + + 0 + False + False + + + + + + + diff --git a/mytwitter.py b/mytwitter.py index 488b05a..6b3b356 100755 --- a/mytwitter.py +++ b/mytwitter.py @@ -2,16 +2,14 @@ # # Custom twitter client... mostly for learning Python -import sys, twitter, wx, ConfigParser, os, tkMessageBox, datetime, dateutil.tz +import sys, twitter, ConfigParser, os, datetime, dateutil.tz, gtk, gtk.glade, gobject -class TwitWindow(wx.Frame): +class MyTwitter(): """ Display Tweets, post to twitter """ - def __init__(self, parent, title): - wx.Frame.__init__(self, parent, title=title, size=(300,600)) - + def __init__(self): config = ConfigParser.ConfigParser() config.read(os.path.expanduser("~/.mytwitter")) self.username = config.get('global', 'username') @@ -22,101 +20,45 @@ class TwitWindow(wx.Frame): self.labels = [] self.texts = [] + # Authenticate with twitter, set up the API object + self.api = twitter.Api(username=self.username, password=self.password) + + # Load up all the GUI stuff + self.init_user_interface('./default.glade') self.init_widgets() + def init_user_interface(self, path_to_skin): + self.widget_tree=gtk.glade.XML(path_to_skin, "window") + self.widget_tree.signal_autoconnect(self) + + def init_widgets(self): - main_sizer = wx.BoxSizer(wx.VERTICAL) + self.tweet_box = self.widget_tree.get_widget('tweet_box') + self.update_entry = self.widget_tree.get_widget('update_entry') + self.update_count = self.widget_tree.get_widget('update_count') - # Create the scrolled frame that will hold the tweets - tweet_view = wx.ScrolledWindow(self) - tweet_sizer = wx.BoxSizer(wx.VERTICAL) - - # Status bar - self.CreateStatusBar() - - # Menu bar - filemenu = wx.Menu() - filemenu.Append(wx.ID_ABOUT, "&About", "About MyTwitter") - menu_exit = filemenu.Append(wx.ID_EXIT, "E&xit", "Close MyTwitter") - self.Bind(wx.EVT_MENU, self.on_exit, menu_exit) - - menu_bar = wx.MenuBar() - menu_bar.Append(filemenu, "&File") - - self.SetMenuBar(menu_bar) - - # Create labels and text widgets + # Build us some labels... for i in range(0, self.num_entries): - self.labels.append(wx.TextCtrl(tweet_view, style=wx.TE_READONLY)) - self.texts.append(wx.TextCtrl(tweet_view, style=wx.TE_MULTILINE | wx.TE_READONLY)) - self.labels[i].SetDefaultStyle(wx.TextAttr('DARK_BLUE')) - self.texts[i].SetDefaultStyle(wx.TextAttr('LIGHT_BLUE')) - tweet_sizer.Add(self.labels[i]) - tweet_sizer.Add(self.texts[i]) + self.labels.append(gtk.Label()) + self.tweet_box.pack_start(self.labels[i]) + self.labels[i].set_alignment(0.0, 0.0) + self.labels[i].set_selectable(True) + self.labels[i].set_line_wrap(True) + self.texts.append(gtk.Label()) + self.tweet_box.pack_start(self.texts[i]) + self.texts[i].set_alignment(0.0, 0.0) + self.texts[i].set_selectable(True) + self.texts[i].set_line_wrap(True) - # Layout the tweet view widget - width,height=tweet_view.GetSizeTuple() - tweet_view.SetSizerAndFit(tweet_sizer) - tweet_view.SetScrollbars(0, 20, 0, height/20) - tweet_view.SetSize((300,400)) - - # A button to refresh manually - button_sizer = wx.BoxSizer(wx.HORIZONTAL) - refresh_button = wx.Button(self, label="Refresh") - refresh_button.Bind(wx.EVT_BUTTON, self.update_window) + self.tweet_box.show_all() - button_sizer.Add(refresh_button) - - # Create an update box at the bottom of the window - update_sizer = wx.BoxSizer(wx.HORIZONTAL) - - self.update_entry = wx.TextCtrl(self) - self.update_entry.Bind(wx.EVT_TEXT, self.char_counter) - self.update_entry.Bind(wx.EVT_TEXT_ENTER, self.update_status_callback) - - update_button = wx.Button(self, label="Update") - update_button.Bind(wx.EVT_BUTTON, self.update_status) - - self.update_count = wx.StaticText(self, label="0/140") - - update_sizer.Add(self.update_entry, 1, wx.EXPAND) - update_sizer.Add(update_button) - update_sizer.Add(self.update_count) - - ### Set up bindings - - # Bind scrollwheel to move the tweets, as well as page up/down - # fixme: convert this to wxPython - # self.tkroot.bind_all("", self.scroll_wheel) - # self.tkroot.bind_all("", self.scroll_wheel) - # self.tkroot.bind_all("", self.line_up) - # self.tkroot.bind_all("", self.line_down) - # self.tkroot.bind_all("", self.page_up) - # self.tkroot.bind_all("", self.page_down) - - # Pack the top level together - main_sizer.Add(tweet_view, 1, wx.EXPAND) - main_sizer.Add(button_sizer) - main_sizer.Add(update_sizer) - - self.SetSizerAndFit(main_sizer) - - # Init the twitter API - self.api = twitter.Api(username=self.username, password=self.password) - - # Updates! - self.timer = wx.Timer(self) - self.timer.Bind(wx.EVT_TIMER, self.update_window_callback) - self.timer.Start(self.refresh_time * 1000) + # Timer to update periodically self.update_window() - - # end of init_widgets + gobject.timeout_add(self.refresh_time * 100, self.update_window) def update_window(self): - print "DEBUG: update_window()" - timezone = dateutil.tz.gettz() time_format = "%Y.%m.%d %H:%M:%S %Z" @@ -131,33 +73,22 @@ class TwitWindow(wx.Frame): timestring = timestamp.astimezone(timezone).strftime(time_format) labeltext = user.name + " (" + user.screen_name + ") " + timestring - self.labels[i].Clear() - self.labels[i].AppendText(labeltext) + self.labels[i].set_text(labeltext) # Display the text of the tweet - self.texts[i].Clear() - self.texts[i].AppendText(statuses[i].text) - - - def update_window_callback(self, event): - self.update_window() + self.texts[i].set_text(statuses[i].text) def update_status(self): - text = self.update_entry.GetValue() - if len(text) > 140: - d = wx.MessageDialog(self, 'Tweet too long', 'Tweets must be <= 140 characters'); - d.ShowModal() - d.Destroy() - return - self.update_entry.Clear() + text = self.update_entry.get_text() + self.update_entry.set_text(none) self.api.PostUpdate(text) self.update_window() # Just calls update_status, here so that things # that pass an event can be used - def update_status_callback(self, event): + def update_status_callback(self, widget): self.update_status() @@ -186,12 +117,18 @@ class TwitWindow(wx.Frame): # self.tweet_view.yview('scroll', 5, 'units'); - def char_counter(self, event): - new_count = str(len(self.update_entry.GetValue())) + "/140" - self.update_count.SetLabel(new_count) + def char_counter(self, widget): + new_count = str(len(self.update_entry.get_text())) + "/140" + self.update_count.set_label(new_count) + + + def gtk_main_quit(self, widget): + gtk.main_quit() + + + def on_about(self, widget): + print "DEBUG: help->about not yet implemented" - def on_exit(self, event): - self.Close(True) ### end class TwitWindow @@ -218,7 +155,5 @@ def print_formatted(statuses): # main -app = wx.App(False) -root = TwitWindow(None, "MyTwitter") -root.Show(True) -app.MainLoop() +my_twitter = MyTwitter() +gtk.main()