[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『更新履歴の追加』(狭山)
お世話になります。
また、よろしくお願いいたします。
作業の更新履歴を付けるマクロを使用しています。
(ネット上から検索しました)
式は以下の通りです。
ThisWorkBookモジュールへ
Private Sub Workbook_Open()
flg = False
For i = 1 To ActiveWorkbook.Sheets.Count
If Sheets(i).Name = "更新履歴" Then
flg = True
Exit For
End If
Next
If flg = False Then
Sheets.Add after:=Sheets(Sheets.Count)
ActiveSheet.Name = "更新履歴"
With Sheets("更新履歴")
.Range("A1") = "シート名"
.Range("B1") = "変更セル"
.Range("C1") = "値"
.Range("D1") = "年月日 時 刻 "
.Range("E1") = "ユーザー名"
End With
End If
Sheets("更新履歴").Visible = False
Sheets(1).Select
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Sh.Name = "更新履歴" Then Exit Sub
With Sheets("更新履歴")
.Rows(2).Insert Shift:=xlDown
.Range("A2").Value = Sh.Name
.Range("B2").Value = Target.Address
.Range("C2").Value = Target.Value
.Range("D2").Value = Now()
.Range("E2").Value = Application.UserName
.Columns("A:E").EntireColumn.AutoFit
End With
End Sub
現在は
Range("A1") = "シート名"
.Range("B1") = "変更セル"
.Range("C1") = "値"
.Range("D1") = "年月日 時 刻 "
.Range("E1") = "ユーザー名"
のみなのですが追加で以下の作業を表示する事ができますでしょうか。
セルの内容をDeleteとで消した場合にF列に【削除】表示
行若しくは列を削除した場合G列に【削除】表示
入力してあるセル内のデータが他のセルに移動があった場合H列に【○○〜○○へ移動】表示
以上なのですがご教授お願いいたします。
< 使用 Excel:Excel2010、使用 OS:Windows7 >
申し訳ございません。 もう1つ忘れてしまいました。 保存を行った場合、I列に【保存】を表示 以上の F〜Iの追加です。 よろしくお願い致します。
(狭山) 2016/09/17(土) 12:04
(γ) 2016/09/17(土) 12:18
(γ) 2016/09/17(土) 12:45
ありがとうございます。 よろしく頼む、じゃなく、自分で調べてからにしてください ですが、自分なりに調べているつもりですが 言葉悪く失礼しました。 結果ですが (1)は 現状の空白で見極めます。 (2)は、シートの保護にて行い削除等はさせない。 (3)は、ちょっと難しそうですので行いません。 これで行ってみたいと思います。
(狭山) 2016/09/17(土) 15:50
調べながら少し変更してみました。 Private Sub Workbook_Open() flg = False For i = 1 To ActiveWorkbook.Sheets.Count If Sheets(i).Name = "更新履歴" Then flg = True Exit For End If Next If flg = False Then Sheets.Add after:=Sheets(Sheets.Count) ActiveSheet.Name = "更新履歴" With Sheets("更新履歴") .Range("A1") = "シート名" .Range("B1") = "変更セル" .Range("C1") = "値" .Range("D1") = "年月日 時 刻 " .Range("E1") = "ユーザー名" .Range("F1") = "保存ユーザー名" End With End If Sheets("更新履歴").Visible = False Sheets(1).Select End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Sh.Name = "更新履歴" Then Exit Sub
With Sheets("更新履歴")
.Rows(2).Insert Shift:=xlDown
.Range("A2").Value = Sh.Name
.Range("B2").Value = Target.Address
.Range("C2").Value = Target.Value
.Range("D2").Value = Now()
.Range("E2").Value = Application.UserName
.Range("F2").Value = CreateObject("WScript.Network").UserName
.Columns("A:F").EntireColumn.AutoFit
End With
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
With Sheets("更新履歴")
.Rows(2).Insert Shift:=xlDown
.Range("G2").Value = ""
.Range("H2").Value = ""
.Range("I2").Value = "上書き保存"
.Range("J2").Value = Now()
.Range("K2").Value = Application.UserName
.Columns("G:K").EntireColumn.AutoFit
End With
End Sub
ただ.Range("C1") = "値"の部分がDeleteした場合削除表示ができませんでしたが 空白で消去と判定すれば良いかと思いましてそのままです。 また、(2)の、変更セルの大きさで判定も調べましたが分からなかったため 前項のシートの保護にて対応しようかと思っております。
(狭山) 2016/09/17(土) 22:06
二点だけコメントします。
(1)インデントをしっかり付けて下さい。
参照したところが悪いのか知りませんが、その点では零点です。 こうした悪習は即刻やめてください。 他人に見せるから、ではありません。 ご自分がコードを書いたり、デバッグするのに、効率が悪いからです。 重いハンディを背負って歩くようなものです。
(2)参照したコードの問題かと思いますが、 Changeイベントプロシージャの中で、セルの値を変更すると、 それがまたChangeイベントプロシージャを引き起こします。 冒頭の一行で直ぐ抜けるので実害は無いとは言え、無駄は無駄です。 イベントの連鎖を防ぐためには、以下のようにするとよいでしょう。 トータルの効率の問題より、こういう場合の作法として記憶された ほうが良いでしょう。
If Sh.Name = "更新履歴" Then Exit Sub Application.EnableEvents = False '■追加 With Sheets("更新履歴") .Rows(2).Insert Shift:=xlDown .Range("A2").Value = Sh.Name .Range("B2").Value = Target.Address '以下、数行を省略しました。 End With Application.EnableEvents = True '■追加
(γ) 2016/09/17(土) 23:12
(γ)さんのおっしゃるとおりです。 いろいろと調べてまして今回の件で、10の内1くらいは自分の益になりました。(自分の理解度で低いですが) エクセルを初めて2年くらいでマクロなんて早いのは分かっているのですが
FalseとTrueの件ですが プロシージャの中で、無限ループに近い形になっているのを止める対策 逆にTrueで戻してあげないとプロシージャはうんともすんともいわなくなるという事なんですね。 勉強になりました。(まだまだ理解度が低いですが)
↓完成 Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) If Sh.Name = "更新履歴" Then Exit Sub Application.EnableEvents = False '■追加 With Sheets("更新履歴") .Rows(2).Insert Shift:=xlDown .Range("A2").Value = Sh.Name .Range("B2").Value = Target.Address .Range("C2").Value = Target.Value .Range("D2").Value = Now() .Range("E2").Value = Application.UserName .Range("F2").Value = CreateObject("WScript.Network").UserName .Columns("A:F").EntireColumn.AutoFit End With Application.EnableEvents = True '■追加 End Sub
使用して問題が出てしまい最後にご教授いしいただきたい事がでてしまいまして。 G列にB列C列を検索して「問題あり」「正常」を判断するものも追加したいのですが マクロでは出来なくて・・ご指導下さい。 条件付きの数式は何とか出来たのですが、今回の”更新履歴”シートは 上から下へ記録されるのではなく、新記録が常に2列目以下に記載となり 数式を入れていても新規の履歴の場合式を毎回入れなおさないと駄目で 式は G2=IF(AND(B2<>"",C2<>""),"正常","問題あり") を入れています。
G列の条件は B列とC列に何かの文字が入っていた場合は G列「正常」 B列に文字ありC列が空白の場合 G列「問題あり」 B列とC列が共に空白の場合 G列「正常」 です。 ご教授お願い致します。
(狭山) 2016/09/18(日) 10:26
(γ) 2016/09/18(日) 11:31
ありがとうございます。 投稿等を検索したのですが分かりませんでした。 更新履歴のシートで G2=IF(AND(B2<>"",C2<>""),"正常","問題あり")をコピーしながら行います。 また、 B列とC列が共に空白の場合 G列「正常」、とはならないんじゃないかな。 ですが、空白の場合はコピーはしない事で対応したいと思います。 (γ)さん 何度もご指導ありがとうございました。 (狭山) 2016/09/18(日) 20:57
2016/09/17(土) 22:06 の発言にインデントをつけるとこうなるはずです。
Private Sub Workbook_Open() flg = False For i = 1 To ActiveWorkbook.Sheets.Count If Sheets(i).Name = "更新履歴" Then flg = True Exit For End If Next If flg = False Then Sheets.Add after:=Sheets(Sheets.Count) ActiveSheet.Name = "更新履歴" With Sheets("更新履歴") .Range("A1") = "シート名" .Range("B1") = "変更セル" .Range("C1") = "値" .Range("D1") = "年月日 時 刻 " .Range("E1") = "ユーザー名" .Range("F1") = "保存ユーザー名" End With End If Sheets("更新履歴").Visible = False Sheets(1).Select End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) If Sh.Name = "更新履歴" Then Exit Sub With Sheets("更新履歴") .Rows(2).Insert Shift:=xlDown .Range("A2").Value = Sh.Name .Range("B2").Value = Target.Address .Range("C2").Value = Target.Value .Range("D2").Value = Now() .Range("E2").Value = Application.UserName .Range("F2").Value = CreateObject("WScript.Network").UserName .Columns("A:F").EntireColumn.AutoFit End With End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) With Sheets("更新履歴") .Rows(2).Insert Shift:=xlDown .Range("G2").Value = "" .Range("H2").Value = "" .Range("I2").Value = "上書き保存" .Range("J2").Value = Now() .Range("K2").Value = Application.UserName .Columns("G:K").EntireColumn.AutoFit End With End Sub
(なお、変数の型宣言もきちんとするべきです。)
参照元は知恵袋ですか?
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13151657003
あそこは、コードのインデントに配慮がなく、
行頭のスペースは詰まって表示されます。
それはとてもイレギュラーなことなんですよ。
学び始めて間が無い方は、勘違いし易いから、あまりお勧めできません。
(γ) 2016/09/18(日) 21:19
参照元は知恵袋です。 (γ)さんのおっしゃるのは分かるのですが 直ぐに使用出来てしまうので ついつい活用してしまって。
ところで、 Application.EnableEvents = False '■追加 Application.EnableEvents = True '■追加 が入っていませんでしたが?入れるのですよね?
インデントが大事だと勉強になりました。
(狭山) 2016/09/18(日) 22:48
(γ) 2016/09/18(日) 23:49
お世話になります。 (1)ですが申し訳ございません。 断っておりました。 サイトのコピーだけ行うのか? おっしゃるとうりです。弁解の余地もございません。 (2) オプション設定しました。 一行目に挿入Option Explicit入れたところ コンパルエラー 定数が定義されていません!と出てしまいflg = Falseのflg の部分が青く どうすれば使用出来るようになればいいのでしょうか。 (狭山) 2016/09/19(月) 11:00
(γ) 2016/09/19(月) 11:36
お世話になります。 何回もの対応いただきましてありがとうございました。
しかし、ゲーム感覚で、Web上だけのコード例だけ集めてみても・・・ そんなつもりで検索しているわけではございません。 (γ)さんからみれば、私が出来ない、学ばないように感じるかと思いますが そんなつもりでは。 しかし、そう思われても仕方がないような質問しかしてないですものね。
私の投稿の返答は(γ)さんが多いように感じるのですが (γ)さんがストレスを感じるのであれば、無理に返答していただかなくても と思います。(変な意味でとらないでください) 申し訳ない気持ちからです。 ありがとうございました。 (狭山) 2016/09/19(月) 13:42
(γ) 2016/09/19(月) 14:09
横から失礼します。
コードの内容云々も、当然、Q/Aの重要マターですが、同様に、コード記述におけるミスを いかにミニマイスするか、それも非常に重要なポイントです。
そのもっとも重要なものとして、γさん指摘の
1.変数はすべて明示的に記述する 2.コード記述は、そのロジックブロックが視覚的に把握しやすいように適切なインデントを つけてコーディングする。
この2つがあります。
1.については、たとえば
http://officetanaka.net/excel/vba/variable/02.htm
こういった解説ページをじっくりと読んでみることを推奨します。
2.についても、「VBA インデント」といったもので検索すると、実例つきの解説ページが、どっさりとでてきますので 是非、わかりやすいものに目を通して、理解し、取り入れていただきたいと思います。
1、2 ともに、それをしなくてもコードは書けますし、正しいコードならちゃんと実行されます。 でも、1、2を守ることが上達の早道ですし、開発生産性も格段にアップ、保守性にも優れたものになります。
だまされたと思って、この2つを取り入れてください。
で、その上で、本線というか、Q/Aのテーマであるロジック的なものに進んでいかれたらいいんです。
だけど、狭山さんは、「わかりました」とコメントしながら、ちっとも、その2つを取り入れずに、先に進もうと しておられるように感じます。
もちろん、コメントしましたように、1、2 を取り入れなくてもコードは書けるので 『そんなことを取り入れるつもりはない。コードロジックの回答だけほしい。』と【宣言】されるのも、佐山さんの自由です。
(β) 2016/09/19(月) 16:33
本スレで狭山さんががんばっておられるのは(ときどき)分かるのですが
それに不似合いなくらい、勉強の仕方が下手なように感じられます。
やる気が空回りしてもったいないカンジ。
ゲーム感覚というのがどういう意味か分かりかねますが
たしかに狭山さんは、基礎的なテキストを読まれたほうが良いと思います。
「初めて読む」ことになるのか、「もう一度読む」ことになるのか存じません。
でも基礎は一度読んだから終わりではなく、十度読んだから終わりではなく、百度読んだから終わりではなく
そこまで大げさなことでなくても
「変数が定義されていません」に対応できないとしたら、
基礎的なことをご存じないか、知ってはいても いざというとき思い当たらない、つまり
基礎が身についていないということです。もう一度読んだほうがいいと思います。
( 佳 ) 2016/09/19(月) 17:27
(β)さん( 佳 )さん ありがとうございました。 お二人がおっしゃる通りです。 (β)さんの教えていただいたサイトも拝見しました。 日にちを掛けて何度かまた勉強したいと思います。
( 佳 )さんのご指摘のやる気が空回りしてもったいない ですが、やる気と言うよりきっと直ぐに完成して明日からでも使用したかったからだと思います。 やはり、基礎すら出来ていないのに無理ですよね。(反省です) 結果、今回のコードは使用不可の状態で止まっていますので。
最後に、(γ) さまがおっしゃっていた知恵袋の 『あそこは、コードのインデントに配慮がなく、 行頭のスペースは詰まって表示されます。 それはとてもイレギュラーなことなんですよ。 学び始めて間が無い方は、勘違いし易いから、あまりお勧めできません。』 には正直ショックでした。 結構使用したコードもあり(幸いにも異常はでませんでしたが) 他の人も利用している人もいますので、早速、教えてあげたいと思います。 情報ありがとうございました。
大変ご迷惑をお掛けいたしました。 機会がございましたらよろしくお願い致します。
(狭山) 2016/09/19(月) 19:03
> 大変ご迷惑をお掛けいたしました。 > 機会がございましたらよろしくお願い致します。
なんか、解決したような雰囲気が出ていますが、解決なんですか?
それとも、諦めたのですか? それとも、すこし勉強してから、カムバックするお積りなんですか?
>やる気と言うよりきっと直ぐに完成して明日からでも使用したかったからだと思います。 単に思っただけで、明日から使用できなくても現実的に支障ないんですか? 私としては、人の成長を云々しているより、目の前にある問題を解決する方が興味あるんですけど。
(半平太) 2016/09/19(月) 19:27
(半平太)さん ご意見ありがとうございます。 解決ではありません。 すこし勉強してから、カムバックでは手遅れで。 現実的には明日からでも使用出来ないと支障はあるのですが しかし今の自分には無理と判断したところです。
(狭山) 2016/09/19(月) 19:53
(γ) 2016/09/19(月) 20:26
読み返してみましたが、
要するに、Option Explicitを書かなければ旨く動くが、
> 一行目に挿入Option Explicit入れたところ > コンパルエラー > 定数が定義されていません!
と出て困ったということだけですか?
(半平太) 2016/09/19(月) 20:34
> 更新履歴のシートで G2=IF(AND(B2<>"",C2<>""),"正常","問題あり")をコピーしながら行います。 そこ、ちょっと分からなかったです。
> .Range("F2").Value = CreateObject("WScript.Network").UserName
その文の下に↓を挿入すればいいんじゃないですか? .Range("G2").Formula = "=IF(AND(B2<>"""",C2<>""""),""正常"",""問題あり"")"
(半平太) 2016/09/19(月) 20:49
(半平太)さんありがとうございます。 2016/09/19(月) 20:34の通りです。 ファイルを開くと コンパルエラー 変数が定義されていません とエラーが出てFor iのiの部分が青くなるのです。(Dim tmp As Longにしても駄目でした)
一度整理するために下記に現在のコードを貼り付けます。 何度も申し訳ございません。
Option Explicit Private Sub Workbook_Open() Dim flg As Boolean Dim tmp As Long = 1 To ActiveWorkbook.Sheets.Count If Sheets(i).Name = "更新履歴" Then flg = True Exit For End If Next If flg = False Then Sheets.Add after:=Sheets(Sheets.Count) ActiveSheet.Name = "更新履歴" With Sheets("更新履歴") .Range("A1") = "シート名" .Range("B1") = "変更セル" .Range("C1") = "値" .Range("D1") = "年月日 時 刻 " .Range("E1") = "ユーザー名" .Range("F1") = "保存ユーザー名" End With End If Sheets("更新履歴").Visible = False Sheets(1).Select End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) If Sh.Name = "更新履歴" Then Exit Sub Application.EnableEvents = False '■追加 With Sheets("更新履歴") .Rows(2).Insert Shift:=xlDown .Range("A2").Value = Sh.Name .Range("B2").Value = Target.Address .Range("C2").Value = Target.Value .Range("D2").Value = Now() .Range("E2").Value = Application.UserName .Range("F2").Value = CreateObject("WScript.Network").UserName .Range("G2").Formula = "=IF(AND(B2<>"""",C2<>""""),""正常"",""問題あり"")" .Columns("A:F").EntireColumn.AutoFit End With Application.EnableEvents = True '■追加 End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) With Sheets("更新履歴") .Rows(2).Insert Shift:=xlDown .Range("G2").Value = "" .Range("H2").Value = "" .Range("I2").Value = "上書き保存" .Range("J2").Value = Now() .Range("K2").Value = Application.UserName .Columns("G:K").EntireColumn.AutoFit End With End Sub
(狭山) 2016/09/19(月) 21:29
γさんが解説している通りです。
>i なら、参照サイトでも出てきていますが、整数を表す Long 型を使います。 >分からなければ、 >Dim i >でもエラーは解決するはず。
あと、更新履歴シートが最左端にあった場合、それは非表示なので、 Sheets(1).Select のステートメントがトラブります。
なので、その場合を考慮すると、
Private Sub Workbook_Open() Dim flg As Boolean Dim i As Long ’←γさんが解説している通りです。 Dim temp As Long '表示中のシートの最左端(通常1だが、更新履歴が1の場合は2)
For i = 1 To ActiveWorkbook.Sheets.Count If Sheets(i).Name = "更新履歴" Then flg = True
If i = 1 Then temp = 2 Else temp = 1 End If
Exit For End If Next i '←キチンと「i」を書いた方がいいです。
If flg = False Then Sheets.Add after:=Sheets(Sheets.Count) ActiveSheet.Name = "更新履歴" With Sheets("更新履歴") .Range("A1") = "シート名" .Range("B1") = "変更セル" .Range("C1") = "値" .Range("D1") = "年月日 時 刻 " .Range("E1") = "ユーザー名" .Range("F1") = "保存ユーザー名" End With End If Sheets("更新履歴").Visible = False Sheets(temp).Select End Sub
(半平太) 2016/09/19(月) 21:49
>ActiveWorkbook.Sheets.Count
こう云うのは危なっかしいので
Thisworkbook.Sheets.Count
の方が、明確にブックを限定できるのでベターでした。
(半平太) 2016/09/19(月) 22:15
(半平太)さん 本当にご親切にコードの詳細まで、ありがとうございました。 明日、早速使用してみます。
.Range("G2").Formula = "=IF(AND(B2<>"""",C2<>""""),""正常"",""問題あり"")" の部分ですが、もしかしたら変更があるかもしれないとの連絡が入りまして。
予定は G2=IF(COUNTA(B2:C2),IF(COUNTA(B2:C2)=2,"問題なし?@",IF(B2="","問題なし?A","削除 Delete!")),"空白 問題なし?B")になるかもしれません。 その際は式の部分を変更して行います。
本当にありがとうございました。 (狭山) 2016/09/19(月) 22:31
申し訳ございません。 式が変でした。
G2=IF(COUNTA(B2:C2),IF(COUNTA(B2:C2)=2,"問題なし1",IF(B2="","問題なし2","削除 Delete")),"問題なし3")
(狭山) 2016/09/19(月) 22:50
狭山さん 回答云々では無く申し訳ありませんが、、 更新履歴を一操作づつ記録して行く興味深いシートで 以前、私も似た様なものを作ろうとした事がありましたが 結局は実行しませんでした
その理由はセルの数値変更であれ、列削除、挿入であれ、その都度マクロが働いてしまうので 操作上の一つである 直前に行った操作を取り消す ”元に戻す”(曲がった矢印のマーク) が使えなくなるためです この点、狭山さんのところでは大丈夫なんでしょうか? (私の職場ならクレームが来そうです)
この事、回避する方法がもしあれば私も知りたいです (感Feel) 2016/09/19(月) 23:21
ご指摘ありがとうございます。 いやー参りました。元に戻す機能が使えないなんて(泣) 最後の 最後になって・・・・ 残念です。クレームですね。
(狭山) 2016/09/19(月) 23:54
また失礼いたします。 前文の件ですが、元に戻す機能が使えないなんて確認不足でした。 回避する方法はないでしょうか。 ご意見お願い致します。
(狭山) 2016/09/19(月) 23:59
>元に戻す機能が使えないなんて確認不足でした。 マクロを使う者の間では常識的なことなんですけどね。
>回避する方法はないでしょうか。 今までもこんな趣旨の質問がありましたけど、まともに解決しているケースはなかったと思います。 (私が興味ないので、ろくにその経緯を追っていなかっただけかも知れませんけども)
アイデアとしては当該ブックの更新履歴シートに書かないで、メモ帳に書き込むとか、 別インスタンスのExcelを開いてそこに更新履歴ブックを開かせて書き込むとか。
つまり、本来のExcelに書き込まないようにすれば、戻るボタンが使用できるってことにはなります。
言うは易く、行いは難し。
ちょっとテストしてみましたけども、安定的な運用は難しそうだなぁという感触です。 何かもっといいアイデアが寄せられるといいですね。
>クレームですね。 私としては、元々のプログラムでさえ本当にうまくいくの? と思っていました。 いっぺんに多量のセルの書き込みがあったらどうなるのかなぁと不安になっています。
自己満足のレベルじゃなく、他人からクレームが付くようなきっちりした計画だとすると、 私の手に余る仕様です。お役に立たず済みません。 m(__)m
(半平太) 2016/09/20(火) 06:56
(γ) 2016/09/20(火) 07:05
自分もVBAを始めたのは4年前で、ちょっとしたきっかけでNETでコードを見つけ、
それをコピペしたらとってもすごい動きをエクセルがしてくれて、虜になりました。
最初は狭山さんと同じで、コードをろくに理解せず、走らせる事ばかりを優先し、
あちこちのコードをコピペしては繋ぎ合わせて、インデントも無視、という状態でした。
ここの学校で狭山さんと同じ様に皆さんに叱られながら、それでもコードが走る快感と、
職場の周囲の人達からすごいと評価され、みんなの仕事の効率化を図るツールをいくつも
作っていました。
今の狭山さんも、自分と同じであれば、正式な職務では無く、周囲から期待されて
ツールを作っているのではないでしょうか。そんな気がしました。
今となっては、狭山さんがコードの内容や、アドバイスを理解出来ていなくて、無理やり書いている事が分かる様になりました。
でも最初は自分も狭山さんと全く同じだったので、長い目で見てあげて下さい。
決して悪気はないと思います。もう少しすれば、早く走らせる事より、
しっかりコードを理解して、人に見られても恥ずかしく無いコードを
書こうと思って基礎を理解しようとする様になると思います。
皆さんとのやり取りから、そう感じられたので。
横からスミマセンでした。
(素人) 2016/09/20(火) 11:51
(半平太)さんありがとうございました。 (素人)さんのご意見ですが私は正式な職務では無いです。 周囲から期待されている訳ではないのですが、ただ効率よく行いたいためなんです。 沢山のご意見ありがとうございました。 (γ) さんもお世話になりました。
(狭山) 2016/09/20(火) 15:53
狭山さん、もう読まないのかも知れませんが、あきらめて終わるつもりだとしたら、
こんな形で終わるとしたら、今まで指導頂いたγさんや半平太さんに失礼だと思います。
少なくとも、γさんの質問、「でも今まで使ってきたのでしょう?」には答えるべきです。
自分は質問ばかりして、回答者さんの質問には答えない、説明もしない、では
コミュニケーションとして成り立たないし、本当に一方的で失礼だと思います。
学ぶつもりがあるのなら、成長する為に、あえて回答者さんは厳しい言い方をされますが、
食い下がっていくべきだと私は思います。
元に戻す機能がどうしても必要なら、
難しいテーマの様なので完璧では無いかも知れませんが、
この学校の回答者さん達は、必ず満足のいく回答をしてくれます。
もし読まれたら、今後の為にも必ずコメントをよろしくお願い致します。
(素人) 2016/09/21(水) 09:09
> すこし勉強してから、カムバックでは手遅れで。
> 現実的には明日からでも使用出来ないと支障はあるのですが
なぜそういう立場に立ってしまうでしょうねぇ。
マクロがあるから大丈夫と思うのでしょうか、、、、マクロはまだ無いのに。
頼まれ仕事なら引き受ける時点で
「いつまでに完成させるか」だけでなく
「できないばあい、いつまでに言えばいいか」取り決めをすればいいのに。
自分自身の仕事なら、無しで済ませる方法もいちおう考えて。
万一うまく行かなかった場合でもツボらずにすむ対策をあらかじめ取らないと。
γさん、ゲーム感覚のご説明ありがとうございます。
自分の場合、ゲーム感覚といわれて浮かぶイメージは
遊びだとかオモチャだとかいい加減だとか
(真剣にゲームをプレイしているひとに怒られそうですが)
でもそれだと文脈に合わないので変だなぁと思っていました。
なるほど、マニュアルフリーですか。きいてみるものですねぇ。
( 佳 ) 2016/09/21(水) 10:06
皆様には大変ご迷惑をお掛けして申し訳ございませんでした。 (素人) さまの 少なくとも、γさんの質問、「でも今まで使ってきたのでしょう?」には答えるべきです。 この件ですが、確かにマクロを実行後はデータが戻せないのは知っておりました。 しかし、マクロデータが入っている 戻す機能は恐らく使用した事がないかもしれません。 今まで元データを貼り付け加工するのが多かったためです。 当然、通常のファイル時には行いますが。
また、普段は標準モジュールに入れたのを使用してまして、今回のThis workbookに 入れて使用するのは初めてで 皆様のご指摘の通りもっと基礎から行うようにと言うのは真摯に受け止めます。 申し訳ございません。
現在の報告ですが今回のコードを使用しておりまして やはあり、元に戻す機能が使えないとのクレームが出てしまいました。 もう一つは .Range("G2").Formula = "=IF(AND(B2<>"""",C2<>""""),""正常"",""問題あり"")" この部分を以下の式に変更したくて =IF(COUNTA(B2:C2),IF(COUNTA(B2:C2)=2,"問題なし1",IF(B2="","問題なし2","削除 Delete")),"問題なし3")
入れてみたのですがコンパイルエラー 修正候補:ステートメントの最後 が出てしまい、調べまして 1つの完結した命令を1行に書くのが原則でその行の命令は、何か変という意味らしいのですが 改善方法が分からず、変更の式を手作業でコピーしながら行っている状況です。 図々しいお願いではございますが対処方法があれば、ご教授お願いしたいのですが。
(狭山) 2016/09/21(水) 11:56
想像すると、ダブルクォーテーションの使い方を間違えていそうです。元の式では""""で""を表現しているので、ダブルクォートで括られた内側でダブルクォートを使う場合は2個連続させる、という仕様を理解しているのかな?、とも思えますが、意味を考えず使っていたら、ミスしてそうです。
(???) 2016/09/21(水) 12:50
狭山さん、
.Range("G2").Formula = "=IF(COUNTA(B2:C2),IF(COUNTA(B2:C2)=2,""問題なし1"",IF(B2="""",""問題なし2"",""削除 Delete"")),""問題なし3"")"
こうゆう事だと思いますよ。
(素人) 2016/09/21(水) 13:42
(???)さん、(素人)さんありがとうございます。 全文の(半平太) さんの2016/09/19(月) 20:49 を確認しとけばと反省です。
2016/09/21(水) 11:56の投稿時は問題なく使用できていたのですが 別のファイルにコードを入れたところ 実行時エラー '1004' WorksheetクラスのSelectメゾットが失敗しました。
Sheets(temp).Selectが黄色くなってしまいました。
社内での作業は本日は許可が出ないので終わりとせざるを得なく明後日の作業となるので
学校内を検索しましたら
対策として
Sheets("temp").Selectの前に Sheets("temp").Visible = Trueを追加を試す。
と書いてありましたので行ってみたいと思います。
何度も申し訳ございませんが、よろしくお願い致します。 (狭山) 2016/09/21(水) 18:56
> =IF(COUNTA(B2:C2),IF(COUNTA(B2:C2)=2,"問題なし1",IF(B2="","問題なし2","削除 Delete")),"問題なし3")
ここは、マクロの記録が有効ですv(^^
まず数式が期待通りに動くか確認して、問題なければ
どこかのセルにこの数式を入力する動作を記録します。
(もし勉強したければ、もっとシンプルな数式を入力して記録されたコードを観察します)
( 佳 ) 2016/09/21(水) 18:58
>Sheets(temp).Selectが黄色くなってしまいました
これはtemp番目のシートを選択しろという意味です。
そのときのtempの値は何ですか?
もし0なら、0番目のシートということになりますので、当然選択はできません。
If flg = False Then の中に temp = 1 を入れましょう。
>Sheets("temp").Visible = Trueを追加を試す
Sheets(temp).Visible = True ですね。
非表示のシートは選択できませんので、
Sheets(temp)が非表示なら有効ですか、そうでなければ、
すでに表示されているものをさらに表示しても、なにも変わりません。
なんとなくこれは違うような気がします。
( 佳 ) 2016/09/21(水) 19:38
( 佳 )さん お世話になります。 > =IF(COUNTA(B2:C2),IF(COUNTA(B2:C2)=2,"問題なし1",IF(B2="","問題なし2","削除 Delete")),"問題なし3") は期待通りに動きました。 下にマクロの記録で行ったコードを書きます。
Option Explicit
Sub Macro()
Range("G2").Select ActiveCell.FormulaR1C1 = _ "=IF(COUNTA(B2:C2),IF(COUNTA(B2:C2)=2,""問題なし1"",IF(B2="""",""問題なし2"",""削除 Delete"")),""問題なし3"")" Range("G3").Select End Sub このコードがシンプルな数式になるのを教えて下さい。
また、tempの値は何ですか? の件ですが以下のコードの部分でしょうか
For i = 1 To ThisWorkbook.Sheets.Count If Sheets(i).Name = "更新履歴" Then flg = True
If i = 1 Then temp = 2 Else temp = 1 End If If flg = False Then の中に temp = 1 を入れましょう。 ですがどこに入れるのでしょうか。 ご教授お願い致します。
(狭山) 2016/09/21(水) 22:53
あれ? 私の書いたコードがトラブってますか?
> For i = 1 To ThisWorkbook.Sheets.Count > If Sheets(i).Name = "更新履歴" Then > flg = True > > If i = 1 Then > temp = 2 > Else > temp = 1 > End If
すみません。こっちへ変更してください。m(__)m temp = 1 For i = 1 To ThisWorkbook.Sheets.Count If Sheets(i).Name = "更新履歴" Then flg = True
If i = 1 Then temp = 2 End If
(半平太) 2016/09/21(水) 23:37
コードの訂正は行いました。 しかし実際のテストは明後日になりますが動かして問題があれば報告致します。
一旦、整理の為、再度コードを書かせて下さい。
Private Sub Workbook_Open()
Dim flg As Boolean Dim i As Long ’←γさんが解説している通りです。 Dim temp As Long '表示中のシートの最左端(通常1だが、更新履歴が1の場合は2) temp = 1 For i = 1 To ThisWorkbook.Sheets.Count If Sheets(i).Name = "更新履歴" Then flg = True If i = 1 Then temp = 2 End If Next i '←キチンと「i」を書いた方がいいです。 If flg = False Then Sheets.Add after:=Sheets(Sheets.Count) ActiveSheet.Name = "更新履歴" With Sheets("更新履歴") .Range("A1") = "シート名" .Range("B1") = "変更セル" .Range("C1") = "値" .Range("D1") = "年月日 時 刻 " .Range("E1") = "ユーザー名" .Range("F1") = "保存ユーザー名" End With End If Sheets("更新履歴").Visible = False Sheets(temp).Select End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Sh.Name = "更新履歴" Then Exit Sub Application.EnableEvents = False '■追加 With Sheets("更新履歴") .Rows(2).Insert Shift:=xlDown .Range("A2").Value = Sh.Name .Range("B2").Value = Target.Address .Range("C2").Value = Target.Value .Range("D2").Value = Now() .Range("E2").Value = Application.UserName .Range("F2").Value = CreateObject("WScript.Network").UserName .Range("G2").Formula = =IF(COUNTA(B2:C2),IF(COUNTA(B2:C2)=2,"問題なし1",IF(B2="","問題なし2","削除 Delete"))," .Columns("A:G").EntireColumn.AutoFit End With Application.EnableEvents = True '■追加 End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean) With Sheets("更新履歴") .Rows(2).Insert Shift:=xlDown .Range("G2").Value = "" .Range("H2").Value = "" .Range("I2").Value = "上書き保存" .Range("J2").Value = Now() .Range("K2").Value = Application.UserName .Columns("G:K").EntireColumn.AutoFit End With End Sub (狭山) 2016/09/22(木) 00:18
For i = 1 To ThisWorkbook.Sheets.Count
If Sheets(i).Name = "更新履歴" Then flg = True If i = 1 Then temp = 2 End If End If '←Ifに対するEnd Ifが抜けています。 Next i
それと、ここはダブルクォートが必要だし、問題なし3が消えてしまっています。コードのコピペも丁寧にしましょう。
.Range("G2").Formula = "=IF(COUNTA(B2:C2),IF(COUNTA(B2:C2)=2,""問題なし1"",IF(B2="""",""問題なし2"",""削除 Delete"")),""問題なし3"")"
コードの先頭をクリックして、F8キーを押していってデバッグすると、順番にコードが黄色に塗られて移動していきます。黄色が通り過ぎたコードにカーソルをかぶせてみると、例えば
ThisWorkbook.Sheets.Countにカーソルをかぶせると、
ThisWorkbook.Sheets.Count=3 とか、現在の状態を教えてくれます。
こうすれば、例えば元のコードがtemp = 0になっていた、とかを調べられます。
>Sheets(temp).Selectが黄色くなってしまいました。
こういう時に是非やってみて下さい。
(素人) 2016/09/22(木) 09:58
>このコードがシンプルな数式になるのを教えて下さい。
このコードがシンプルな数式になるとは、言っていません。
誤解を誘ったなら申し訳ないです。
ご存知とは思いますがマクロの記録は、エクセル君の目の前で操作をして見せて
操作内容どおりのコードを作らせ、その一部を切り取って自分のコードに組み込むものです。
これを利用して数式のコードを作りましょう。
今回の操作は、G2セルを選択→そのセルに数式入力→G3セルにカーソル移動
これがそのままコードになっていて、このうち使いたいのは
「そのセルに数式入力」 部分の「数式」のみ。
ここですね。
"=IF(COUNTA(B2:C2),IF(COUNTA(B2:C2)=2,""問題なし1"",IF(B2="""",""問題なし2"",""削除 Delete"")),""問題なし3"")"
これを「.Range("G2").Formula =」の右に置けば出来上がりです。
別の数式を入力するときでも、この方法が使えます。
で。
もし、どういうルールでこういう式になるか知りたければ
もっとシンプルな数式を記録してコードを見るとルールを見つけやすいです。
( 佳 ) 2016/09/22(木) 10:15
いえいえ。
確かにそこでなにかしらtempに値が入りますので、そこで確認したくなりますが
確実を期すなら Sheets(temp).Select ここです。
ここに来るまでにどんなグチャグチャなことをしても
シートを選択する時点でtempの値が 実在するシートの番号であればOKです。
tempの値を確認する方法はたとえば
Sheets(temp).Select がエラーで黄色くなっているときに
tempのうえにマウスポインタを持っていってそのままじっと1秒ほど待つと
その時点での値がポップアップされます。
(エラー時以外でも、コードが一時停止しているときならこの方法が使えます)
Msgboxも使えますね。わたしはこれが好きで 値の確認用によく使います。
( 佳 ) 2016/09/22(木) 10:38
突き放すようですが これは でも
コードの意味を理解すれば、自分で決められるはずです。
いただいたコードは動作確認して次へ進むではなく、ちゃんと理解しましょう。
理解できていない部分は、ここが理解できないから分かるように教えてクレと質問しましょう。
いまならまだ1つ1つのコードはそんなに長くありませんから。
( 佳 ) 2016/09/22(木) 10:53
興味が沸いたのでファイルにコピペしてみました。
「問題なし2」は更新履歴シートのB列(変更セル)が空白の時に表示され、
「問題なし3」は更新履歴シートのB列とC列(変更セル)と(値)が空白の時に表示されますが、
更新履歴シート以外のシートに記入したり削除したりした場合、
削除するとB列に変更セルが記入されるしG列に「削除」が記入されますし、
記入するとB列とC列に変更セルと値が記入されるので、
どういう時に問題なし2と3が表示されるのかがわかりません。
更新履歴シートのB列、C列のセルを手動で削除しないと表示されない様に思うのですが、
問題が無い範囲でどの様に使用するのか使用方法を教えて下さい。
(もしかしたら自分の業務にも応用出来るかも知れないので)
よろしくお願いします。
(素人) 2016/09/22(木) 11:39
主として自宅でしかアクセスしませんのでどうしても遅くなります。 まずもって、(素人)さんのご配慮に感謝申し上げます。
「今まで使ってきたのではないか」に対する回答をいただきましたが、 納得できるものではありませんでした、しかし、もうどうでもよいです。 単に回答を得たいがための方便に過ぎないとよくわかりましたので。 たぶん、複数の人が使うことはこれまでもなかったし、今も使っていないと 思います。また検討中の内容も効率には一切関係がないと思います。
このあと続けて、基礎学習がいかに大切なのか、 質問する際に架空の話を余り作らなくても回答は得られる(自然体のすすめ) といった点など、70行近くのコメントを書いたのですが、 アップしません。馬の耳になんとかのような気配が濃厚ですので。
それでは頑張って下さい。
(γ) 2016/09/22(木) 12:25
(素人)さんご親切にありがとうございました。 返答が多くなってしまったので纏めて申し訳ございません。
2016/09/22(木) 09:58(素人)さんへ返答です。 (素人)さん End Ifがひとつしかありません。 (狭山) 訂正、コードを書き替えました。
(素人)さん コードのコピペも丁寧にしましょう。 (狭山) はい。コピー抜けていましたので.Range("G2").Formula =から""問題なし3"")"まで訂正しました。
(素人)さん F8キーで現在の状態を確認 (狭山) Sheets(temp).Selectを確認しましたtemp=1でした。
2016/09/22(木) 11:39(素人)さんへ返答です。 この件ですが(素人)さんの業務に応用出来ることは無いかと・・・ 最終的にフィルターで“削除 Delete”のみを検索するだけです。 (素人)どういう時に問題なし2と3が表示されるのかがわかりません。 (狭山)申し訳ございません。問題なし2に関しましては不用でした。 問題なし3に関しては手入力の時にI〜Jの上書き保存の表示が出た時に 空白になるので使用していましたが、現在は“削除 Delete” “問題なし1”のみで 大丈夫でした。申し訳ございません。
(狭山) 2016/09/22(木) 18:02
( 佳 )さんご親切にありがとうございました。 返答が多くなってしまったので纏めて申し訳ございません。
2016/09/22(木) 10:15( 佳 )さんへ返答です。
( 佳 )さん シンプルな数式になるとは、言っていません。 (狭山) 私が勘違いしてしまいました。申し訳ございません。
( 佳 )さん 別の数式を入力するときでも、この方法が使えます。 (狭山) 今回、勉強させていただきましたので次回、挑戦してみたいと思います。
2016/09/22(木) 10:38( 佳 )さんへ返答です。 ( 佳 )さん Sheets(temp).Select tempの値を確認は (狭山) Sheets(temp).Selectを確認しましたtemp=1でした。
2016/09/22(木) 10:53( 佳 )さんへ返答です。 ( 佳 )さんIf flg = False Then の中に temp = 1 を入れましょう。 (狭山)Sheets(temp).SelectをSheets(temp1).Selectでよろしいでしょうか。 ご教授お願い致します。
(狭山) 2016/09/22(木) 18:06
> (狭山)Sheets(temp).SelectをSheets(temp1).Selectでよろしいでしょうか。
なぜそのように考えられましたか?
あ、ダメという意味ではありません。
いい、という意味でもありません。
単になぜそう考えたのかをご説明願いたいだけです。
( 佳 ) 2016/09/23(金) 11:58
大変遅くなりまして申し訳ございません。 シートを選択する時点でtempの値が 実在するシートの番号であればOKと 前回教えていただいたのでtemp=1 と確認できたので入れました。 これが理由です。
現在、サーバーを導入中でコードを入れていません。 夕方には入れられるかと思います。 (狭山) 2016/09/23(金) 12:50
あれ、それはおかしいですよ。
その考えで行けば
Sheets(temp=1).Select でないと理屈が通りません。
でしょう?
なぜSheets(temp1).Selectなのでしょう。
>コードの意味を理解すれば、自分で決められるはずです。
こちらはいかがですか?
( 佳 ) 2016/09/23(金) 15:07
分かりました。 Sheets(1).Select コピーしたシートを選択でしょうか。 (狭山) 2016/09/23(金) 15:30
>Sheets(1).Select
それでいいなら、tempなんか要りませんね。
どこから出てきたんでしたっけ、tempは。
( 佳 ) 2016/09/23(金) 16:09
何度も申し訳ございません。 Sheets("更新履歴").Selectでしょうか。 (狭山) 2016/09/23(金) 16:25
>Sheets("更新履歴").Selectでしょうか。
ええと、そのコードの意味は分かりますか?
分かった上で、どのシートを選択したいですか?
( 佳 ) 2016/09/23(金) 16:57
(狭山) 2016/09/23(金) 19:06
そういうことがしたいのですか?
( 佳 ) 2016/09/23(金) 20:23
他のワークシートの With Sheets("更新履歴") .Range("A1") = "シート名" .Range("B1") = "変更セル" .Range("C1") = "値" .Range("D1") = "年月日 時 刻 " .Range("E1") = "ユーザー名" .Range("F1") = "保存ユーザー名" を更新履歴へ書き出す事を行いたいのです。 すみません分からなくなってしまいました。 (狭山) 2016/09/23(金) 20:36
>すみません分からなくなってしまいました。 という事なので、現在進行中の( 佳 )さんとのやり取りに的を絞ってみますと
Private Sub Workbook_Open() 'このファイルを開いたタイミングで実行する手続きである
Dim flg As Boolean '「更新履歴」シートが既に存在するかどうかを覚えておく変数 Dim i As Long ' Dim temp As Long 'この手続きの最後に選択するシートは左から何番目かを覚えておく変数
temp = 1 '★最初にtempを1にしておく(最後に選択するシートは左から1番目の意) For i = 1 To ThisWorkbook.Sheets.Count 'ブック内の全シート(の名前)を左から順に調査し、 If Sheets(i).Name = "更新履歴" Then ' シート名が「更新履歴」だったら flg = True ' flgをTrueにする(「更新履歴」シートが既に存在しますの意) If i = 1 Then ' 既に存在してた「更新履歴」シートが左から1番目のシートだったら temp = 2 ' ★tempを2にする(最後に選択するシートは左から2番目の意。なんだけど End If ' 左から1番目である「更新履歴」シートは非表示にしちゃう訳だから End If ' 実質「見た目上」左から1番目にあるシートを選択する様に仕掛けてる) Next i ' (尚、「更新履歴」シート以外に非表示のシートが無いという前提の話)
If flg = False Then ' 調査の結果「更新履歴」シートが無かった場合は Sheets.Add after:=Sheets(Sheets.Count) ' 1番右に新規シートを追加 ActiveSheet.Name = "更新履歴" ' そのシートの名前を「更新履歴」にする With Sheets("更新履歴") ' その「更新履歴」シートの .Range("A1") = "シート名" ' A1セルの値を「シート名」にする .Range("B1") = "変更セル" ' B1セルの値を「変更セル」にする .Range("C1") = "値" ' C1セルの値を「値」にする .Range("D1") = "年月日 時 刻 " ' D1セルの値を「年月日 時 刻 」にする .Range("E1") = "ユーザー名" ' E1セルの値を「ユーザー名」にする .Range("F1") = "保存ユーザー名" ' F1セルの値を「保存ユーザー名」にする End With ' End If '
Sheets("更新履歴").Visible = False ' 「更新履歴」シートを(既にあった場合も今回作った場合も)非表示にする Sheets(temp).Select ' ★「見た目上」左から1番目にあるシートを選択する End Sub
( 佳 )さんからの問い掛けは、上記の★の部分に関する(狭山)さん自身の「ご意向」の確認ではないですかね?
>更新履歴へ書き出す事
それは「本題」です。 今( 佳 )さんから問い掛けられている事ではないと思います。。 「あ、実はそこはどうでもいいんですよね」という事であれば、 その様にお返事をされてもいいと思います。
(白茶) 2016/09/23(金) 21:54
白茶さん、フォローありがとうございます。
まずはお礼まで。
( 佳@狭山さんのコメント待ち ) 2016/09/24(土) 11:45
(白茶)さんありがとうございました。 一つ一つコードの解説まで。感謝いたします。 ★の部分に関する(狭山)自身の「意向」の確認ですが そこは気にしないのです。
本日実際にファイルにコードを入れてみまして 最初は実行時エラー '1004'WorksheetクラスのSelectメゾットが失敗しました。 Sheets(temp).Selectが黄色くなってしまいました。 もしかしたら試験用ではエラーが出なかったため、試験用で実際のシートの数(37個)と同じ名前 を入れOK、内容を全て入れ替えたところエラーが出ずに大丈夫でした。 現在まで使用していたファイルがどこかしら破損していたのでしょうか。
これまで本当にお世話になりありがとうございました。 皆様は勿論感謝しておりますが、後半で( 佳 )さんの質問では 検索して調べながらですので大変勉強になりました。 正確な回答はできませんでしたが・・・・・ 今後ともよろしくお願い致します。
(狭山) 2016/09/24(土) 14:58
>★の部分に関する(狭山)自身の「意向」の確認ですが
>そこは気にしないのです。
ああ、それなら、tempがらみのコードは全部必要ありません。
消してしまって構いません。
ま、残しておいてただちに悪さをするわけではないので、
あわてて消さなくても大丈夫ではあります。
'--
再度、基礎を勉強されるようお勧めします。
本スレでは、急いでコードが必要なので間に合わないということでしたが
急ぎのコードはなくなりましたので。
勉強していて もし分からないことが出てきたら、遠慮なく質問してください。
'--
>もしかしたら試験用ではエラーが出なかったため、試験用で実際のシートの数(37個)と同じ名前
>を入れOK、内容を全て入れ替えたところエラーが出ずに大丈夫でした。
自分で考えてこういう対応ができるなら、エラーの原因もいずれ分かるようになります。
ああ、そうだ、この原因特定を、基礎を学ぶ当面の目標としてもいいかもしれませんね。
なんの目標もなくばくぜんと勉強するより、ねらうところがあるほうが張り合いがあると思うので。
( 佳 ) 2016/09/25(日) 09:54
( 佳 ) さんご返信ありがとうございます。 tempがらみのコードは暫く残しておきたいと思います。 今後、悪さをした場合に実際に体験したいからと思いまして。 また、今回のように急いでコードの質問はしません。申し訳ございませんでした。 色々と本当にお世話になりました。 ありがとうございました。 また、よろしくお願い致します。
(狭山) 2016/09/25(日) 10:59
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.