- PR -

ListBoxのオーナードロー(OwnerDrawVariable)でスクロールが逆方向に見える

投稿者投稿内容
ジブ
大ベテラン
会議室デビュー日: 2005/09/22
投稿数: 135
投稿日時: 2005-11-25 21:29
こんにちは。

ListBoxのオーナードロー(OwnerDrawVariable)でスクロールが逆方向に見える現象が直りません。

フォームにListBoxを貼り付けて、DrawModeをOwnerDrawVariableとして、以下のコードを追加します。

コード:

Private Sub ListBox1_MeasureItem(ByVal sender As Object, ByVal e As System.Windows.Forms.MeasureItemEventArgs) Handles ListBox1.MeasureItem
e.ItemHeight = 15
End Sub

Private Sub ListBox1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles ListBox1.DrawItem
If e.Index < 0 Then Exit Sub

If ListBox1.SelectedIndex = e.Index Then
e.Graphics.FillRectangle(Brushes.Aqua, e.Bounds)
Else
e.Graphics.FillRectangle(Brushes.LightGray, e.Bounds)
End If
e.Graphics.DrawString(e.Index.ToString, ListBox1.Font, Brushes.Black, e.Bounds.X + 10, e.Bounds.Y + 1)


End Sub

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load

For i As Integer = 0 To 99
ListBox1.Items.Add(i)
Next
ListBox1.SelectedIndex = 0

End Sub

Private Sub ListBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
ListBox1.Invalidate()
End Sub



下へスクロールするときに水色の部分が逆方向へ動いているように見えます。
この現象はOwnerDrawFixedの場合は起きません。

なんとか方法はないものでしょうか?

[ メッセージ編集済み 編集者: ジブ 編集日時 2005-11-25 21:32 ]
ジブ
大ベテラン
会議室デビュー日: 2005/09/22
投稿数: 135
投稿日時: 2005-11-30 23:09
この現象は、なんともしがたいのでしょうか?

高さを可変にして自分でDrawしようとする場合は別なコントロールを使用すべきなのでしょうか?

それともそもそも無理なものなのでしょうか?

すべて自前で作るとすれば、どういう手順が必要になるのでしょうか?

それとも、なにか大きな勘違いをしているのかな???
未記入
大ベテラン
会議室デビュー日: 2005/03/12
投稿数: 148
投稿日時: 2005-12-01 00:23
たしかWindowsがウィンドウをアニメーション的に最大化したり、
スムースなスクロールとかするようになってから
よく見かけるようになった現象ですよね。
違ったかな?
それまでオーナードローのアプリが少なかっただけかな。

別の掲示板で同じ質問見たことある。
そこでは完璧ではないが多少改善したらしい。
see 高さ可変オーナードローリストボックスのスクロール挙動
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2005-12-01 00:55
こんばんは。

引用:

ジブさんの書き込み (2005-11-30 23:09) より:
この現象は、なんともしがたいのでしょうか?



実はジブさんのおっしゃる現象を検証するために
ジブさんのコードを実行してみていたのですが、
私の環境では再現しなかったので、回答することを見合わせていました。

OwnerDrawVariableの場合もOwnerDrawFixedの場合も、挙動は同じでした。
特に、スクロールが逆方向に見える現象が起こることはありませんでしたが…
他の皆さんのところはどうなんでしょうね?

引用:

未記入さんの書き込み (2005-12-01 00:23) より:
それまでオーナードローのアプリが少なかっただけかな。



べつにオーナードロー自体は、最近できたテクニックではないですし
今まで極当たり前のように使われてきたはずですけれども。
私も今までWindowsアプリの製品開発では、オーナードローは多用してきてますし、
市販製品だって、オーナードローを見かけない方が稀のように思いますが。
ジブ
大ベテラン
会議室デビュー日: 2005/09/22
投稿数: 135
投稿日時: 2005-12-01 21:10
引用:

未記入さんの書き込み (2005-12-01 00:23) より:

別の掲示板で同じ質問見たことある。
そこでは完璧ではないが多少改善したらしい。
see 高さ可変オーナードローリストボックスのスクロール挙動



ありがとうございました。

.Net のListBoxだとOnVScrollがないかOverridableになっていないようでいろいろ試行錯誤の結果
WndProcでWM_VSCROLLを監視し、一時的に描画を停止して障害を回避しました。

SB_PAGEDOWNの描画で新しいページを下から出なく上から降ろしてしまうという初歩的なバグのようですね。


引用:

Tdnr_Symさんの書き込み (2005-12-01 00:55) より:

実はジブさんのおっしゃる現象を検証するために
ジブさんのコードを実行してみていたのですが、
私の環境では再現しなかったので、回答することを見合わせていました。



わざわざありがとうございました。

未記入さんのご紹介の掲示板でもとりあげられているように
引用:

