hiroshi akutsuの日記

主にプログラミング関係のこと

Excel vba 【特定のシートを表示したときだけオートコンプリートをonにする】

いつも邪魔くさいオートコンプリートは結構offにしている人が多いと思うけど、あるシートだけはonにしたいってケースがあったのでメモ。

オートコンプリートをonにしたいシートにWorksheet_ActivateイベントとWorksheet_Deactivateイベントを使い、Application.EnableAutoCompleteの値を切り替える。

準備として宣言セクションに元のオートコンプリートの設定値を保存する。
モジュールレベルのグローバル領域に変数acを記述し、acにシートを表示する前の設定値を保存しておき、シートが表示されなくなったらEnableAutoCompleteの設定をacに戻す。

こんな感じ。。。

Option Explicit
Private ac As Boolean

Private Sub Worksheet_Activate()
    ac = Application.EnableAutoComplete
    Application.EnableAutoComplete = True
End Sub

Private Sub Worksheet_Deactivate()
    Application.EnableAutoComplete = ac
End Sub


こうすることでサブルーチンやイベントをまたいでも変数を保持していられ、元の設定値を変えないままオートコンプリートをonにできる。

Excel vba【specialcells(xlcelltypeconstants)で定数セルが1つもない場合はエラーになる場合】

たとえばエクセルのマクロで

Dim ra As Range
Set ra = Selection.SpecialCells(xlCellTypeConstants)

でselectionに何か値が入っているセルがないとエラーになる。

こういうのが面倒というか、vbaの振る舞いが予想しづらいところで、非常に煩わしく感じる。

とりあえずおこられてしまったので、

Dim ra As Range
Set ra = Selection
If Apprication.WorksheetFunction.CountA(ra) Then
  Set ra = ra.SpecialCells(xlCellTypeConstansts)
End If

とした。
ワークシート関数のcounta関数を使って判定。
counta関数はご存じのとおり、引数にセル範囲を渡してやると文字や数値が入力されたセルの個数を返してくれる。

if文の条件式に0以外の数値が渡るとtrueと扱われる。

ネットで調べたら、on error gotoで別処理させる例がよく載っていたが数百行に及ぶモジュールになってくるとスパゲッティ化するのであれだけは新人に真似してほしくない。
on error gotoを使うならせめてユーザー定義関数とかで最小の影響範囲に抑える工夫が必要だ。

ただし、ベンチマークをとっていないので、specialcells(xlcelltypeconstants)の全部をこうしたらいいという保証はできない。countaもだいぶ高速だと思うが。

jquery-ui【tooltipで表示されるhtmlのコンテンツをajaxで取得して表示】

jquery-uiのtooltipは非常に簡単にツールチップを実装できるツールとして知られている。

たとえば、
jqueryのjsファイル、
jquery-uiのjsファイル、
jquery-uiのcssファイルを読み込んだ状態で、

$(function(){
  $(document).tooltip();
})

とするとtitle属性に指定された文字がツールチップとして表示される。

htmlを表示したい場合は

$(function(){
  $(document).tooltip({
    items   : "[class]",
    content : "<div class=\"tooltip-content\">HTML表示</div>"
  });
});

とかってやるとhtmlが記述できる。

ではajaxで取得したhtmlをcontentに設定するには?
単純に以下のようにやってもだめ。

$(function(){
  $(document).tooltip({
    items   : "[class]",
    content : function(){
      return ajaxFunc();
    }
  });
});
function ajaxFunc(){
  var ret = "";
  $.post(
    "Ajax.php?class_name=hoge",
    {},
    function(d, dt){
      ret = d;//関数の戻り値を設定(しようとしている)
    },
    "html"
  );
  return ret;
}

最初はみんなやります。この間違い。
当たり前だけど、$.post()は非同期なので下の関数のretの変数にはサーバーからの返答がを待たずして、
return ret;
が先に実行されてしまうので期待通りの動作になりません。
かといって$.ajax()のasyncオプションをfalseにして同期通信でとってくるという方法もださい。ツールチップはその滑らかさが売りなのに画面がいちいちとまってしまうことになる。

