X



Excel VBA 質問スレ Part63
■ このスレッドは過去ログ倉庫に格納されています
0258デフォルトの名無しさん (アークセー Sxcb-FpGY)
垢版 |
2019/10/13(日) 22:13:33.97ID:0JmSqCe7x
シートが可視化された配列だってのはその通りなんだけど誰でもGUIで簡単に編集できてしまう点が逆に弱点でもある
値の読み書きだけでイベントハンドラに制御が渡るからそもそも重いし
0262デフォルトの名無しさん (アウアウウー Sa5b-8cCB)
垢版 |
2019/10/13(日) 23:09:26.19ID:YeAfr+Aea
>>241
こういうこと?
Sub 検索()
Const COL_C As Long = 3
Const COL_F As Long = 6
Const COL_O As Long = 15
Dim nSetRow As Long
nSetRow = 5
Dim nRow As Long
For nRow = 5 To 17
If Not IsExistValue(Cells(nRow, COL_C).Value) Then
Cells(nSetRow, COL_O).Value = Cells(nRow, COL_C).Value
nSetRow = nSetRow + 1
End If
Next
For nRow = 5 To 21
If Not IsExistValue(Cells(nRow, COL_F).Value) Then
Cells(nSetRow, COL_O).Value = Cells(nRow, COL_F).Value
nSetRow = nSetRow + 1
End If
Next
End Sub
0263デフォルトの名無しさん (アウアウウー Sa5b-8cCB)
垢版 |
2019/10/13(日) 23:09:42.80ID:YeAfr+Aea
Function IsExistValue(ByVal pValue As Variant) As Boolean
IsExistValue = True
Const COL_Y As Long = 25
Dim nRow As Long
For nRow = 5 To 25
If Cells(nRow, COL_Y).Value = pValue Then
Exit Function
End If
Next
IsExistValue = False
End Function
0265デフォルトの名無しさん (ワッチョイ 9fe0-o74w)
垢版 |
2019/10/14(月) 00:48:24.78ID:2bLpiP0X0
2シートを連結する際、それぞれの各行をクラスインスタンスに代入&コレクション化してるのですが連結方法に悩んでいます

Personクラス(pID, 氏名, 名字プロパティ, 生年月日,...)→Persons.Add Personインスタンス, str(pID)
Diaryクラス(dID, pID, 作成日, 本文,...)→Diaries.Add Diaryインスタンス, str(dID)
'出力
Dim d as Diary
For each d in Diaries
if(存在チェック) then xxx = Persons.Item(d.pID).名字
Next d

現在上記のように回してますが、より楽に書けるor固いor保守しやすい...実装があれば教えて頂きたいです
現状はプロパティの予測表示がされないのが微妙に使いにくいのと、そもそもコレクションにおけるkeyの動作をよく分かっていません
0267デフォルトの名無しさん (ワッチョイ bf68-NJTS)
垢版 |
2019/10/14(月) 09:29:31.58ID:+oSE7p5I0
VBAでOPENしたファイルを引数で渡す事は出来ますか?
こんな感じで処理したいのですが、「#1」って変数では無いのでしょうか

