tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルMsgBoxがはみ出して押せない
記事No8063
投稿日: 2008/09/03(Wed) 11:04
投稿者ダンボ
Yes/Noボタンを持つMsgBoxを表示させていますが、場合により数10行のメッセージを
表示するため、ボタン位置が画面最下行より下になってしまってユーザに見えません。
ボタン2つだけなので見えなくても操作はできるのですが、これではUIとして駄目です。

TextboxあるいはListBoxを用いたMsgBoxを自作するのが良いでしょうか?
それとも何か秘策があるでしょうか?

[ツリー表示へ]
タイトルRe: MsgBoxがはみ出して押せない
記事No8064
投稿日: 2008/09/03(Wed) 11:30
投稿者もょもと
こちらなんか参考になりそうですよ。

MsgBoxを考える
http://www.penhagi.com/access/tips/75_msgbox.htm

[ツリー表示へ]
タイトルRe^2: MsgBoxがはみ出して押せない
記事No8065
投稿日: 2008/09/03(Wed) 13:23
投稿者ダンボ
もょもと さん、どうも有り難うございます。

> http://www.penhagi.com/access/tips/75_msgbox.htm

これの主旨は、長いメッセージ文を分割して複数のMsgBoxで表示するって
ことですね。う〜ん、ちょっと美しく無いかな?

[ツリー表示へ]
タイトルRe^3: MsgBoxがはみ出して押せない
記事No8071
投稿日: 2008/09/03(Wed) 16:06
投稿者よねKEN
> > http://www.penhagi.com/access/tips/75_msgbox.htm
>
> これの主旨は、長いメッセージ文を分割して複数のMsgBoxで表示するって
> ことですね。う〜ん、ちょっと美しく無いかな?

それに加えてスクロールする方法はなさそう、ともありますね。
ということは、

>TextboxあるいはListBoxを用いたMsgBoxを自作するのが良いでしょうか?

この文に対してはYesと言えそうですね。

インストーラで最初に許諾内容をずらずらっと表示するというのがありますが、
あぁいうイメージになるんじゃないでしょうか。

[ツリー表示へ]
タイトル[解消] MsgBoxがはみ出して押せない
記事No8072
投稿日: 2008/09/03(Wed) 17:11
投稿者ダンボ
はい。作りました。これだけのステップですが、ちょっと汎用性も持たせたし小技も使ったので紹介します。

Imports System.Windows.Forms
Public Class TextMsgBox
    Public Overloads Function ShowDialog(ByVal TextInfo As String, Optional ByVal TextAsk As String = Nothing) As DialogResult
        txtInfo.Text = TextInfo
        If IsNothing(TextAsk) Then
            lblASK.Text = ""
            NO_Button.Visible = False
        Else
            lblASK.Text = TextAsk
            NO_Button.Visible = True
        End If
        Me.ShowDialog()
    End Function

    Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click
        Me.DialogResult = System.Windows.Forms.DialogResult.OK
        Me.Close()
    End Sub

    Private Sub NO_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NO_Button.Click
        Me.DialogResult = System.Windows.Forms.DialogResult.No
        Me.Close()
    End Sub
End Class