$.Defferedとかも考えたけど、Defferedオブジェクトは非同期処理の実行順序を保証してくれるだけで、レスポンス結果が取得されるのを待ってreturnするとかはできない(と思うがうまく使えばできるのかな)。
何とか非同期でとってこようとしたらいろいろ方法は考えられるがStack Overflowにあった回答を参考にやったのは次の方法。openのオプションで取ってくる。

$(function(){
  $(document).tooltip({
    items   : "[class]",
    content : "now loading...",
    open    : function(){
      ajaxFunc($(this));
    }
  });
});

function ajaxFunc($oj){
  var ret = "";
  $.post(
    "Ajax.php?class_name=hoge",
    {},
    function(d, dt){
      $oj.tooltip("option", "content", d);//ここで取得した内容を設定
    },
    "html"
  );
  return ret;
}

これできちんとajaxの内容を表示できた。

css【Internet Explorer10でcssで設定したborderが印刷プレビューで表示されない不具合】

以下のhtml(本当はもっと複雑なことをしようとしたんだけど、バグを特定するため、不要な設定を削除していった結果以下のようになりました)をブラウザに表示させてみたところ……

<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<style type="text/css">
	div{
		width:900px;
	}
	table{
		border:solid 3px black;
		border-collapse:collapse;
		width:100%;
	}
	
	table th{
		background-color:#ccc;
		border:solid 1px black;
	}
	
	table td{
		border:solid 1px black;
	}
</style>
</head>
<body>
	<div>
		<table>
			<thead>
				<tr>
					<th class="col1">th1</th>
					<th class="col2">th2</th>
					<th class="col3">th3</th>
					<th class="col4">th4</th>
					<th class="col5">th5</th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td colspan="5">
						td1
					</td>
				</tr>
			</tbody>
		</table>
	</div>
</body>
</html>

普通のhtml5で表示したテーブル。
ie10で表示すると
f:id:hakoniwahaniwa:20131227151516p:plain
のようになります。

cssでは設定しているにもかかわらずth2~th5までのセルのborder-bottomが消えてしまっています。

さらに印刷プレビューを表示すると、
f:id:hakoniwahaniwa:20131227153209p:plain
となり、td1の左右のborderが消えてしまいます。

この現象はie10で確認しています。

いろいろ試した結果、th2~th5までのセルのborder-bottomが消えてしまったのはjqueryを読み込まなければ解消されるということが確認できました。

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

の記述を削除したら、
f:id:hakoniwahaniwa:20131227153641p:plain
のように表示されました。
jquery、ieのどちらのバグか定かではないですが。

しかし、印刷プレビューのほうはjqueryを消しても直りませんでした。

調べてみると結局のところborder-collapse:collapseが一番の元凶のようでした。

これはあきらめてborder-collapse:separateを使うほうが無難のよう。
ちょっと設定は面倒になるが、border-collapse:collapseの印刷時のバグが解決されない以上、

	table{
		border:solid 3px black;
		border-collapse:separate;
		border-spacing:0px;
		width:100%;
	}

として、擬似的にcollapseを実装するしかないか。

mysql【Can't connect to local MySQL server through socketでエラーした】

昨日何気なくテスト環境のゲストOSのshutdownコマンドをサボってvirtualboxのウィンドウの×ボタンで閉じようとしたのだけど、どうも正常にshutdownされなかった。

1晩経っても停止中のステータスから変わらないので仕方ないからホスト側windowsのタスクマネージャーから強制的に終了。

virtualboxのステータスが中止に変わり、いざ起動をかけてみると、どうもmysqlphpから接続できない模様。

Can't connect to local MySQL server through socketとブラウザに表示された。

ゲストOSの環境は
centOS : 6.5
mysql server version : 5.1.71
(・php5.3.3)

調査開始。

#vi /var/log/mysqld.log

で見てみると、最後のログが、昨日のstartの記録だった。昨日stopした記録や、chkconfigで自動で立ち上がるようにしているはずだが、今日startした記録がない。確実に正常にシャットダウンできなかったことが原因みたいだ。

#/etc/init.d/mysqld start

でmysqldを立ち上げようとするも失敗
mysqlが使用するはずの「3306ポートはすでに使用されている」みたいなアラートが出た。

#/etc/init.d/mysqld stop
は成功した。

でもこの後、
#/etc/init.d/mysqld start
をすると先ほどと同じようなメッセージがでる。