Sub foo()
Open "TESTFILE" For Output As #1 ' Open file for output.
Call write_(#1,"content")
Close #1
End Sub

Function write_(filenumber, content)
Write filenumber, content
End Function
0269デフォルトの名無しさん (アウアウウー Sa5b-8cCB)
垢版 |
2019/10/14(月) 12:22:02.07ID:UlmNQm1da
>>267
ファイル番号は1-255の範囲で常に固定値でやるなら引数で渡さずにどこも#1でいいかと思う
FreeFileって関数があってこれは番号を任意に付番してくれるので
たとえば
Dim nNo as Integer
nNo = FreeFile
Open .... #nNo
って書くこともできる
このnNoを引数に指定してもいいかもね
0270デフォルトの名無しさん (ワッチョイ bf68-NJTS)
垢版 |
2019/10/14(月) 12:27:42.70ID:+oSE7p5I0
>>269
行けました!ありがとうございます
ナンバー記号「#」の詳細ってMSDNかどこかにありますか?

Sub foo()

Dim nNo As Integer
nNo = FreeFile

Open "TESTFILE" For Output As nNo ' Open file for output.
Call write_(nNo, "conteaasnt")
Close #1

End Sub

Function write_(nNo, content)
Write #nNo, content
End Function
0271デフォルトの名無しさん (アークセー Sxcb-FpGY)
垢版 |
2019/10/14(月) 14:39:32.50ID:aC+4aHxsx
>>265
Persons、Diariesをコレクションにしている理由は、「Person、Diaryという2つのカスタムクラスの集合オブジェクト」という意味論以外に、何か実装的な理由はあるのかな?

例えば、2つのコレクションクラスに格納するデータの型が一様でないからCollectionじゃないとリスト化できないとか、多態のためにCollectionクラスをインターフェース継承させているとか

そういう事情がないならば、Keyの存在確認手段を持たないCollectionクラスではなく、Keyの存在確認を行うExistsメソッドを持つDictionaryを使うのが実装的には楽だと思う
pID・Person、pID・Diaryの二種類のペアに対応するDictionaryを個別に作ってpIDでリレーション確認するイメージ(各DictionaryではpIDをKeyとしておく)

そもそもRemoveやAddといった基本的な機能はCollectionとDictionaryとで共通しているし、Dictionaryの方が動作も早いしね
0274デフォルトの名無しさん (ワッチョイ bf68-NJTS)
垢版 |
2019/10/14(月) 15:51:24.60ID:+oSE7p5I0
>>272-273
あれ、じゃあなんでしょうねこれ
コンソールで
?#1
ではエラーになるので、ただの数値ではなくなるみたい
#1=2
も出来ない。なんとなくリテラルか参照っぽいですが、何でしょうね
openなどの時にしか使えないのでしょうか
0275デフォルトの名無しさん (ワッチョイ 9fe0-o74w)
垢版 |
2019/10/14(月) 15:54:12.83ID:2bLpiP0X0
>>271
ありがとうございます
コレクションを選択した理由は特にありません
(あえて挙げるなら、コレクションにまとめるリファレンスが最初に目に付いた です)

>pID・Person、pID・Diaryの二種類のペアに対応するDictionaryを個別に作ってpIDでリレーション確認するイメージ(各DictionaryではpIDをKeyとしておく)
言葉足らずですみません。Diaryクラス側ではpIDが重複しdIDが主キーとなるので、一意に取得できません。(この認識も間違っていたらすみません...)
エラー処理がExistsで済むのは明確なメリットですね。Collectionでは、調べた限りではOnErrorGoToで飛ばす方法しか見つけられませんでした
ひとまず、Diary側のループで取得したpIDでPersonDictionaryにExistsをかける 方法を試してみようと思います。
0278デフォルトの名無しさん (アークセー Sxcb-FpGY)
垢版 |
2019/10/14(月) 17:26:42.75ID:J7mWSp9Bx
>>275
複数のDiaryインスタンスが共通のpIDを持つならば、連結を二重化したらいいんじゃないだろうか

まずpIDをキーとするDiary用のDictionaryをまず作っておいて、
同じpIDを持つDiaryインスタンスをまとめたDictionaryかCollectionをItemとして持たせる形にすればいいと思う

構造的に表すと
(Key[i] = pID, Item[i] = (Key[j] = dID, Item[j] = Diary))

みたいな感じ
0279デフォルトの名無しさん (ワッチョイ bfad-la4p)
垢版 |
2019/10/14(月) 22:48:09.17ID:PwgP8aUB0
VBAで表からその左の行を検索したいのですがどうしたらいいでしょうか?
Dim rng As Range
Set rng = ws_siriaru.Range("D:L").Find(ken4, LookAt:=xlWhole)
If rng Is Nothing Then rng
MsgBox ""ない
Exit Sub
End If
siriaru = Range("C" & rng.Row).Value
gouki = siriaru
label_siri = gouki
では表示はされるのですがうまくいきませんでした。
0280デフォルトの名無しさん (ワッチョイ 9fe0-o74w)
垢版 |
2019/10/14(月) 23:16:54.59ID:2bLpiP0X0
>>278
重ねてありがとうございます。

なるほど。Dictionaryの各要素を、そのkeyに対応するインスタンスの集合とするんですね
1key対1レコード という考えしか無かったので目から鱗です
0282デフォルトの名無しさん (ワッチョイ 9fe0-o74w)
垢版 |
2019/10/15(火) 00:02:27.41ID:0b9bW6T40
>>279
どういった表示がされて、実際に欲しい情報とどこが違うでしょうか?

Range("D:L")をken4で完全一致検索をかけ、最初に見つかったセルの行番号を取得
その行のC列セルの値をsiriaruに代入

という点ではプログラムに間違いはありません
0283デフォルトの名無しさん (アークセー Sxcb-FpGY)
垢版 |
2019/10/15(火) 00:30:22.92ID:i09LlRYux
>>280
その通り
そのようにすれば、Diaryのインスタンス集合全体に対してpIDの存在確認をすることも出来るし、pID, dIDという2つのプロパティ値を使って目的のDiaryオブジェクトを取り出すこともできる
0288デフォルトの名無しさん (アークセー Sxcb-FpGY)
垢版 |
2019/10/15(火) 21:28:52.40ID:NB8YI5GFx
>>287
Variant型は便利だけどRangeオブジェクトを突っ込むためだけの変数で使用するにはねぇ
実際のデータ型を明示しないぶんコードが読みにくくなるしコーティング時にインテリセンスも利かなかったりとデメリットの方が目立つ
実行時エラーの原因って感じ
0289デフォルトの名無しさん (ワッチョイ bfad-la4p)
垢版 |
2019/10/15(火) 22:36:34.14ID:LwOOuMgG0
リストの表示について
以下の表示の際最終行後ろのセルが空白だった場合最終行が表示されません。
なぜでしょうか?
LastRowではA列の最終行を指定しているので間違いではないと思うのですが
最終行のみ全てのセルに数値を入れていないと最終行に反映されないみたいです;。
With ws_kiki
    LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
myData = .Range(.Cells(1, 1), .Cells(Rows.Count, 13).End(xlUp)).Value

End With
With list_ken
.ColumnCount = 13
.ColumnWidths = "20;60;50;50;50;70;70;50;50;50;50;50"
.List = myData
0291デフォルトの名無しさん (アークセー Sxcb-FpGY)
垢版 |
2019/10/15(火) 23:33:50.79ID:NB8YI5GFx
>>289
あなたsiriaruの人でしょ
もういい加減お金払って誰かに教えてもらうか、MSDNのVBAのリファレンスを読み込んできちんと勉強すべきだとおもうよ
会社で使ってるマクロのコードベタ貼りしてるのも本当に宜しくない

今回の問題は、せっかくLastRowにA列の使用セルの最終行の行インデックスを格納しているのに、myDataに入れる値のセル範囲指定でそのLastRowの値を使っていないことが原因でしょ
自分の頭をちゃんと使って書いてる?

myData = .Range(.Cells(1, 1), .Cells(LastRow, 13)).Value

と書き直せば終わり
0295デフォルトの名無しさん (ワッチョイ 9f4f-aOdU)
垢版 |
2019/10/16(水) 07:23:15.57ID:Qp+et4KT0
.Net系もやってる人に質問です
列挙体に属性付けて指定すると数値の他に定義した文字列返す方法があると思うんですけど
アレをVBAで行う方法は有りますか?
Constで定義すれば出来ないことは無いんですがなんかダサくて・・・
0299295 (ササクッテロ Spcb-aOdU)
垢版 |
2019/10/16(水) 12:54:37.89ID:swoRisr+p
>>296
そのためにクラスを作るとVBAの場合はひとクラス1モジュールファイルを切らないといけないし、
フォルダ分けも出来ないので、クラスを作る方法は後々クラスファイルが煩雑になる可能性があるのでやめておきます。

構造体や配列を使うのは少し大掛かりな気もしますが、お陰で何となくイメージがわきました。
DictionaryとかCollectionとかのValueペアのオブジェクトを使って、key側にenumで使用している番号、
Value側に文字列を設定して、enumに紐付けてやるような感じでやろうかなと。
ただ、修正が入るときに手間が掛かるようだとあまり意味がないのでその辺の構成は気をつけて作るような
感じですかね。ありがとうございました。

>>297
どんな言語だろうと自分なりに構成を考えて作っていくのは大事だと思いますよ。
今回の件は無理して作る程のものではありませんが
きちんと部品化しておけばまた違った局面で使うことが出来るので、
自分のためにも、引き継ぐ人のためにも大事だと思います。それはどの言語でも同じでしょう。
0304デフォルトの名無しさん (アークセー Sxcb-FpGY)
垢版 |
2019/10/16(水) 22:11:30.10ID:Y2Xm51x3x
>>299
値のペアを返す参照構造を作りたいんだったらワークシートを素直に使ってハッシュテーブルで運用した方がメンテ工数が少ないのでは
ワークシートはGUI化された多次元配列なのでね
セルの値の読み書きでイベントハンドラに制御が渡るのが嫌なら別だが
0305デフォルトの名無しさん (ワッチョイ 5701-TO0X)
垢版 |
2019/10/16(水) 22:19:50.46ID:IiLmkjOX0
フィルタされたデータをシート上で複数繋がった状態で選択したとする。その場合にそれら『のみ』を取得することはできるんだろか?教えていただきたいです。
バージョンはexcel2016です。

例)
以下がフィルタされたセル。
 A1←選択
 A4←選択
 A5
