ページ 1 / 2
検索終ったあとのINIへの書込み
Posted: 2006年12月28日(木) 23:12
by 雷電
検索機能を最近追加しましたが、履歴機能を追加したいと思っていました。
しかし、いざ実装してみても、ちゃんと思うように動いてくれません。
上手くいかないコード [ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
Dim Count=0 As Long
Dim Ending_String As String
Sub FindStr_CommandButton1_Click()
Dim FindString As String
Dim buffer As String
Dim MOJISU As Long
Dim nPos As Long
Dim length As Long
buffer=GetDlgItemTextStr(hMainWnd,EditBox1)
FindString=GetDlgItemTextStr(hFindStr,ComboBox1)
If Ending_String="" Then
Ending_String=FindString
Else
If InStr(0,Ending_String,FindString)=0 Then
Ending_String=Ending_String + Ex"\r\n" + FindString
Else
Ending_String=Ending_String
End If
End If
nPos=InStr(Count+1,buffer,FindString)-1
If nPos<0 Then
MessageBox(hFindStr,"指定された文字列はありません","エラー",MB_OK)
Count=0
Exit Sub
End If
length=nPos + Len(FindString)
Count=length
SendMessage(GetDlgItem(hMainWnd,EditBox1),EM_SETSEL,nPos,length)
SendMessage(GetDlgItem(hMainWnd,EditBox1),EM_SCROLLCARET,0,0)
SetFocus(GetDlgItem(hMainWnd,EditBox1))
End Sub
検索ウィンドウを閉じる際に、INIへ書込みするようにしています。
閉じる際にする処理 [ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
Sub FindStr_CommandButton3_Click()
Dim OK_NO As Long
OK_NO=WritePrivateProfileString("Main","FindStr",Ending_String,".\findstr.ini")
If OK_NO=0 Then
MessageBox(hFindStr,"INIの書き込みに失敗しました","エラー",0)
EndDialog(hFindStr,0)
Else
EndDialog(hFindStr,1)
End If
End Sub
こうなっていますが、初めの部分がおかしいのかなという風に思っています。
どこがおかしいのでしょうか?
また、読み込む際にはどうしたらいいでしょう?
返信@yu0627
Posted: 2006年12月29日(金) 17:17
by yu0627
どのように動かしたいのでしょうか?また、どこがうまくいかないのでしょうか?
とりあえずコードをたどっていくと、
コード: 全て選択
検索文字列を履歴バッファに追加
↓
文字列を検索
↓
検索して文字列があったならそれを選択してその位置までスクロール
だと思いますが...。
とりあえず気になったところを挙げていきます。
その1コード: 全て選択
If InStr(0,Ending_String,FindString)=0 Then
Ending_String=Ending_String + Ex"\r\n" + FindString
Else
Ending_String=Ending_String
End If
この部分のElseはいらないと思います。
その2コード: 全て選択
length=nPos + Len(FindString)
Count=length
SendMessage(GetDlgItem(hMainWnd,EditBox1),EM_SETSEL,nPos,length)
SendMessage(GetDlgItem(hMainWnd,EditBox1),EM_SCROLLCARET,0,0)
SetFocus(GetDlgItem(hMainWnd,EditBox1))
これではもし英数字と日本語が検索文字列に混在する時に選択位置がずれてしまいます。
選択する位置の指定は文字単位なので1Byte文字(=英数字)と2Byte(=日本語)は同じ一文字として認識されます。
もうひとつ。INIファイルに書き込む文字列に改行コードはどうかと...。
あと、INIファイルからの読み出し方ですが、以下のAPIを使います。
コード: 全て選択
'指定のINIファイルから整数値を取得する
'戻り値
' 正常終了のとき 指定のキーに対応した整数値
' 指定のキーがない場合 nDefaultが戻る
' キーの値が整数値でない場合 0
Declare Function GetPrivateProfileInt Lib "Kernel32.dll" Alias "GetPrivateProfileIntA" _
(lpszAppName As BytePtr, 'セクション名
lpszKeyName As BytePtr, 'キー名
nDefault As Long, '指定のキーが見つからない場合のデフォルトの数値
lpszFileName As BytePtr 'INIファイル名
) As Long
'指定のINIファイルから文字列を取得する
'戻り値
' 正常終了のとき バッファにコピーしたバイト数
' nSizeが不十分なとき nSize-2
'備考
' INIファイルをフルパス名で指定しないときWindowsディレクトリを検索する
' lpKeyNameにvbNullStringを設定すると、このセクション全ての全てのキーが取得できる
Declare Function GetPrivateProfileString Lib "Kernel32.dll" Alias "GetPrivateProfileStringA" _
(lpszAppName As BytePtr, 'セクション名
lpszKeyName As BytePtr, 'キー名
lpszDefault As BytePtr, 'キー名が見つからない場合のデフォルトの文字列
lpszReturnedString As BytePtr, '(戻り値)文字列を受け取るバッファ
nSize As Long, '同、サイズ
lpszFileName As BytePtr, 'INIファイル名
) As Long
GetPrivateProfileIntでは数値を、
GetPrivateProfileStringでは文字列を取得します。
使い方はまた今度書きます。
Posted: 2006年12月29日(金) 17:29
by 雷電
yu0627 さんが書きました:その2
コード: 全て選択
length=nPos + Len(FindString)
Count=length
SendMessage(GetDlgItem(hMainWnd,EditBox1),EM_SETSEL,nPos,length)
SendMessage(GetDlgItem(hMainWnd,EditBox1),EM_SCROLLCARET,0,0)
SetFocus(GetDlgItem(hMainWnd,EditBox1))
これではもし英数字と日本語が検索文字列に混在する時に選択位置がずれてしまいます。
選択する位置の指定は文字単位なので1Byte文字(=英数字)と2Byte(=日本語)は同じ一文字として認識されます。
英数字と日本語でも大丈夫です。
こっちの環境では正常に動いています。
例えば
raiden雷電
を、多い文字列の中から探そうと思っても、普通にその部分が選択されています。
このことに関しては問題ないと思います。
返信@yu0627
Posted: 2006年12月29日(金) 17:32
by yu0627
英数字と日本語でも大丈夫です。
こっちの環境では正常に動いています。
ではどのあたりが思い通りに動かないのでしょうか。
こちらでは実行していないので分かりかねますが...。
Posted: 2006年12月29日(金) 17:35
by 雷電
検索した文字列をどう保存すれば、次に検索したときに、またコンボボックスに全て入っているのか、ということです。
こんな文章だけで、すいません。
それを、改行コードで解決させようとしたのですが、できないわけです。
返信@yu0627
Posted: 2006年12月29日(金) 17:44
by yu0627
検索した文字列をどう保存すれば、次に検索したときに、またコンボボックスに全て入っているのか、ということです。
こんな文章だけで、すいません。
それを、改行コードで解決させようとしたのですが、できないわけです。
改行コードでは無理ですね....。
今はまだプログラムを書く暇がありませんので、筋道だけ書いておきます。
今日のうちに追ってプログラムはアップしたいと思います。
---保存時---
1、検索履歴の追加はこのままで
2、保存時に改行コードごとに検索文字列をばらす
3、検索文字列の数を数え、それをINIファイルに記録する
4、それぞれの検索文字列をひとつずつINIファイルに記録する
セクション名は例えば「FindString○○(○○に通し番号)」にする
---読み込み時---
1、INIファイルから検索文字列の数を取得
2、検索文字列を順番にINIファイルから取得して[SendDlgItemMessage(親ウインドウのハンドル, コンボボックスのハンドル, CB_ADDSTRING, 0, 検索文字列)]でコンボボックスに検索文字列を追加する。
こんな感じでいけると思います。
ではまた。
Re: 返信@yu0627
Posted: 2006年12月29日(金) 17:49
by 7
> これではもし英数字と日本語が検索文字列に混在する時に選択位置がずれてしまいます。
> 選択する位置の指定は文字単位なので1Byte文字(=英数字)と2Byte(=日本語)は同じ一文字として認識されます。
C++言語のサンプルコードでも以下のようになっています。
コード: 全て選択
SendMessage(hEdit,EM_SETSEL,dwPos,strlen(lpfr->lpstrFindWhat)+dwPos);
他のトピックで他の方も同じようなことを仰ってましたけど、その情報はどこに書いてあるんでしょう?
複数の方がそう思っているということはどこかにそう説いている物があると思うんですけど、特に見当たりません...。
EM_SETSELはたしかに「文字列の選択」という機能を持ってますが文字単位の計算ではないはずだと思います。GetWindowTextLength()関数などでも「あ」は2バイトと取得されますよね?
EM_SETSELだけ文字単位の計算なら、GetWindowTextLength()関数の戻り値やlstrlen()関数などで選択範囲を決めようとすると面倒なことになります。
WIN32APIの関数に使われる開始値はすべて(おそらく)
0から始まる値であるのに、ActiveBasicのInStr関数が
1から始まってしまってて、戻り値も
+1されてるので勘違いする方が居ると思うんですよね...。
返信@yu0627
Posted: 2006年12月29日(金) 17:59
by yu0627
すみません。
こちら側で前々にちょっと作ったプログラムを見たところそうでした。
EM_SETSEL、その時以来使っていなかったので多分忘れていました...。
そしてなぜか文字単位の指定というように記憶がなっていました...。
あと、InStrは本当に最初のほうしか使っていません。その後はmemicmpとかlstrcmpを使っています。
#とりあえずプログラムを書いています。
GetDlgItemTextStr関数は申し訳ありませんが使わない予定です...。
Posted: 2006年12月29日(金) 18:13
by 7
INIファイルに書き込まれている項目の数を取得することができないと思うので自分は以下のようにしようと思います。
書き込む場合
- 1.保存時にコンボボックスの項目(文字列)をすべて取得する
2.項目(文字列)と項目(文字列)の間に特殊な文字を挿入し、複数の項目(文字列)を一つの文字列にしてしまう
3.生成された文字列をINIファイルに書き込む
読み込む場合
- 1.INIファイルから文字列を読み込む
2.文字列の中の特殊な文字を判定して複数の文字列に分解する
3.分解された複数の文字列(項目)をコンボボックスの項目として設定する
こんな感じでしょうか。
> GetDlgItemTextStr関数は申し訳ありませんが使わない予定です...。
僕に対して書いてるんでしょうか...?
イグトランスさんが考案された関数ですよ。
返信@yu0627
Posted: 2006年12月29日(金) 18:25
by yu0627
INIファイルに書き込まれている項目の数を取得することができないと思うので自分は以下のようにしようと思います。
う~ん。文が説明不足でした。
INIファイルの中に項目数を書き込んでいるんです...。
そして読み込み時にそれを読み込んで処理するということでした...。
僕に対して書いてるんでしょうか...?
イグトランスさんが考案された関数ですよ。
いえ、雷電さんにです。
とりあえず関数をコピーしてきたので、使用します。
返信@yu0627
Posted: 2006年12月29日(金) 18:59
by yu0627
とりあえずプログラムを組んでみました。
簡略化させるために検索したらすぐINIファイルに追加するようにしましたが、良かったでしょうか?
Yahoo!ブリーフケースから「プログラム名.zip」をダウンロードして、ファイルを解凍してください。
その中にあるプロジェクトファイルがそうです。
(諸事情によりURLは除去いたしました)
一部無駄な処理も入っていますが...。参考にどうぞ。
#久しぶりのString型だった...。
Posted: 2006年12月29日(金) 21:42
by 雷電
コードの提供ありがとうございました。
早速、プログラムを少し、こちらの環境に合わせてやって見ました。
すると
コード: 全て選択
FindStr.sbp(57) - [警告] 一時オブジェクトの解放を行えません。キャスト用オブジェクトを用意してください。
というのが出ました。
しかし、コンパイルは一応終了して、問題なく動きました。
両方、ありがとうございました。
返信@yu0627
Posted: 2006年12月29日(金) 21:57
by yu0627
警告文を見るとAB5.0を利用されているようですね。
今までのプログラムをAB5.0のコンパイラに通してみたらかなりエラーが出るんです...○| ̄|_
すなわち今まで以上に型チェックなどが厳しくなっています。
今後とも頑張って下さい。
あれれ??
Posted: 2006年12月29日(金) 22:29
by 雷電
[ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
Sub FindStr_CommandButton1_Click()
Dim FindString As String '検索文字列
Dim buffer As String 'EditBox1の文字列
Dim nPos As Long
Dim Length As Long '
'検索文字列を取得
FindString=GetDlgItemTextStr(hFindStr,ComboBox1)
'EditBox1の文字列を取得
buffer=GetDlgItemTextStr(hMainWnd,EditBox1)
If InStr(0, FindStringHistory, FindString) = -1 Then
'検索履歴バッファに検索文字列が無かった時
Dim lpstrKeyName[255] As Byte '気にしなくて良い
'検索文字列をINIファイルに追加
WritePrivateProfileString("FindString", "NumOfFindString", Str$(NowFindStringNum), ".\findstr.ini")
wsprintf(lpstrKeyName, "FindString(%d)", NowFindStringNum)
WritePrivateProfileString("FindString", lpstrKeyName, StrPtr(FindString), ".\findstr.ini")
NowFindStringNum++
'検索履歴バッファに検索文字列を追加
FindStringHistory = FindStringHistory + Ex"\r\n" + FindString
End If
'検索文字列をEditBox1の内容から検索
nPos = InStr(Count+1, buffer, FindString)-1
If nPos < 0 Then
MessageBox(hFindStr, "指定された文字列はありません", NULL, MB_OK)
Count=0
Exit Sub
End If
'検索文字列を選択してその位置までスクロールさせる
Length=nPos + Len(FindString)
Count=Length
SendMessage(GetDlgItem(hMainWnd,EditBox1), EM_SETSEL, nPos,Length)
SendMessage(GetDlgItem(hMainWnd,EditBox1), EM_SCROLLCARET, 0, 0)
SetFocus(GetDlgItem(hMainWnd, EditBox1))
End Sub
こうしたら、また動かなくなってしまった。
何ゆえ?
返信@yu0627
Posted: 2006年12月30日(土) 00:36
by yu0627
そりゃ動きません(爆
コンボボックスで選択中の文字列はGetDlgItemText(Str)では取得できません。
もう遅いので(日付変わっちゃってるし)、プログラムはバイト終わってから書きます。
夕方になると思います。