C# DataGridViewのSelectedRowsをDataTableで取得する

DataGridViewで選択している行を取得する、SelectedRowsはかなりの頻度で利用するのですが、さらにSelectedRowsで取得できる行から、特定の行だけを抽出したい場合。

DataGridView.SelectedRowsをDataTableに変換して取り出す方法

DataTableに変換してから、Selectで抽出するという、とりあえず思いつく方法。

DataTable dt = ((DataTable)dataGridView.DataSource).Clone();
foreach (DataGridViewRow row in dataGridView.SelectedRows)
{
    dt.ImportRow(((DataTable)dataGridView.DataSource).Rows[row.Index]);
}
DataRow[] dr_array = dt.Select("check=true");
DataTable selectedTable = dr_array.CopyToDataTable()

こんな感じで、DataRowの配列として取り出します。

DataTable.Selectではなくて、LinQで取り出すなら

DataRow[] dr_array2 = dt.Rows.Cast<DataRow>().Where(dr => dr["check"].Equals((object)true)).ToArray();
DataTable selectedTable = dr_array.CopyToDataTable()

って感じで。

 

DataGridView.SelectedRows から直接とりだす

DataTableに変換してからではなく、SelectedRowsから直接取り出すには、

DataGridViewRow[] rowList = dataGridView.SelectedRows.Cast<DataGridViewRow>()
                .Where(dr => dr.Cells["check"].Value.Equals((object)true)).ToArray();

とすれば、DataGridViewRowの配列で取り出せます。

比較のところは、Equalsメソッドを使ってますが、こんな風にしてもOK。

DataGridViewRow[] rowList = dataGridView.SelectedRows.Cast<DataGridViewRow>()
                .Where(dr => (bool)dr.Cells["check"].Value == true).ToArray();

PHP 西暦から和暦に変換して年号表示する

PHPで、西暦を和暦に変換するコード。

ただし、
1989年は、1月7日まで昭和64年ですが、平成元年として。
1926年は、12月24日まで大正15年ですが、昭和元年として。
それぞれ変換しています。

    echo $this->getWareki(1989);

    function getWareki($seireki){
        $nengo_year = array('平成' => 1989 , '昭和' => 1926 , '大正' => 1912 , '明治' => 1868 );
        foreach($nengo_year as $nengo => $year){
            if ($seireki >= $year){
                $wareki = $seireki - $year + 1;
                return $nengo . (($wareki==1)?"元":$wareki);
            }
        }
        return "";
    }

 

日時まで正確に算出したければ、次のように、タイムスタンプで。

    echo $this->getWareki2(strtotime("1912-7-30 00:00:00"))."<br>";;
    echo $this->getWareki2(strtotime("1926-12-25 00:00:00"))."<br>";;
    echo $this->getWareki2(strtotime("1912-7-30 00:00:00"))."<br>";;

    function getWareki2($timestamp){
        $nengo_year = array('平成' => 600220800 , '昭和' => -1357603200 , '大正' => -1812153600);
        foreach($nengo_year as $nengo => $ts){
            if ($timestamp >= $ts){
                $wareki = ((date('Y' , $timestamp) - date('Y' , $ts)) + 1) ;
                return $nengo . (($wareki==1)?"元":$wareki);
            }
        }
        return "";
    }

WordPress 投稿画面で[短縮URLを取得]ボタンが消えてしまったときの対処法

消えた「短縮URLを取得」ボタン

あるクライアントさんから、[短縮URLを取得] ボタンが消えてしまった!昨日まであったのに。。
と連絡が。

調べてみると、理由は簡単で、WordPressのバージョンを4.3から4.5に更新したから。

実際のところは、WordPress 4.4 から、タイトル下の[短縮URLを取得]ボタンと、[投稿を表示]ボタンがなくなってしまったのですが、そうと知らなければびっくりしますよね。

で、どうやって解決するかというと、テーマのfunction.phpあたりに以下を入れます。(PHPのバージョンが5.2以下の場合は、これを入れるとエラーで止まりますので注意!追記参照)