上の場合にA1とA4のみを取得する。A2とA3は取得しない。
0306デフォルトの名無しさん (アークセー Sxcb-FpGY)
垢版 |
2019/10/16(水) 22:43:21.53ID:Y2Xm51x3x
フィルタ抽出されたセル範囲だけを取得したいなら、
Range("A1:A5").SpecialCells(xlCellTypeVisible).Select

の一行で終わると思う
Range.SpecialCellsプロパティが可視セルだけを返すよう、引数に列挙定数xlCellTypeVisibleを渡せばいい
Range("A1:A5")のフィルタ範囲は必要に応じて変えてね
0307デフォルトの名無しさん (ワッチョイ bfad-la4p)
垢版 |
2019/10/16(水) 23:52:50.60ID:e5YHiPLP0
>>289です。
わぉ!辛辣ですね。こちらで聞いて大分やりたいことが出来ましたので
後は自分で考えていきます。
参考書を聞きかじってインターネットからまるまるパクったコードをデバックしまくって改造
していきます。
ちなみに今回のコードは
LastRow = .Cells(Rows.Count, 1).End(xlUp).Row
myData = .Range(.Cells(1, 1), .Cells(Rows.Count, 13).End(xlUp)).Value
これが正しいコードでした。
myData = .Range(.Cells(LastRow, 1), .Cells(1, 13).End(xlUp)).Value
最終列の最終行を取得してたのでそこが空白だと最終列が反映されないことが判明しました
0309デフォルトの名無しさん (アークセー Sx47-vS/Z)
垢版 |
2019/10/17(木) 01:12:20.23ID:cDk85Tz1x
>>307
読んでて頭痛のするような酷い文章だな
デバックじゃなくてデバッグだろ

