2013年6月2日日曜日

自作Twitterクライアント作成の記録(3)いろいろ実装


さて、現在このような外見をしておりますがパッと見て最初の時よりかなりましな作りになってきてると思います。
このように表示を少し変えたり

設定を変えたりできます。まだかなり少ないですけど・・・・

で、前回からの主な変更点ですが。
・普通のテキストボックスからRichTextBoxに変更し、ハイパーリンクが使えるようになった。
・設定とトークン保存の仕方を少し変更。
・設定ダイアログの作成。
・常に手前に表示できるようにした。
・フォントの変更ができるようになった(ただし、色以外)
・認証情報のリセットができるようにした。
・ツイート可能文字数の表示ができるようにした。
・ツイート状況や、タイムライン取得状況がステータスバーに表示されるようにした。

こんなところかな?
では、待望の?ソースです。

※コメント等は自分の解釈で書いてたりするのでわかりにくかったりするかもです、もし間違ってたりしたらコメントしてくれるとうれしいです。
また、いらなくねこれっていうのも教えてくれるとありがたいです。


まずはForm1から

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LinqToTwitter;
using System.Diagnostics;
using System.Configuration;
using Twitterizer;
using System.IO;using System.Xml;
using System.Net;

namespace じみったー

{
    public partial class Form1 : Form
    {      
//認証情報の初期設定
        private string pincode = "";
        PinAuthorizer auth;

        public string accessToken = "";
        public string accessSecret = "";
        public string consumerKey = "rgSsDf7C2iHd7lipvwuZSQ";
        public string consumerSecret = "JMAcaQ8ThwQ13dn8nnEoRej16IovqYnmUnjHSmFMs";
        OAuthTokenResponse req;
        string pin = "";
        OAuthTokenResponse actToken;
        //TL等の取得に必要なものの準備
        TwitterContext twitterCtx;
        //検索フォームの呼び出し準備
        Search sdb = null;

        public Form1()
        {
            InitializeComponent();
        }