//PHP5.3 以上の場合
add_filter('get_shortlink', function($shortlink){return $shortlink;});

これだけで、[短縮URLを取得]ボタン が表示されるようになります。

※追記 2016/07/13
ただし、PHPのversionが5.2以下の場合は無名関数(関数名を省力)が使えないので、500エラーでサイトも管理画面も表示されなくなってしまいます。
そうなったら、FTPクライアントソフトから直接function.phpを編集して追加した上記を消すしかないので焦ります。
なので、PHP5.2以下か、PHPのバージョンが不明、あるいは「何言ってるのかわかんない」の場合は以下をfunction.phpに入れます。

//PHP5.2 以下の場合
function show_button_shortlink ($shortlink) {
	return $shortlink;
}
add_filter('get_shortlink', 'show_button_shortlink');

 

 

ちなみに、WordPress 4.3以前で、[短縮URLを取得]ボタンを非表示にしたい!という逆の願いをかなえるには、

add_filter('get_shortlink', '__return_false');

とすればいいそうです。

 

あと、[投稿を表示]ボタンについては、どうやって表示させるかわかりませんでしたが、まぁこれは管理画面上の黒い管理バーにあるので、いらないっちゃいらないですね。

WP Fastest Cache ログイン中の管理バーが表示されなくなった

 

WordPressで管理画面にログイン中であれば、フロント側を表示しても画面の上側に、黒い帯の管理バーが表示されます。

ところが、WP Fastest Cache を導入後に管理バーが表示されなくなる。という問題が発生。
で、調べてみたら簡単なことでした。

ログインユーザーに対してキャッシュを表示しない

WP Fastest Cache の設定で、「ログインユーザーに対してキャッシュを表示しない」のチェックが外れていました。ここにチェックがついていなかったので、訪問者が見る、ログオフ時のフロント側のキャッシュが表示される→管理バーが出てこない。

ということでした。
よく確認せずに、設定しなかったのが間違いでした。

ちなみに、「モバイルユーザーに対してキャッシュを表示しない」というのは、チェックをつけると当然モバイル端末で閲覧した人には、キャッシュの恩恵は受けられません。
で、なんでわざわざこんな設定があるのかというと、たとえば、wp_is_mobile関数などで、モバイル用に表示を分けて出力している場合。

具体的にはこんなかんじで→WordPressのレスポンシブデザインでPC表示を選択できるようにする

すると、キャッシュのせいでPC用の画面がうまく表示されない場合があるので、そんなときには「モバイルユーザーに対してキャッシュを表示しない」にチェックをつけると。

逆に、完全にJavaScriptとCSSのみでレスポンシブ対応しているのなら、ここのチェックは外しておいたほうがいいということになります。

 

WordPressのカスタムタクソノミーで絞り込み

投稿一覧(category.phpやtaxnomy.php)で、カスタムタクソノミーで絞り込み表示できるようにします。

まずは、絞り込みのための一覧を表示します。
get_terms()で、カスタムタクソノミーの一覧を取得できます。

たとえば、get_terms('howto_category','orderby=slug') とすれば、howto_categoryというカスタムタクソノミーをslug順で並べて取得できます。

<?php $mycats = get_terms('howto_category','orderby=slug'); ?>
<?php if(count($mycats)>0) : ?>
	<div class="howto_cat">
		<p>クリックすると絞り込みます。</p>
		<?php foreach($mycats as $mycat): ?>
		<?php if (($myca -> count) >0): ?>
			<a href="<?php echo $thisPageURL.'?howto_cat='.$mycat -> slug; ?>">
			<?php echo esc_html($mycat -> name); ?></a>
		<?php endif; ?>
		<?php endforeach; ?>
	</div>
<?php endif; ?>

で、URLにGETパラメータをつけておいて、そのリンクをクリックすると、そのパラメータで絞り込み。

get_query_var('paged')で、現在のページを取得して、query_postsで取得。