しかも単なるコード改変のことをデバッグとか言ってるしさ
本気でデバッグしなきゃならないときにスキルのないこういうコピペコーダーは何の役にも立たないのに
会社の資産であるコードをこんな掲示板に晒しといて何やってんだか
0311デフォルトの名無しさん (ワッチョイ 1ead-b2ak)
垢版 |
2019/10/17(木) 01:19:38.31ID:KClIintl0
>>309
会社の資産でもなんでもないけど?
1から自分で休日に作ってるんだけど?会社で使うものでもないんでw
0320デフォルトの名無しさん (ワッチョイ e36d-S3Tg)
垢版 |
2019/10/17(木) 10:14:17.57ID:V7Fv8DAn0
結局、表入力が簡単で確実なんだよな
なんつか心配がいらない
処理はpythonのほうが楽だがエクセル
ファイルのみで管理できるってことも含め
総合的にはVBAいいんだよね 雑な意味で
データと処理が一つにまとまってるんで
オブジャクト思考的ってか
0322デフォルトの名無しさん (ワッチョイ e36d-S3Tg)
垢版 |
2019/10/17(木) 10:39:10.24ID:V7Fv8DAn0
API呼び出せるんだから
大概のことはVBAでどうにか
なってしまうんだよな。小さい会社、つまり
会社の9割以上はVBA程度で
十分なんだよな まあVBAがおもちゃで
なくてはならないって立場は分からんでもないがw
0323デフォルトの名無しさん (ワッチョイ 2701-Maid)
垢版 |
2019/10/17(木) 15:37:20.74ID:e7g1u0+T0
エクセルの表から始まる作業ならVBAがいいとおもうよ
例えば客からの電話注文をエクセルに一度まとめていて、それを管理画面に反映させる作業とか・・・
スクリプトを動かす必要のないサイトならブラウザ開かずにボタンポチで完了するし
(いつもちゃんと登録されてるのか不安がられるが)
0326デフォルトの名無しさん (ササクッテロ Sp47-F9Df)
垢版 |
2019/10/17(木) 18:09:32.12ID:p8i0Yvjup
まぁVBAやって育ってくるとその内
VB.Netとかやるようになって
Web系を扱うようになると
ASP.Netとかやる機会も出て来るから
SQLと同じようにHTMLとかCSSとか
JavaScriptとか必要に迫られて
片手間で覚えるようになるから大丈夫。