もう一回
#/etc/init.d/mysqld stop
をしてみると、さっきストップしてその後スタートに成功していないはずだから失敗するのかと思いきや成功した。

う~ん。何でだ。

#netstat -tanp

で検索してみてmysqlが起動していないことを確認。

いったん再起動してみよう。
#shutdown -r now

shutdown中に普通なら
httpdをstopしているよー OK
mysqldをstopしているよー OK

みたいなコンソールが表示されるはずだけど、この再起動では「mysqldをstopしているよー」は表示されなかった(ように思う。すみません、不確か)。

そんで起動されたから直ったかなと思って、もう一度phpからmysqlを呼んでみたけど、現象は解消されず。。。

んで、ぐぐって見て、結構同様の問題で悩んでいる人がいるみたい。
どうも/var/lib/mysqlにあるmysql.sockが悪さしているようだということがわかり、また、このファイルの作成日時が
#ls --full-time /var/lib/mysql
で表示してみると昨日のmysqlの起動時間になっていて、かつ空ファイルということがわかり、どうもmysql.sockはmysqld起動時に自動作成をするファイルのようなので念のためスナップショットを撮って削除した。

そして、
#/etc/init.d/mysqld start

すると見事に成功。
無事mysqlの起動ができました。

細かいところまで原因を正確に突き止められなかったけど、テスト環境だし、開発も追われているので今回の調査はこれでひとまず終了。

flash【safariだけcssのoverflow:hiddenが適用されない場合の解決方法】

他のブラウザではちゃんとflashがoverflowで表示されるのに、safariだけoverflowがまったく効かなかった。

何がしたかったのかというと、flashのステージの大きさを動的に読み込むflvの大きさに合わせてactionscriptで小さくできたらいいんだけど(flvは複数あってかつ大きさは不定、ただしステージの大きさを超えることはない)、それがどうも難しそうなので、overflowで見える範囲を小さくすることにした。
IEおっけー、FFおっけー、くろーむおっけー、さふぁりおっ、おおっっ!なんだこのひどいレイアウトは!

どんな見た目になっていたかというとoverflowでhiddenにしたはずの領域がもろ前面に出てきている。
おかげでその下のhtmlが隠れてしまって、クリックできない。


原因をいろいろ調べたのだけど、海外のサイトだとz-index指定やらiframeを使えやら、overflowのdivにposition:relativeにしろやら、いろいろ書いてあったけどiframe以外全部試したけどだめだった。


藁にもすがる思いで日本語のサイトに絞って調べてみたらジャストな方法が見つかったのでtips。

環境はwindows 7 professional 64bit OS
safari5.1.7(7534.57.2)

htmlは肝心なとこ以外省略しています。


ごくごく普通のflashの表示方法。
ただし、
param name="wmode" value="opaque"

wmode="opaque"
が非常に重要。

<div class="container">

  <div class="wrapper">

    <object class="mov">

      <param name="movie" value="…">
      <param name="wmode" value="opaque">

      <embed class="mov" src="…" wmode="opaque">

    </object>

  </div>

</div>

そして

div.container {
  width: 660px;
  height: 380px;
  margin: auto;
  overflow: hidden;
  position: relative;
}

div.wrapper {
  width: 760px;
  height: 600px;
  position: absolute;
  top: -110px;
  left: -50px;
}

.mov {
  width: 100%;
  height: 100%;
}

これでばっちり表示できました。

safariで表示するflashはこのwmodeをopaqueにしないと、z-indexを無視して最前面に強制的に表示されるらしい。

このパラメータはわからなかった。。。

jQuery-ui【datepickerに今日の日付の初期値を設定する】

忘れやすいのでメモ。
datepickerは非常に便利な日付選択可能なUIなんですが、ページのロード時にあらかじめ今日の日付がセットされていてほしいことがある。

そんなときは……

$(':text').datepicker().datepicker('setDate','today');

とする。
面倒なんだけどdatepicker()をチェーンで2回呼び出しているのはsetDateはオプションではなくメソッドであるから、初期化が必要なんだとか。

$(':text').datepicker();
$(':text').datepicker('setDate', new Date());

としても可のようだ。
setDateメソッドには、stringとオブジェクトの両方を渡せる。