        //Pin_Formから値を受け取る&認証の続き
        public string Pinform
        {
            set
            {
                try

                {
                    pincode = value;
                    pin = pincode;
                    actToken = OAuthUtility.GetAccessToken(consumerKey, consumerSecret, req.Token, pin);
                    auth.OAuthTwitter.OAuthToken = actToken.Token;
                    auth.OAuthTwitter.OAuthTokenSecret = actToken.TokenSecret;
                    twitterCtx = new TwitterContext(auth);
                    SaveInit();
                    MessageBox.Show("認証成功", "じみったー", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "認証失敗", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            get
            {
                return pincode;

            }
        }
      
        //認証のリセット情報の受け取り
        public string pinReset
        {
            set
            {
                string Reset = value;
                if (Reset == "reset")
                TokenResetInit();
            }
        }

        //テキストボックス関連の設定準備
        public RichTextBox RTBox
        {
            get { return TweetRichTextBox; }
        }

        //認証が押された
        private void PinToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (accessToken == "") //アクセストークンが指定されてるか
            {
                auth = new PinAuthorizer();
                auth.Credentials = new InMemoryCredentials
                {
                    ConsumerKey = this.consumerKey,
                    ConsumerSecret = this.consumerSecret
                };
                auth.UseCompression = false;
                req = OAuthUtility.GetRequestToken(consumerKey, consumerSecret, "oob");
                Process.Start(OAuthUtility.BuildAuthorizationUri(req.Token).ToString());
                PIN_Form PinForm = new PIN_Form(this); //Foem1が参照できるように引数はthis
                PinForm.TopMost = this.TopMost; //Form1のTopMostの状態を代入
                PinForm.ShowDialog(); //PinFormを表示               

            }
            else
            {
                MessageBox.Show("すでに認証されてます。", "じみったー", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        //Form1が読み込まれた
        private void Form1_Load(object sender, EventArgs e)
        {
            LoadInit();
            if (accessToken != "") //アクセストークンが指定されてるか
            {
                auth = new PinAuthorizer();
                auth.Credentials = new InMemoryCredentials
                {
                    ConsumerKey = this.consumerKey,
                    ConsumerSecret = this.consumerSecret
                };
                auth.OAuthTwitter.OAuthToken = this.accessToken;
                auth.OAuthTwitter.OAuthTokenSecret = this.accessSecret;
                twitterCtx = new TwitterContext(auth);
            }
            else
            {
                MessageBox.Show("認証情報がありません、認証してください。", "じみったー", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        // 設定値を読み込み
        private void LoadInit()
        {
            this.accessToken = Properties.Settings.Default.accessToken;
            this.accessSecret = Properties.Settings.Default.accessSecret;
            TweetRichTextBox.Font = Properties.Settings.Default.Font;
            this.TopMost = Properties.Settings.Default.TpoMostE;
            if (this.TopMost)
                TopMostToolStripMenuItem.Checked = true;
            TweetRichTextBox.DetectUrls = Properties.Settings.Default.DetectUrls;
        }
        //設定値の書き込み
        private void SaveInit()
        {
            Properties.Settings.Default["accessToken"] = auth.OAuthTwitter.OAuthToken;
            Properties.Settings.Default["accessSecret"] = auth.OAuthTwitter.OAuthTokenSecret;
            Properties.Settings.Default["Font"] = TweetRichTextBox.Font;
            Properties.Settings.Default["TpoMostE"] = this.TopMost;
            Properties.Settings.Default["DetectUrls"] = TweetRichTextBox.DetectUrls;
            Properties.Settings.Default.Save();
        }
        //トークンのリセット
        private void TokenResetInit()
        {
            Properties.Settings.Default["accessToken"] = "";
            Properties.Settings.Default["accessSecret"] = "";
            Properties.Settings.Default.Save();
        }
        //設定のリセット
        private void ResetSetting()
        {

        }
        //TL取得
        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                twittertoolStripStatusLabel1.Text = "タイムライン取得中・・・";
                //TLの取得準備
                var tweets =
                    from tweet in twitterCtx.Status
                    where tweet.Type == StatusType.Home
                    select tweet;
                TweetRichTextBox.Clear();
                //TLの取得
                foreach (var tweet in tweets)

                {
                    TweetRichTextBox.Text += (tweet.User.Name + "\r\n" +
                        tweet.Text + "\r\n\r\n");
                }
                twittertoolStripStatusLabel1.Text = "取得完了!";
            }
            catch (Exception ex) //例外設定
            {
                MessageBox.Show(ex.Message, "じみったー", MessageBoxButtons.OK, MessageBoxIcon.Information);
                twittertoolStripStatusLabel1.Text = "取得エラー";
            }
        }
        //つぶやき入力欄に入力されたか
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            tweetLavelChange();
            if (textBox1.Text != "") //入力欄に何か入力されていれば
            {
                button1.Enabled = true; //ツイートボタンが使用可能に
            }
            else
            {
                button1.Enabled = false; //ツイートボタンが使用不可に
            }
        }
        //ツイートボタンが押された
        private void button1_Click(object sender, EventArgs e)
        {
            twittertoolStripStatusLabel1.Text = "投稿中・・・";
            var tweet = twitterCtx.UpdateStatus(textBox1.Text);
            twittertoolStripStatusLabel1.Text = "投稿完了!";
            textBox1.Clear();
        }
        //文字数のカウント
        private void tweetLavelChange()
        {
            int count,tweet = 120;
            count = textBox1.Text.Length - textBox1.GetLineFromCharIndex(textBox1.Text.Length) * 2; //ボックス内の文字数を取得

            tweet -= count; //残り入力可数の計算
            if (0 > tweet)
            {
                tweet = 0;
            }
            label2.Text = "あと" + tweet + "文字まで"; //ラベルの変更
        }
        //検索が押された
        private void SeachToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (sdb == null || sdb.IsDisposed)
            {
                sdb = new Search(TweetRichTextBox);
                this.AddOwnedForm(sdb);
                sdb.TopMost = this.TopMost;
                sdb.Show();
            }
        }
        //設定が押された

        private void SettingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Setting setting = new Setting(this);
            setting.TopMost = this.TopMost;
            DialogResult dr = setting.ShowDialog();
            if (dr == DialogResult.OK)
            {
                SaveInit();
                setting.SetOption();
            }
        }      
//常に手前表示
        private void TopMostToolStripMenuItem_Click(object sender, EventArgs e)
        {
          
this.TopMost = !this.TopMost;
          
SaveInit();      
}      
//フォント設定
        private void FontToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult dr = fontDialog1.ShowDialog();
            if (dr == DialogResult.OK)
            {
                TweetRichTextBox.Font = fontDialog1.Font;
                SaveInit();
            }        }
        private void TweetRichTextBox_LinkCliked(object sender, LinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start(e.LinkText);
        }
    }

とまあ、例のごとくまるまるです。
お次はSearch(検索フォーム)です。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace じみったー
{
    public partial class Search : Form
    {
        RichTextBox _mainText;
        int searchIndex; //文字列を検索する位置を格納
        public RichTextBox mainText
        {
            get { return _mainText; }
            set { _mainText = value; }
        }

        public Search(RichTextBox text)
        {
            InitializeComponent();
            mainText = text;
            searchIndex = mainText.SelectionStart;
        }
        //検索欄に入力されたかどうか
        private void textChanged(object sender, EventArgs e)
        {
            if (textBox1.Text != "")
                button1.Enabled = true;
            else
                button1.Enabled = false;
        }
        //キャンセルボタンが押された
        private void button2_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        //検索の処理
        private void SearchText(String str)
        {
            if (searchIndex != -1)
            {
                int findTextIndex;
                if (radioButton1.Checked)
                    findTextIndex = mainText.Find(str, 0, searchIndex, RichTextBoxFinds.Reverse);
                else
                    findTextIndex = mainText.Find(str, searchIndex, 0);
                if (findTextIndex == -1)
                {
                    MessageBox.Show("指定したツイートは見つかりませんでした", "じみったー", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
                mainText.Select(findTextIndex, str.Length);
                mainText.ScrollToCaret();

                if (radioButton1.Checked)
                    searchIndex = findTextIndex - 1;
                else
                    searchIndex = findTextIndex = findTextIndex + str.Length;
            }
            else
            {
                MessageBox.Show("指定したツイートは見つかりませんでした", "じみったー", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SearchText(textBox1.Text);
        }

        private void Dialog_activated(object sender, EventArgs e)
        {
            searchIndex = mainText.SelectionStart;
        }
    }
}

そういえば前回検索作ったのにソース張り忘れてましたね。
まあ、あれからかなり変更してるからいっか。
お次はSetting(設定フォーム)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace じみったー
{
    public partial class Setting : Form
    {
        Form1 _mainForm;
        public Form1 mainForm
        {
            get { return _mainForm; }
            set { _mainForm = value; }
        }

        public Setting(Form1 form)
        {
            InitializeComponent();
            mainForm = form;
            OptionInitializeComponent();
        }

        //設定項目を反映
        public void SetOption()
        {
            if (ResetOAthCheckBox.Checked)
            {
                mainForm.pinReset = "reset";
                MessageBox.Show("リセットしました再起動します。","じみったー",MessageBoxButtons.OK,MessageBoxIcon.Information);
                Application.Restart();
            }
            if (UrlCheckBox.Checked)
            {
                mainForm.RTBox.DetectUrls = false;
            }
            else
            {
                mainForm.RTBox.DetectUrls = true;
            }

        }

        //設定項目の初期化
        private void OptionInitializeComponent()
        {
            if (mainForm.RTBox.DetectUrls == false)
            {
                UrlCheckBox.Checked = true;
            }
        }
    }
}

と、今回はこんな感じに変更(わからねーよふつう)

ここで今後の実装予定(目標ともいう)
・@ツイート、DMの送受信を可能にする。
・リツイート、お気に入りの追加、削除を可能にする。
・フォロー、フォロワーの取得、追加。
・ユーザー画像の表示。
・画像つきツイートを可能にする。
・ストリーミングに対応させる。

とまあ、普通のクライアントにはある機能を中心に進めていきます。
あと、このソースSkyDriveにもおいているのでめんどくさいという方はここからどうぞ。

6/20追記:なぜか一行ごとにHTMLタグが入ってたため修正。

2 件のコメント:

  1. 初めまして。私も現在クライアント作成中で拝見させていただきました。

    ところでForm1のソース部分で一行毎に
    <dvi class=~(HTMLタグなので全角にしてます)
    が記述されてますがなんですかねこれ?

    ちなみにChrome・IEで確認してます。

    返信削除
    返信
    1. コメントありがとうございます。

      「<dvi class=~」についてですが、プログラムに全く関係ないです、なぜか勝手に記述されてました。
      なので、該当行をすべて修正してきたのでこれで大丈夫なはずです。

      削除