EditBoxの追記制限
EditBoxの追記制限
下記の方法でEditBoxに表示(追記)しています。
(過去ログから見つけた方法なので、詳細はわかりませんが・・・)
Dim hEdit As HWND
Dim Len As Long
hEdit=GetDlgItem(hMainWnd,EditBox1)
Len=GetWindowTextLength(hEdit)
SendMessage(hEdit,EM_SETSEL,Len,Len)
SendMessage(hEdit,194,0,writeData As Long)
上記で、永遠と追記していくと、EditBoxの限界点で表示が停止してしまいます。
MAX値を指定し、古い表示を忘れ新しい表示を追記したいのですが、方法を教えてください。
(過去ログから見つけた方法なので、詳細はわかりませんが・・・)
Dim hEdit As HWND
Dim Len As Long
hEdit=GetDlgItem(hMainWnd,EditBox1)
Len=GetWindowTextLength(hEdit)
SendMessage(hEdit,EM_SETSEL,Len,Len)
SendMessage(hEdit,194,0,writeData As Long)
上記で、永遠と追記していくと、EditBoxの限界点で表示が停止してしまいます。
MAX値を指定し、古い表示を忘れ新しい表示を追記したいのですが、方法を教えてください。
どうすれば良いか適当に解説
エディットコントロールにある文字の長さ=length1
追記する文字列の長さ=length2
エディットコントロールの限界値=limit
とします
length1+length2>limitであれば容量を超えてしまって追記できないので
エディットコントロールの内容を確保しておいたバッファ(大きさはlength1+length2+1)に取得
このバッファにlstrcatで追記する文字列を連結
このままWM_SETTEXTでバッファのアドレスを指定するとlength1+length2-limit Byteはみ出してしまうので
SendMessage(エディットコントロールのハンドル,WM_SETTEXT,バッファのアドレス+length1+length2-limit,0)
のように書き込み始めるアドレスをずらす
最後にカーソルを最後尾に持っていく
これでできるはず
とまあここまで書いておいて何なんですが、こんなもん書かなくていいと思う
せっかく人がやる気になってんのにこんなどうでもいい所で不毛なコード書かざるを得なくなるとテンションが下がるしね
(個人的にはこれがABが流行らない根本的な理由だと思ってる)
話が逸れました
プロジェクトに↓を加えて下さい
http://www.2chab.net/uploader/src/up0009.sbp
' TODO: この位置にグローバルな変数、構造体、定数、関数を定義します。
の位置に
Dim pclw As *CLogWindow
を記述
メインウィンドウのCreateイベント内に
pclw = New CLogWindow(GetDlgItem(hMainWnd,エディツトコントロールのID))
を記述
メインウィンドウのDestroyイベント内に
Delete pclw
を記述
後は普通のエディットコントロールと同じように使えるはずです。
上限の設定は
SendMessage(エディットコントロールのハンドル,EM_SETLIMITTEXT,上限サイズ,0)
でできます
デフォルトは32KByte=32*1024Byteです
エディットコントロールにある文字の長さ=length1
追記する文字列の長さ=length2
エディットコントロールの限界値=limit
とします
length1+length2>limitであれば容量を超えてしまって追記できないので
エディットコントロールの内容を確保しておいたバッファ(大きさはlength1+length2+1)に取得
このバッファにlstrcatで追記する文字列を連結
このままWM_SETTEXTでバッファのアドレスを指定するとlength1+length2-limit Byteはみ出してしまうので
SendMessage(エディットコントロールのハンドル,WM_SETTEXT,バッファのアドレス+length1+length2-limit,0)
のように書き込み始めるアドレスをずらす
最後にカーソルを最後尾に持っていく
これでできるはず
とまあここまで書いておいて何なんですが、こんなもん書かなくていいと思う
せっかく人がやる気になってんのにこんなどうでもいい所で不毛なコード書かざるを得なくなるとテンションが下がるしね
(個人的にはこれがABが流行らない根本的な理由だと思ってる)
話が逸れました
プロジェクトに↓を加えて下さい
http://www.2chab.net/uploader/src/up0009.sbp
' TODO: この位置にグローバルな変数、構造体、定数、関数を定義します。
の位置に
Dim pclw As *CLogWindow
を記述
メインウィンドウのCreateイベント内に
pclw = New CLogWindow(GetDlgItem(hMainWnd,エディツトコントロールのID))
を記述
メインウィンドウのDestroyイベント内に
Delete pclw
を記述
後は普通のエディットコントロールと同じように使えるはずです。
上限の設定は
SendMessage(エディットコントロールのハンドル,EM_SETLIMITTEXT,上限サイズ,0)
でできます
デフォルトは32KByte=32*1024Byteです
文字列を追加したいっていう要望は今までに何回かありましたけど、文字列を追加したいけどはみ出る、そんな場合先頭の文字列を切り捨てていきたいっていう要望は今までありませんでしたね。
エディットボックス大好き人間、ここはオレの出番だろぉぉぉぉ、という訳で関数を作ってみました。
関数の名前はちょっと適当です...。
原理というかはゲストさんの説明を読めばなんとなく分かるのではないかと。
追記。
何か忘れてる気がすると思ったら、操作できるバイト数より追加する文字列のバイト数が大きかった場合の処理をしてなかったので修正しました。
エディットボックス大好き人間、ここはオレの出番だろぉぉぉぉ、という訳で関数を作ってみました。
関数の定義 [ここをクリックすると内容が表示されます]
コード: 全て選択
' エディットボックスに文字列を追加
Function Edit_AddText(ByVal hWnd As HWND,ByVal lpString As LPSTR,ByVal bUndo As BOOL) As BOOL
SendMessage(hWnd,EM_SETSEL,GetWindowTextLength(hWnd),-1)
Return SendMessage(hWnd,EM_REPLACESEL,bUndo,lpString As LPARAM) As BOOL
End Function
' エディットボックスで操作できる文字列のバイト数を取得
Function Edit_GetLimitText(ByVal hWnd As HWND) As Long
Return SendMessage(hWnd,EM_GETLIMITTEXT,0,0) As Long
End Function
' エディットボックスに文字列を追加、はみ出る場合先頭の文字列を捨てる
Function Edit_AddTextEx(ByVal hWnd As HWND,ByVal lpString As LPSTR) As BOOL
Dim lpStr As LPSTR
Dim length[1] As Long, limit As Long
limit=Edit_GetLimitText(hWnd)
length[0]=GetWindowTextLength(hWnd)
length[1]=lstrlen(lpString)
If length[1]>limit Then
Return SetWindowText(hWnd,lpString+length[1]-limit)
End If
If (length[0]+length[1])>limit Then
lpStr=malloc(length[0]+1)
GetWindowText(hWnd,lpStr,length[0]+1)
SetWindowText(hWnd,lpStr+length[0]+length[1]-limit)
free(lpStr)
End If
Return Edit_AddText(hWnd,lpString,TRUE)
End Function
コード: 全て選択
' コマンドボタン1が押された時に文字列を追加します
Sub MainWnd_CommandButton1_Click()
Edit_AddTextEx(GetDlgItem(hMainWnd,EditBox1),"追加したい文字列")
End Sub
原理というかはゲストさんの説明を読めばなんとなく分かるのではないかと。
追記。
何か忘れてる気がすると思ったら、操作できるバイト数より追加する文字列のバイト数が大きかった場合の処理をしてなかったので修正しました。
ゲスト様
ありがとうございます。
試しましたが、コンパイル時にDestroyイベントにて追加した行でエラーが出ます。
>Delete pclw
MainWnd.sbp(61) - 定数式にリテラル値、または定数以外のものが含まれています
MainWnd.sbp(61) - Delete演算子にポインタ以外の型が指定されています
よろしくお願いします。
------------------------------
7様
ありがとうございます。
試しましたが、コンパイルは正常に終了しますが実行時にエラーがでます。
コンパイラのエラー
スレッド(&h17FC)でアクセス違反がありました(EPI=&H0012CF98)
function.sbp 316行
>_Support_tan=x/(1-t)
Windowsのエラー
BasicCompiler.exeは動作を停止しました。
問題が発生したため、プログラムが正しく動作しなくなりました。・・・
トレースすると、Edit_GetLimitText()からfunction.sbpに行きエラーに
なっている様子です。
>Function Edit_AddTextEx(ByVal hWnd As HWND,ByVal lpString As LPSTR) As BOOL
>Dim lpStr As LPSTR
>Dim length[1] As Long, limit As Long
>
>limit=Edit_GetLimitText(hWnd)
使用OS:WindowsVista HomePremium
よろしくお願いします。
ありがとうございます。
試しましたが、コンパイル時にDestroyイベントにて追加した行でエラーが出ます。
>Delete pclw
MainWnd.sbp(61) - 定数式にリテラル値、または定数以外のものが含まれています
MainWnd.sbp(61) - Delete演算子にポインタ以外の型が指定されています
よろしくお願いします。
------------------------------
7様
ありがとうございます。
試しましたが、コンパイルは正常に終了しますが実行時にエラーがでます。
コンパイラのエラー
スレッド(&h17FC)でアクセス違反がありました(EPI=&H0012CF98)
function.sbp 316行
>_Support_tan=x/(1-t)
Windowsのエラー
BasicCompiler.exeは動作を停止しました。
問題が発生したため、プログラムが正しく動作しなくなりました。・・・
トレースすると、Edit_GetLimitText()からfunction.sbpに行きエラーに
なっている様子です。
>Function Edit_AddTextEx(ByVal hWnd As HWND,ByVal lpString As LPSTR) As BOOL
>Dim lpStr As LPSTR
>Dim length[1] As Long, limit As Long
>
>limit=Edit_GetLimitText(hWnd)
使用OS:WindowsVista HomePremium
よろしくお願いします。
> >>ActiveBasicのバージョンはなんでしょう?
>
> 4.24です。
互換性の問題でしたね。
>
> 4.24です。
互換性の問題でしたね。
Ver 4.24向け [ここをクリックすると内容が表示されます]
コード: 全て選択
Function Edit_AddText(ByVal hWnd As HWND,ByVal lpString As LPSTR,ByVal bUndo As BOOL) As BOOL
SendMessage(hWnd,EM_SETSEL,GetWindowTextLength(hWnd),-1)
Edit_AddText=SendMessage(hWnd,EM_REPLACESEL,bUndo,lpString As LPARAM) As BOOL
End Function
Function Edit_GetLimitText(ByVal hWnd As HWND) As Long
Edit_GetLimitText=SendMessage(hWnd,EM_GETLIMITTEXT,0,0) As Long
End Function
Function Edit_AddTextEx(ByVal hWnd As HWND,ByVal lpString As LPSTR) As BOOL
Dim lpStr As LPSTR
Dim length[1] As Long, limit As Long
limit=Edit_GetLimitText(hWnd)
length[0]=GetWindowTextLength(hWnd)
length[1]=lstrlen(lpString)
If length[1]>limit Then
Edit_AddTextEx=SetWindowText(hWnd,lpString+length[1]-limit)
Exit Function
End If
If (length[0]+length[1])>limit Then
lpStr=malloc(length[0]+1)
GetWindowText(hWnd,lpStr,length[0]+1)
SetWindowText(hWnd,lpStr+length[0]+length[1]-limit)
free(lpStr)
End If
Edit_AddTextEx=Edit_AddText(hWnd,lpString,TRUE)
End Function
7様
ありがとうございます。
無事動きました。
教えて頂いたコードに、コントロールコードであれば<02>の様に表示する機能を追加してみました。
1、メモリ確保の方法が悪く、大量のコントロールコードでメモリが溢れる。
何か良い解決策は有りませんか?
2、なぜか、free(dummy)を実行するとEXEが落ちる。
宜しくお願いいたします。
ありがとうございます。
無事動きました。
教えて頂いたコードに、コントロールコードであれば<02>の様に表示する機能を追加してみました。
[ここをクリックすると内容が表示されます]
一応は動くのですが、以下の対策を教えてください。コード: 全て選択
Function Edit_AddTextEx(ByVal hWnd As HWND,ByVal lpString As LPSTR) As BOOL
Dim lpStr As LPSTR
Dim length[1] As Long, limit As Long
limit=Edit_GetLimitText(hWnd)
length[0]=GetWindowTextLength(hWnd)
length[1]=lstrlen(lpString)
Dim dummy As BytePtr
Dim I As Long
Dim tp[9] As Byte
Dim tmp[9] As Byte
dummy = calloc(lstrlen(lpString)*2) :'不安定要因 対策が必用。
For I = 0 To lstrlen(lpString) -1
memcpy(tp ,lpString + I , 1)
'cr/lfを除くコントロールコードであれば"<01>"の様に表示する。
If tp[0] < &h1f And tp[0] <> &hd And tp[0] <> &ha Then
wsprintf(tmp , "<%02x>" , tp[0])
lstrcat(dummy , tmp)
Else
lstrcat(dummy , tp)
End If
Next
length[1]=lstrlen(dummy)
If length[1]>limit Then
Edit_AddTextEx=SetWindowText(hWnd,dummy+length[1]-limit)
Exit Function
End If
If (length[0]+length[1])>limit Then
lpStr=malloc(length[0]+1)
GetWindowText(hWnd,lpStr,length[0]+1)
SetWindowText(hWnd,lpStr+length[0]+length[1]-limit)
free(lpStr)
End If
Edit_AddTextEx=Edit_AddText(hWnd,dummy,TRUE)
' free(dummy) :'メモリを開放するとEXEが落ちる!!
End Function
1、メモリ確保の方法が悪く、大量のコントロールコードでメモリが溢れる。
何か良い解決策は有りませんか?
2、なぜか、free(dummy)を実行するとEXEが落ちる。
宜しくお願いいたします。
まだ実行していないので詳しい事は全く言えないんですが、callocの下のlstrcatは文字列が長くなると重くなるので、dummy_length等の名前で現在の文字の長さを保管しながらmemcpyした方が安定します。
あと、それより前にForブロックがあるんですが、Toの値は関数にしないほうがいいです。実行速度低下の要因になります。
メモリ確保量の問題は、溢れそうになったらreallocするとか、あるいは全てが変換対象のコードだった場合を想定してメモリを元の文字列の4~5倍の大きさ、確保するとか、他にも変換する個数を予め数えてから確保し、変換を開始するなど。
日本語文字列に対するチェックが甘すぎるようですが・・・。
それと、途中で抜ける時にどうもfreeし忘れているように見えるんですが・・・。
freeについては、原因が解りません。
コード: 全て選択
'before
lstrcat(dummy , tp)
'after
Dim dummy_length As Long
memcpy(dummy+dummy_length,tp,lstrlen(tp))
dummy_length+=lstrlen(tp)
コード: 全て選択
'before
For I = 0 To lstrlen(lpString) -1
'after
Dim lpStringLength As Long
lpStringLength=lstrlen(lpString)-1
For I = 0 To lpStringLength
日本語文字列に対するチェックが甘すぎるようですが・・・。
それと、途中で抜ける時にどうもfreeし忘れているように見えるんですが・・・。
freeについては、原因が解りません。
Website→http://web1.nazca.co.jp/himajinn13sei/top.html
ここ以外の場所では「暇人13世」というHNを主として使用。
に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
ここ以外の場所では「暇人13世」というHNを主として使用。
に署名を書き換えて欲しいと言われたので暇だしやってみるテスト。
これから仕事なので細かくチェックしてないのですが以下のように書いてみました。
まずは文字列の置換関数を考えてみた方がスッキリするかもしれません。
[ここをクリックすると内容が表示されます]
要は、指定された文字列の中に含まれる制御コードをパっと目に見える形に置換したいっていう要望ですよね。コード: 全て選択
Function Edit_AddTextEx(ByVal hWnd As HWND,ByVal lpString As LPSTR) As BOOL
Dim lpStr As LPSTR
Dim length[1] As Long, limit As Long
Dim cnt As Long
Dim dummy As BytePtr, tmp[9] As Byte
limit=Edit_GetLimitText(hWnd)
length[0]=GetWindowTextLength(hWnd)
length[1]=lstrlen(lpString)
' lpStringがタブ文字だけの1バイトだったとすると
' 必要なメモリは4バイト必要
' lpStringがタブ文字だけの2バイトだったとすると
' 必要なメモリは8バイト必要
' それとNULL文字分の1バイトが必要
dummy = calloc(lstrlen(lpString)*4+1)
For cnt = 0 To length[1]-1
If IsDBCSLeadByte(lpString[cnt]) Then
memcpy(VarPtr(dummy[lstrlen(dummy)]),VarPtr(lpString[cnt]),2)
cnt++
Else
If (lpString[cnt] < &h1f) And (lpString[cnt] <> &hd) And (lpString[cnt] <> &ha) Then
wsprintf(tmp,"<%02x>",lpString[cnt])
memcpy(VarPtr(dummy[lstrlen(dummy)]),tmp,lstrlen(tmp))
Else
dummy[lstrlen(dummy)]=lpString[cnt]
End If
End If
Next
length[1]=lstrlen(dummy)
If length[1]>limit Then
Edit_AddTextEx=SetWindowText(hWnd,dummy+length[1]-limit)
free(dummy)
Exit Function
End If
If (length[0]+length[1])>limit Then
lpStr=malloc(length[0]+1)
GetWindowText(hWnd,lpStr,length[0]+1)
SetWindowText(hWnd,lpStr+length[0]+length[1]-limit)
free(lpStr)
End If
Edit_AddTextEx=Edit_AddText(hWnd,dummy,TRUE)
free(dummy)
End Function
まずは文字列の置換関数を考えてみた方がスッキリするかもしれません。
> 要は、指定された文字列の中に含まれる制御コードをパっと目に見える形に置換したいっていう要望ですよね。
> まずは文字列の置換関数を考えてみた方がスッキリするかもしれません。
朝はちょっと考えが浅くてオススメしただけだったんですが、やっぱり特定の制御コードだけを別の文字列に換えるような関数を作った方がいいと思います。
今回作った Edit_AddTextEx という関数はテキストボックスに文字列を追加し、エディットボックスが操作できる容量を超えるようだったらその分先頭の文字列を切り捨てるという関数ですが、この関数の中に他のことをするようなコードを潜り込ませるのはあまりいい事ではありません。
いくつかの関数をまとめて一つの関数にするメリットはいくつかありますが、その一つ、「コードの再利用」という目的から離れて行ってしまっているからです。(僕個人の考えですけど)
あと、「制御コードを別の文字列に変換し、その文字列をエディットボックスに追加する。エディットボックスの容量以上になる場合、先頭文字列を切り捨てる」
という関数は非常に有効範囲が狭く応用が利きません。
「制御コード(特定の文字列)を別の文字列に変換する」
「文字列をエディットボックスに追加する。エディットボックスの容量以上になる場合、先頭文字列を切り捨てる」
こういう風に役目毎に関数を切り分けることで応用が利きやすくなります。
質問の内容と関係ない説明でウザいかもしれませんね...。
追記。
ハンドルネームについても一つ。
あなたは今までに投稿してきた「初心者」さんと同一人物ですか?
あまり考える必要はありませんがちょくちょくかぶったり、かぶるようなハンドルネームはちょっと...。
もし次に新しいトピックを作る場合、もうちょっとユニークなハンドルネームでお願いします。
> まずは文字列の置換関数を考えてみた方がスッキリするかもしれません。
朝はちょっと考えが浅くてオススメしただけだったんですが、やっぱり特定の制御コードだけを別の文字列に換えるような関数を作った方がいいと思います。
今回作った Edit_AddTextEx という関数はテキストボックスに文字列を追加し、エディットボックスが操作できる容量を超えるようだったらその分先頭の文字列を切り捨てるという関数ですが、この関数の中に他のことをするようなコードを潜り込ませるのはあまりいい事ではありません。
いくつかの関数をまとめて一つの関数にするメリットはいくつかありますが、その一つ、「コードの再利用」という目的から離れて行ってしまっているからです。(僕個人の考えですけど)
あと、「制御コードを別の文字列に変換し、その文字列をエディットボックスに追加する。エディットボックスの容量以上になる場合、先頭文字列を切り捨てる」
という関数は非常に有効範囲が狭く応用が利きません。
「制御コード(特定の文字列)を別の文字列に変換する」
「文字列をエディットボックスに追加する。エディットボックスの容量以上になる場合、先頭文字列を切り捨てる」
こういう風に役目毎に関数を切り分けることで応用が利きやすくなります。
質問の内容と関係ない説明でウザいかもしれませんね...。
追記。
ハンドルネームについても一つ。
あなたは今までに投稿してきた「初心者」さんと同一人物ですか?
あまり考える必要はありませんがちょくちょくかぶったり、かぶるようなハンドルネームはちょっと...。
もし次に新しいトピックを作る場合、もうちょっとユニークなハンドルネームでお願いします。
最後に編集したユーザー 7 [ 2007年4月20日(金) 18:06 ], 累計 1 回