<?php if (isset($_GET['howto_cat'])) :
	$paged = get_query_var('paged');
	$query_str = 'post_type=post&paged=' . $paged;>
	$query_str .= '&howto_category=' . htmlentities($_GET['howto_cat'], ENT_QUOTES, "utf-8");
	query_posts($query_str);
endif; ?>

 

だがしかし。ほんとうは、pre_get_posts でやるべきところですので、function.phpあたりに、以下を。(pre_get_posts使うのなら、上記のコードquery_posts()はいりません。)

function my_posts_per_page($query) {
	if( is_admin() || ! $query->is_main_query() ){
		return;
	}

	if ( $query->is_category('howto') ) {
		if (isset($_GET['howto_cat'])) {
		$howto_cat = htmlentities($_GET['howto_cat'], ENT_QUOTES, "utf-8");
		$taxquery = array(
			array(
				'taxonomy' => 'howto_category',
				'field' => 'slug',
				'terms' => array( $howto_cat )
				)
			);
			$query->set( 'tax_query' , $taxquery );
		}
		return;
	}
}
add_action( 'pre_get_posts', 'my_posts_per_page' );

以上

 

パーマリンクを設定していなくてもできるWordPressの高速化

WordPressの高速化で有効なキャッシュ系プラグインもいろいろあります。

おすすめなキャッシュ系プラグイン