スクロールバーもつまみやボタンで操作すると問題ないようですが、
つまみとボタンの間をクリック(PAGEUPやPAGEDOWN?)した時に変な動作をしますね
普段使わない部分なので気がつきませんでした



「つまみとボタンの間をクリック」した場合はいかがでしょうか
それともVS.Net2005とかで直っているものでしょうか?

ともかく、応急避難的な対応でなんとかなりました。
ちらつきは仕方ないとあきらめてよしとしようと思います。

また、スムーズスクロールをOffにできるのであればそのほうがよさそうに思ったのですが
ListBoxのプロパティとかにはみつけられませんでした。

それと、副産物としてスクロールがとても早くなりました。
とくにマウスホイールでの動作は耐えられないくらい遅かった(なんであんなに遅いんだろう、不思議なくらい遅い)のですが
いっそ、SB_PAGEDOWNだけでなくすべてのWM_VSCROLLで同様にしたら
(ちらつきをがまんすれば)早くなり、いらいら解消になりました。

いろいろ、ありがとうございました。

未記入
大ベテラン
会議室デビュー日: 2005/03/12
投稿数: 148
投稿日時: 2005-12-01 22:43
引用:

Tdnr_Symさんの書き込み (2005-12-01 00:55) より:

べつにオーナードロー自体は、最近できたテクニックではないですし
今まで極当たり前のように使われてきたはずですけれども。
私も今までWindowsアプリの製品開発では、オーナードローは多用してきてますし、
市販製品だって、オーナードローを見かけない方が稀のように思いますが。



何か最後の発言だけ取り上げて揚げ足取っているみたいだから、言い直そう。

Windowsがスムーズスクロールなどを行うようになった頃から、俺はこの現象を見かけるようになった。

こんなおかしな現象は、大きく取り上げられてもいいはずなのに、情報が少ないんだよな。
一応この現象に触れているものは見たことあるが、オーナードローを行っているプログラマーからの質問や意見や解決策みたいなのはめっちゃ少ない。
理由はなんだろう
* 再現する環境だがオーナードローのプログラミングしない
* 再現する環境だがオーナードローするアプリをもっていないので知らない
こういったことからだろうか。

そういった観点から、オーナードローするアプリが少ないとか、オーナードローのプログラミングする人が少ないと考えました。
# 今は、スムーズスクロールが有効だと再現できると考えているが、プログラムを書いてまで事実確認しようとは思わない。

再現しない環境が多いかどうかは着目していませんでした。
以下の可能性もあるということか
* 再現しない環境だ

さらに
* 再現する環境だがあきらめた、特に取り上げる気にならない
* 俺が質問や意見や解決策を発見できていないだけ
* 実はみんな解決策を知っているが、特に取り上げる気にならない

[ メッセージ編集済み 編集者: 未記入 編集日時 2005-12-01 23:03 ]
ジブ
大ベテラン
会議室デビュー日: 2005/09/22
投稿数: 135
投稿日時: 2005-12-01 23:15
引用:

未記入さんの書き込み (2005-12-01 22:43) より:
こんなおかしな現象は、大きく取り上げられてもいいはずなのに、情報が少ないんだよな。
一応この現象に触れているものは見たことあるが、オーナードローを行っているプログラマーからの質問や意見や解決策みたいなのはめっちゃ少ない。
理由はなんだろう
* 再現する環境だがオーナードローのプログラミングしない
* 再現する環境だがオーナードローするアプリをもっていないので知らない
こういったことからだろうか。

そういった観点から、オーナードローするアプリが少ないとか、オーナードローのプログラミングする人が少ないと考えました。

再現しない環境が多いかどうかは着目していませんでした。
以下の可能性もあるということか
* 再現しない環境だ

さらに
* 再現する環境だがあきらめた、特に取り上げる気にならない
* 俺が質問や意見や解決策を発見できていないだけ
* 実はみんな解決策を知っているが、特に取り上げる気にならない



どうなんでしょう。

私などがMSへ積極的にバグレポートをあげるべきなんでしょうね。
以前別件でなんどかメールを出したこともあったのですが、真剣に考えているのかよくわかりません。
最近はあきらめかけています。いかんですね。

サンプルコードを提示しようかなとも思いましたが、あまりに情けない応急処置なので
とても気恥ずかしく書けずじまいでした。

とりあえずサンプルを

コード:


Imports System.Runtime.InteropServices

Public Class myListBox
Inherits System.Windows.Forms.ListBox

+#Region " Windows フォーム デザイナで生成されたコード "

Const WM_VSCROLL As Integer = &H115I
Const WM_PAINT As Integer = &HFI
Const WM_SETREDRAW As Integer = &HBI