別に今のままで良ければそのまま
VBAやってればいいわけだし。
0327デフォルトの名無しさん (ワッチョイ 9f94-vCPd)
垢版 |
2019/10/17(木) 19:58:00.62ID:EDPspb6d0
VBAの最大のデメリットは何でもVBAでやろうとする脳になる事
こんな化石のような言語でやるのは苦行そのもの
今更覚える意味すらない
0329デフォルトの名無しさん (ワッチョイ 9ec6-GDtP)
垢版 |
2019/10/17(木) 20:41:45.44ID:j32AuqLC0
>>322
さすがにエクセルで納品ってわけにいかないから
適当にインターフェースつくるが中身はVBAで
十分ってのはあるな

>>327
そんなに言語仕様クソか?
小綺麗にまとまってると思うけどな
純粋さはないが使い勝手は悪くない
0330デフォルトの名無しさん (ワッチョイ f335-S3Tg)
垢版 |
2019/10/17(木) 20:55:38.52ID:a6vhi3mO0
時代遅れ感があるのと、どう書くべきかが分かりにくいのと、エラーメッセージがクソなのを除けばそこまででもないな
シートモジュールやブックモジュールが邪魔すぎる。標準モジュールだけで良かった
そしてエラーメッセージの「修正:式」はあまりに不親切。ここはアップデートかけてくれてもいいのに
0332デフォルトの名無しさん (ワッチョイ 92da-GDtP)
垢版 |
2019/10/17(木) 21:18:35.64ID:uSN2w5EG0
>どう書くべきかが分かりにくいのと

それは言語の問題じゃない。