WP Fastest Cache がおすすめですね。
設定が簡単で、しっかり効果もでるし、それに設定画面を日本語化できるところもいいです。
WP Fastest Cache の設定で日本語化できます。
大抵の場合、上記のように全部にチェックをつけて、言語に「日本語」をえらんで[設定を保存]をクリックすればOK。
(設定に関しては、こちらが参考になりました→http://nendeb.com/415

でも、パーマリンクを設定していない場合は、このプラグインは使えません。

You have to set permalinks
とエラーになります。

パーマリンクを設定できるのならいいのですが、どうしてもパーマリンク設定したくない場合は仕方がないので、手動で対応していくことになります。

パーマリンク設定していない場合の高速化

.htaccessに次の二つを書き込みます。
まずは、ファイルのGZIP圧縮。(参考になりました→http://oxynotes.com/?p=6519

<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|ico)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI _\.utxt$ no-gzip
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE font/opentype font/ttf font/eot font/otf
</IfModule>

 

それから、ブラウザのキャッシュ設定。これも効果的。

<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 2 weeks"
ExpiresByType image/gif "access plus 1 weeks"
ExpiresByType image/png "access plus 1 weeks"
ExpiresByType image/jpg "access plus 1 weeks"
ExpiresByType image/jpeg "access plus 1 weeks"
ExpiresByType text/html "access plus 1 seconds"
ExpiresByType text/css "access plus 2 weeks"
ExpiresByType text/javascript "access plus 2 weekss"
ExpiresByType application/x-javascript "access plus 2 weeks"
ExpiresByType font/opentype "access plus 2 weeks"
ExpiresByType font/ttf "access plus 2 weeks"
ExpiresByType font/eot "access plus 2 weeks"
ExpiresByType font/otf "access plus 2 weeks"
</IfModule>

ウェブサーバーが対応していれば、これらを.htaccessに入れておくだけで、とっても効果的。

その他、.htaccessでやることは、こちらが参考になります。→ http://urashita.com/archives/671

その他のプラグイン

001 Prime Strategy Translate Accelerator

 WordPressでは、英語を日本語に翻訳しながら表示しているのですが、その翻訳をキャッシュしてくれるようです。

a3 Lazy Load

 画像を遅延読み込み(画面上に表示されていない画像はあとで読み込む)することで、ページの表示を高速化してくれます。

EWWW Image Optimizer

 投稿時に画像を最適化してくれます。

他にも、データベースキャッシュ系のプラグインも試したのですが、いまいち効果がなかったので割愛しました。

MapPress Easy Google Maps が表示されないときの対処法

WordPressでお世話になるプラグイン、トップ5に間違いなく入るであろう、MapPress Easy Google Maps ですが、いざマップを挿入してみると、地図の枠が真っ白で、なにも表示されない、ということがあります。

MappPressの地図が表示されない

こんな感じ。

で、GoogleマップそのものはJavaScriptで呼び出してるので、きっとその読み込みあたりで問題なんだろうな。とMappPressの設定を見てみると、「Script」という項目があって、「Output scripts in footer」にチェックが入っていたので、そのチェックを外してみたところ。。。

Output scripts in footer

ばっちり表示されます。
MappPress 表示されるようになる。

Output scripts in footer にチェックが入っていると、foot部分にMapPressのスクリプトを呼び出すコードが入るようになっていたのですが、チェックを外すことで、head部分にコードが入るようになるというわけです。
すると、スクリプトを呼び出す順番が、マップ部分よりも先になるとか、ほかのスクリプトより先になるとかで、挙動がかわると。

MapPressがうまく表示されないようなら、まずお試しを。

で、これでだめなら、いったん他のテーマ(WordPressにデフォルトで入っているテーマ)や、MappPress以外のプラグインを一つずつ停止させて、マップが表示されるかどうか試していけば、原因となっているプラグインがわかるので、別のプラグインに入れ替えるとかすることになります。

 

C# 二値化した画像をGraphicsで扱えるようにする

C# 二値化した画像をGraphicsで扱えるようにする」で二値化した画像に、赤枠をつけたりしたいと思って、Graphicsで処理しようとすると、「グラフィック オブジェクトをインデックス付きピクセル形式を持つイメージから作成できません」と怒られます。

        void test()
        {

            //元の画像を読込
            OpenCvSharp.IplImage img = new OpenCvSharp.IplImage("test.jpg");

            //二値化画像を保存するIplImageの準備
            OpenCvSharp.IplImage bin_iplImg = new OpenCvSharp.IplImage(img.Width, img.Height, BitDepth.U8, 1);

            //閾値
            int threshould = 180;

            //グレースケールに変換
            img.CvtColor(bin_iplImg, OpenCvSharp.ColorConversion.BgrToGray);
            //二値化処理
            OpenCvSharp.Cv.Threshold(bin_iplImg, bin_iplImg, threshould, 255, OpenCvSharp.ThresholdType.Binary);

            //Bitmapを取得
            Bitmap bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(img);

            //ここで、「グラフィック オブジェクトをインデックス付きピクセル形式を持つイメージから作成できません」と怒られる
            Graphics g = Graphics.FromImage(bmp);

            //赤線で囲む
            Pen pen = new Pen(Color.FromArgb(150, Color.Red), 10);
            g.DrawRectangle(pen, 0, 0, bmp.Width, bmp.Height);

            g.Dispose();
            pen.Dispose();
            pictureBox_scanData.Image = bmp;
        }

どうやら、二値化した画像は、Format1bppIndexedなのでダメということのようで。
https://msdn.microsoft.com/ja-jp/library/system.drawing.graphics.fromimage(v=vs.110).aspx

じゃ、どうするか考えたのですが、GetThumbnailImageを使えば、さくっと解決できます。

        void test()
        {
            //元の画像を読込
            OpenCvSharp.IplImage img = new OpenCvSharp.IplImage("test.jpg");

            //二値化画像を保存するIplImageの準備
            OpenCvSharp.IplImage bin_iplImg = new OpenCvSharp.IplImage(img.Width, img.Height, BitDepth.U8, 1);

            //閾値
            int threshould = 180;

            //グレースケールに変換
            img.CvtColor(bin_iplImg, OpenCvSharp.ColorConversion.BgrToGray);
            //二値化処理
            OpenCvSharp.Cv.Threshold(bin_iplImg, bin_iplImg, threshould, 255, OpenCvSharp.ThresholdType.Binary);

            //Bitmapを取得
            Bitmap bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(img);

            //GetThumbnailImageを利用して変換
            Image image = bmp.GetThumbnailImage(bmp.Width, bmp.Height, new Image.GetThumbnailImageAbort(dummy), IntPtr.Zero);

            //GetThumbnailImageをつかって変換しておけば大丈夫
            Graphics g = Graphics.FromImage(image);

            //赤線で囲む
            Pen pen = new Pen(Color.FromArgb(150, Color.Red), 10);
            g.DrawRectangle(pen, 0, 0, bmp.Width, bmp.Height);

            g.Dispose();
            pen.Dispose();
            pictureBox_scanData.Image = bmp;
        }

 

OpenCvSharp でRGB要素別々で二値化する

OpenCvSharpで、画像を二値化する方法はグレースケールしてから、Cv.Thresholdで二値化します。

        //using OpenCvSharp;
        private IplImage getBinImage()
        {
            //元の画像を読込
            IplImage img = new IplImage("test.jpg");

            //二値化画像を保存するIplImageの準備
            IplImage bin_iplImg = new IplImage(img.Width, img.Height, BitDepth.U8, 1);

            //閾値
            int threshould = 180;

            //グレースケールに変換
            img.CvtColor(bin_iplImg, ColorConversion.BgrToGray);
            //二値化処理
            Cv.Threshold(bin_iplImg, bin_iplImg, threshould, 255, ThresholdType.Binary);
            return bin_iplImg;
        }

 

でも、RGB各要素で閾値を変えたい場合、たとえば、緑成分の多い画像を処理したい時などには次のようにします。

        
        //using OpenCvSharp;
        IplImage getBinImage2()
        {
            //元の画像を読込
            IplImage img = new IplImage("test.jpg");

            //二値化画像を保存するIplImageの準備
            IplImage bin_iplImg = Cv.CreateImage(img.Size, BitDepth.U8, 1);

            //RGB要素のIplImageの準備
            IplImage r_iplImg = Cv.CreateImage(img.Size, BitDepth.U8, 1);
            IplImage g_iplImg = Cv.CreateImage(img.Size, BitDepth.U8, 1);
            IplImage b_iplImg = Cv.CreateImage(img.Size, BitDepth.U8, 1);

            //元画像をRGBに分解
            Cv.Split(img, b_iplImg, g_iplImg, r_iplImg, null);

            //RGB各要素の閾値
            int r_threshold = 180;
            int g_threshold = 230;
            int b_threshold = 150;

            // 各RGB要素で閾値以下のピクセルを抽出する
            Cv.Threshold(r_iplImg, r_iplImg, r_threshold, 255, ThresholdType.BinaryInv); 
            Cv.Threshold(g_iplImg, g_iplImg, g_threshold, 255, ThresholdType.BinaryInv); 
            Cv.Threshold(b_iplImg, b_iplImg, b_threshold, 255, ThresholdType.BinaryInv); 

            // ORでRGB要素を合算
            Cv.Or(b_iplImg, g_iplImg, bin_iplImg, null);
            Cv.Or(bin_iplImg, r_iplImg, bin_iplImg, null);

            return bin_iplImg;
        }

Analytics で直帰率が0%

Analyticsで、なぜかこのブログの直帰率が脅威の0%という、とんでもな数値になっていていました。
まぁ、メモ+実験ブログなので、直帰率なんて気にしてないのですが、なんでだろうと。

直帰率0%

で、調べてみてわかったのですが、結論から言うと、Analyticsのコードが2つはいっていたからでした。
Analyticsコードの重複

というのも、Analyticsを設定した時に、header.phpに直接コードを書き込んだのですが、それとは別に、
Google Analytics Dashboard for WP というプラグインをあとから入れていました。

このプラグインを使うと、WordPressのダッシュボードに簡単なアクセス解析結果を表示してくれるので、重宝するのですが、Google Analytics Dashboard for WP を導入すると自動的にアナリティクスのコードを入れてくれるようでして、それに気が付かずに使っていたということでした。

というわけで、header.phpから、Analyticsのコードを消すと、直帰率が表示されるようになりました。

1604260003

なかなかの高レイト。
まぁ、そうなるよね。