[ツリー表示へ]
タイトルRe: [解消] MsgBoxがはみ出して押せない
記事No8073
投稿日: 2008/09/03(Wed) 17:20
投稿者魔界の仮面弁士
>     Private Sub OK_Button_Click(
>     Private Sub NO_Button_Click(
Form の AcceptButton / CancelButton を使うという手もありますね。


> Me.DialogResult = System.Windows.Forms.DialogResult.OK
> Me.DialogResult = System.Windows.Forms.DialogResult.No
対象性が無いので、これはあまり良くないと思いますよ。
組み合わせるなら、「OK / Cancel」または「Yes / No」にすべきかと。

[ツリー表示へ]
タイトルRe^2: [解消] MsgBoxがはみ出して押せない
記事No8087
投稿日: 2008/09/05(Fri) 09:35
投稿者ダンボ
魔界の仮面弁士 さん、いつもアドバイス有難うございます。

> 組み合わせるなら、「OK / Cancel」または「Yes / No」にすべきかと。

御意の通りです。
言い訳してもしょうがないんですが、Informationの場合は「OK」ボタンだけ表示。
Questionの場合は、このアプリの場合別処理で続行するので「NO」ボタンかな?と
軽く考えて実装しました。
「NO」にこだわるなら「OK」ボタンのTextも「YES」に書き換えるのがベストですね。
UIにこだわっているのだから。


> >     Private Sub OK_Button_Click(
> >     Private Sub NO_Button_Click(
> Form の AcceptButton / CancelButton を使うという手もありますね。

ひょっとしたらAcceptButton / CancelButtonを設定しているとButton.Clickイベント
コードを書かなくても良いのかな。それは素晴らしいと実験してみましたがそんなことは
無かった。
魔界の仮面弁士 さんがおっしゃりたかった事は「ボタンが見えなくともEnter/Escキー
入力で操作できる」ということですよね?

[ツリー表示へ]
タイトルAcceptButton / CancelButton プロパティの利用
記事No8088
投稿日: 2008/09/05(Fri) 11:50
投稿者魔界の仮面弁士
> Button.Clickイベントコードを書かなくても良いのかな。

その通り。戻り値として DialogResult を返すだけでよいのなら、
OK/Cancel ボタンのコードは不要です。


以下、VBC.EXE  Version 9.0.21022.8 でコンパイルして動作確認。

'----
' ソースファイル名
' C:\a.vb
'----
' コンパイル方法
' C:\WINDOWS\Microsoft.NET\Framework\v3.5\VBC.EXE /t:winexe /out:C:\a.exe C:\a.vb
'----
Imports System
Imports System.Windows.Forms
Imports DR = System.Windows.Forms.DialogResult
Class Sample : Inherits Form
 Shared Sub Main()
  Application.Run(New Sample())
 End Sub

 WithEvents B As New Button() With { .Text = "テスト" }
 Private Sub New()
  Controls.Add(B)
 End Sub

 Sub B_Click() Handles B.Click
  Dim ret As DR = TextMsgBox.Show("タイトル")

  MsgBox(ret.ToString() & "が押されました。")
 End Sub
End Class


Public Class TextMsgBox : Inherits Form
 Private Sub New()
  Dim btnOK As New Button() With { .Text = "OK", .DialogResult = DR.OK }
  Controls.Add(btnOK)
  Dim btnCancel As New Button() With { .Text = "Cancel", .DialogResult = DR.Cancel, .Left = btnOK.Right + 3 }
  Controls.Add(btnCancel)
  CancelButton = btnCancel
  AcceptButton = btnOK
 End Sub

 Public Shared Overloads Function Show(ByVal text As String) As DialogResult
  Using F As New TextMsgBox()
   F.Text = text
   Return F.ShowDialog()
  End Using
 End Function

End Class

[ツリー表示へ]
タイトル[解決] AcceptButton / CancelButton プロパティの利用
記事No8089
投稿日: 2008/09/05(Fri) 13:00
投稿者ダンボ
了解しました。
なんで魔界の仮面弁士さんができて、私ができなかったかと言うと、
入力を待つためにモードレスであることが必要だったからです。

そこらへんの事情は、
http://www.atmarkit.co.jp/fdotnet/dotnettips/139dialog/dialog.html

[ツリー表示へ]
タイトル[×解決] AcceptButton / CancelButton プロパティの利用
記事No8092
投稿日: 2008/09/05(Fri) 15:50
投稿者ダンボ
> 入力を待つためにモードレスであることが必要だったからです。

いや、ShowDialogで呼出して、入力完了を待つのだからモーダルですね。
また、早とちりをしてしまいました。
疑問(魔界の仮面弁士さんができて、私ができない理由)は解決していませんが、
イベントコードを書くだけ(コメントアウトを戻すだけ)のことですので
深く考えないようにしようと。

[ツリー表示へ]
タイトルRe: [×解決] AcceptButton / CancelButton プロパティの利用
記事No8098
投稿日: 2008/09/07(Sun) 22:05
投稿者neptune
こんにちは

ちょっとお邪魔します。

求めてないとは思いますが、Hookのサンプルありました。ドイツ語ですけど。
http://www.vb-fun.de/cgi-bin/loadframe.pl?ID=dotnet/tipps/tip0157.shtml
ちょっと改造したら、直ぐ使えるようです。

動作確認したら、少しは修正したかもわかりませんが、殆どそのまんまでサンプルは
動きました。

で、下記を書いて位置修正してみたら、出来るようです。
サンプルのDialogHookProcから下記のAdjustWindowを呼びます。
追加分のみ。vb2008で作成

#Region "Class ProcessingSys"
    Public Class ProsessingSys

        <StructLayout(LayoutKind.Sequential)> _
        Public Structure RECT
            <MarshalAs(UnmanagedType.I4)> _
            Public Left As Integer
            <MarshalAs(UnmanagedType.I4)> _
            Public Top As Integer
            <MarshalAs(UnmanagedType.I4)> _
            Public Right As Integer
            <MarshalAs(UnmanagedType.I4)> _
            Public Bottom As Integer
        End Structure

        Public Structure RECT2
            Public rc As RECT

            Public ReadOnly Property Width() As Integer
                Get
                    Return rc.Right - rc.Left
                End Get
            End Property

            Public ReadOnly Property Height() As Integer
                Get
                    Return rc.Bottom - rc.Top
                End Get
            End Property

        End Structure

        <DllImport("user32.dll")> _
      Private Shared Function GetWindowRect(ByVal hwnd As IntPtr, ByRef lpRect As RECT) As Integer
        End Function


        <DllImport("user32.dll")> _
        Public Shared Function MoveWindow _
                    (ByVal hwnd As IntPtr, _
                     ByVal x As Integer, _
                     ByVal y As Integer, _
                     ByVal nWidth As Integer, _
                     ByVal nHeight As Integer, _
                     ByVal bRepaint As Integer) As Integer

        End Function

        ''' <summary>
        ''' Window位置の調整を行う。渡されたWindowを画面の中央に配置する
        ''' </summary>
        ''' <param name="pHandle">MessageBoxのHWND</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function AdjustWindow(ByVal pHandle As IntPtr) As Boolean
            Dim hWnd As IntPtr = pHandle
            'ディスプレイの大きさ取得
            Dim iWidth As Integer = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width()
            Dim iHeight As Integer = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height()

            'WindowのRECTを取得
            Dim rc As New RECT
            GetWindowRect(pHandle, rc)
            Dim rc2 As New RECT2
            rc2.rc = rc

            Dim x, y As Integer
            x = CInt((iWidth - rc2.Width) / 2)
            y = CInt((iHeight - rc2.Height) / 2)

            Dim ret As Integer = MoveWindow(pHandle, x, y, rc2.Width, rc2.Height, 1)

            Return CBool(ret)
        End Function
    End Class
#End Region

ここで質問
1.FrameWorkで代替があるかどうかわからなかったのでGetWindowRect、MoveWindow 
APIを使いました。FrameWorkの方法があれば教えて下さい。
それと構造としてもっと賢い書き方があれば教えて下さい。

2.'Dim thisThread As Integer = AppDomain.GetCurrentThreadId()
で、「こちらは古い方式」と警告が出る。そこで
Dim thisThread As Integer = System.AppDomain.GetCurrentThreadId()
と書いてみたら、こんどは
'こちらは「インスタンスを経由する共有メンバ、定数メンバ、列挙型メンバ、または
'入れ子にされた型へのアクセスです。正規の式は評価されません。」と警告が出る
なので
'Dim thisThread As Integer = System.Threading.Thread.CurrentThread.ManagedThreadId()
と書いてみたら、今度は、上記2つとは違うスレッドを拾ってくるみたいでHookに失敗する。

警告や、エラーが出ない書き方はどうやるんでしょう?

3.
        <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
        Private Shared Function SetWindowsHookEx( _
            ByVal idHook As Integer, _
            ByVal lpfn As HookProc, _  ←サンプルのこのやり方はMSDNに書いているんですかね?
            ByVal hInstance As IntPtr, _
            ByVal threadId As Integer) As IntPtr
        End Function

以上、暇なときで結構ですからご教示下さい。便乗ですが宜しくお願いします。

感想:
Hookはframeworkではとても面倒。C#のサンプルはあるが、VBのサンプルは殆どない。
さすがにフックするだけあってと、クラスか、メソッドを増やしていけば、背景色や、
文字のフォントとか拡張はどうとでもなりそうだし、使い回しが効くので
一度作れば楽チンかな?。

Webの翻訳サービスはエライ!

ちなみに・・・ボチボチと、私には難しいので理解と、実験に3日掛かりました。^ ^;;
でも正直まだ理屈は良く判らんです。

長々と失礼しました。

[ツリー表示へ]
タイトルRe^2: [×解決] AcceptButton / CancelButton プロパティの利用
記事No8104
投稿日: 2008/09/09(Tue) 09:39
投稿者ダンボ
neptuneさん、どうも有り難うございます。

ドイツ語は第2外国語だったのでちょっと見てみましたが、駄目ですねぇ。
> Wenn Sie einer MessageBox eigene Benennungen und ein eigenes Verhalten geben
> wollen, m&#252;ssen Sie tief in die "Trickkiste" der API-Programmierung greifen.

・もしあなたが一つのメッセージボックスを...しようと思うならば、あなたはAPI
 プログラミングという技を使わなければならない。


> 動作確認したら、少しは修正したかもわかりませんが、殆どそのまんまでサンプルは
> 動きました。

動作確認までしていないのですが、これは「MessageBoxを画面中央に置く」だけのもの
ではないのでしょうか?

> ここで質問
> 以上、暇なときで結構ですからご教示下さい。便乗ですが宜しくお願いします。

おっ、私に回答を求めていらっしゃる?すみませんが分かりそうもないです。
すでにこのスレッドも長くなって、閲覧者も最後まで読み通さないと思われますので、
新規にスレッドを起こされた方が良いと思いますよ。

[ツリー表示へ]
タイトルRe^3: [×解決] AcceptButton / CancelButton プロパティの利用
記事No8113
投稿日: 2008/09/09(Tue) 14:45
投稿者neptune
こんにちは

> 動作確認までしていないのですが、これは「MessageBoxを画面中央に置く」だけのもの
> ではないのでしょうか?
リンク先はButtonのtextを自前のものに変更するだけです。
リンク先の「textを自前のものに変更する」部分で、私の書いたもの(上でUPした奴)
を呼び出すように変更すれば、「MessageBoxを画面中央に置く」だけになります。

> おっ、私に回答を求めていらっしゃる?すみませんが分かりそうもないです。
> すでにこのスレッドも長くなって、閲覧者も最後まで読み通さないと思われますので、
> 新規にスレッドを起こされた方が良いと思いますよ。
あっごめんなさい。もしかしたらとおもったもので。

今回はダンボさんの質問をみて、自分なりの出来るかどうかの実験です。
で、この手法でもできそうという感触を得ました。
 取り合えず問題なく動くようだし、興味だけなので別スレでの質問は今回は見合わせます。

そのうち、又思い起こして質問した際はお願いします。


余談:
背景色、文字色の変更も可能とは思いますが、CBTProcフックだけでは済まず、更に
MessageBoxをサブクラス化して、その処理を描いてやらなければならないような気がします。
で、そこで思ったのが、自前でコントロールか、クラスを作ってやるほうが同じ、位置、
背景色、文字色だけなら簡単じゃないかと。

お後がよろしいようで。^ ^;;
お邪魔しました。

[ツリー表示へ]