英語の文法はわかりにくい → そりゃお前が日本人だからそう思うだけだろ!
日本語の文法はわかりにくい → そりゃお前がアメリカ人だからそう思うだけだろ!
0336デフォルトの名無しさん (ワッチョイ f335-S3Tg)
垢版 |
2019/10/17(木) 23:08:12.09ID:a6vhi3mO0
そう、オブジェクトが何か分かっていれば何の問題もない
しかし現実問題、Excelを使うのは一般事務。setっていつ使うのかなかなか理解できない層が中心なのだ
0337デフォルトの名無しさん (アークセー Sx47-vS/Z)
垢版 |
2019/10/17(木) 23:49:25.80ID:lelQayoPx
implementsステートメントで組み込みのワークシートオブジェクトのインターフェースを継承すればシート用モジュールになります、って感じの仕組みならよかったよな
ユーザー定義クラスだって属性宣言を先頭に持って来ればクラス用モジュールになりますって感じの扱いで良かったし
0344デフォルトの名無しさん (ササクッテロル Sp47-5sgQ)
垢版 |
2019/10/18(金) 12:32:43.64ID:xgSV8V5dp
>>343
そんなこと言わんと
VBAをとっとと卒業してC#辺りに入りなさいな。
他の言語も勉強するとVBAのコードの組み方もガラッと変わるよ。

例えば.Net系をやればクラスやインターフェースの理解がグッと深まるから
テスト項目も減らせる組み方が出来るし、変更点の改修も少ない組み方が出来るようになる。
0349デフォルトの名無しさん (ワッチョイ f345-UkKt)
垢版 |
2019/10/18(金) 14:34:31.34ID:C4vTbpVj0
2つ質問させてください

Sub Main()
Dim n As Long
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws1cell As Range
Dim r As Long
Set ws1 = Worksheets(1)
Set ws2 = Worksheets(Worksheets.Count)
n = ws1.Cells(Rows.Count, 5).End(xlUp).Row + 5
For r = 1 To ws2.Cells(Rows.Count, 5).End(xlUp).Row
Set ws1cell = ws1.Range("E:E").Find(ws2.Cells(r, 5).Value, lookat:=xlWhole)'項目名が違い、達成率が100%でない場合は開始日・終了日・達成率を更新
If ws1cell Is Nothing And ws2.Cells(r, 10) < 1 Then
ws1cell.Range(ws1.Cells(n, 8), ws1.Cells(n, 10)).Value = ws2.Range(ws2.Cells(r, 8), ws2.Cells(r, 10)).Value
n = n + 1
Else'達成度が進んだ場合は開始日・終了日・達成度を更新
If ws1cell.Value = ws2.Cells(r, 5).Value And ws1cell.Offset(0, 3) < ws2.Cells(r, 8) Then
ws1cell.Offset(0, 3) = ws2.Cells(r, 8)
ws1cell.Offset(0, 4) = ws2.Cells(r, 9)
ws1cell.Offset(0, 5) = ws2.Cells(r, 10)
End If
End If
Next r
End Sub
項目名が違う時にエラーが出てしまいます
If ws1cell is nothingの部分で変数を解放しているから問題なのかと考えていましたが、ws1cell = "" , 0に書き換えてもウォッチウィンドウで見ると
set ws1cellを通った後もnothingのままになっていました
setを通れば変数を定義出来ると思っていたのですが、どのようにすれば解決できますか?
よろしくお願いします
0350デフォルトの名無しさん (ワッチョイ f345-UkKt)
垢版 |
2019/10/18(金) 14:35:51.85ID:C4vTbpVj0
改行エラーが出てしまったため2つに分けました
VBAを使い始めて1ヶ月弱なのですがC#でエクセルを操作出来るようになりたいと考えております
VBAで作ったプログラムを元にして、C#を学ぶ方法は無いでしょうか?
書き方が全然違うとの話を聞いたので、諦めて最初から覚えるしかないかと途方に暮れております
よろしくお願いします
■ このスレッドは過去ログ倉庫に格納されています

ニューススポーツなんでも実況