Const SB_LINEUP As Short = &H0S
Const SB_LINELEFT As Short = &H0S
Const SB_LINEDOWN As Short = &H1S
Const SB_LINERIGHT As Short = &H1S
Const SB_PAGEUP As Short = &H2S
Const SB_PAGELEFT As Short = &H2S
Const SB_PAGEDOWN As Short = &H3S
Const SB_PAGERIGHT As Short = &H3S
Const SB_THUMBPOSITION As Short = &H4S
Const SB_THUMBTRACK As Short = &H5S
Const SB_TOP As Short = &H6S
Const SB_LEFT As Short = &H6S
Const SB_BOTTOM As Short = &H7S
Const SB_RIGHT As Short = &H7S
Const SB_ENDSCROLL As Short = &H8S

<StructLayout(LayoutKind.Sequential)> Public Structure SCROLLINFO
Public cbSize As Integer
Public fMask As Integer
Public nMin As Integer
Public nMax As Integer
Public nPage As Integer
Public nPos As Integer
Public nTrackPos As Integer
End Structure

Private Const SB_HORZ = 0 '標準水平スクロールバーを指定する
Private Const SB_VERT = 1 '標準垂直スクロールバーを指定する
Private Const SB_CTL = 2 'スクロールバーコントロールを指定する

Private Const SIF_RANGE = &H1
Private Const SIF_PAGE = &H2
Private Const SIF_POS = &H4
Private Const SIF_DISABLENOSCROLL = &H8
Private Const SIF_TRACKPOS = &H10
Private Const SIF_ALL = (SIF_RANGE Or SIF_PAGE Or SIF_POS Or SIF_TRACKPOS)

<DllImport("user32.dll")> _
Private Shared Function GetScrollInfo(ByVal hWnd As IntPtr, _
ByVal nBar As Integer, _
<MarshalAs(UnmanagedType.Struct)> ByRef lpScrollInfo As SCROLLINFO) As Integer
End Function

<DllImport("user32.dll")> _
Private Shared Function SetScrollInfo(ByVal hWnd As IntPtr, _
ByVal nBar As Integer, _
<MarshalAs(UnmanagedType.Struct)> ByRef lpScrollInfo As SCROLLINFO) As Integer
End Function

<DllImport("user32.dll")> _
Private Shared Function SendMessage(ByVal hWnd As IntPtr, _
ByVal msg As Int32, _
ByVal wParam As Int32, _
ByVal lParam As IntPtr) As Int32
End Function

<DllImport("user32.dll")> _
Private Shared Function GetScrollRange(ByVal hWnd As IntPtr, _
ByVal nBar As Integer, _
ByRef MinPos As Integer, _
ByRef MaxPos As Integer) As Integer
End Function

Private Structure POINT
Public x As Integer
Public y As Integer
End Structure

Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case WM_VSCROLL

SendMessage(m.HWnd, WM_SETREDRAW, False, New IntPtr(0))
MyBase.WndProc(m)
SendMessage(m.HWnd, WM_SETREDRAW, True, New IntPtr(0))
MyBase.Invalidate()

'なぜかスクロールバーが同期しないのでSetScrollInfo
Dim scInfo As SCROLLINFO
scInfo.cbSize = Marshal.SizeOf(scInfo)
scInfo.fMask = SIF_POS
GetScrollInfo(m.HWnd, SB_VERT, scInfo)
SetScrollInfo(m.HWnd, SB_VERT, scInfo)

Exit Sub
End Select
MyBase.WndProc(m)
End Sub

Protected Overrides Sub OnMeasureItem(ByVal e As System.Windows.Forms.MeasureItemEventArgs)
e.ItemHeight = 15
End Sub

Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
If e.Index < 0 Then Exit Sub

If MyBase.SelectedIndex = e.Index Then
e.Graphics.FillRectangle(Brushes.Aqua, e.Bounds)
Else
e.Graphics.FillRectangle(Brushes.LightGray, e.Bounds)
End If
e.Graphics.DrawString(e.Index.ToString, MyBase.Font, Brushes.Black, e.Bounds.X + 10, e.Bounds.Y + 1)

End Sub


Protected Overrides Sub OnSelectedIndexChanged(ByVal e As System.EventArgs)
MyBase.Invalidate()
End Sub


End Class




いらない定義がいっぱい残ってますが、ご容赦を。


また「なぜかスクロールバーが同期しないので」の件は
コード:

Case WM_VSCROLL
MyBase.Visible = False
MyBase.WndProc(m)
MyBase.Visible = True



だけでOKだったんですが、なんだか気分的に好きになれない。

そもそもバグ回避なんで、なんでもいいんですけど。。。。。



[ メッセージ編集済み 編集者: ジブ 編集日時 2005-12-01 23:21 ]
未記入
会議室デビュー日: 2004/08/17
投稿数: 10
投稿日時: 2005-12-01 23:44
関係なかったらゴメンなさい。

この問題ってWindowsのテーマによって発生したりしませんか?
Windowsクラシックだと起きたりとか。

スキルアップ/キャリアアップ(JOB@IT)