.NETプログラミング研究 第53号 †
お知らせ †
「.NETプログラミング研究」が「まぐまぐ!」殿堂入り †
皆様のおかげでこのメールマガジン「.NETプログラミング研究」が「まぐまぐ!」で殿堂入りしました。これからも「.NETプログラミング研究」をよろしくお願いいたします。
.NET質問箱 †
「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込まれた.NETプログラミングに関する投稿を基に、さらに考察を加え、Q&A形式にまとめて紹介します。
Buttonコントロールで矢印キーが押されたことを知るには? †
【質問】
System.Windows.Forms.ButtonコントロールのKeyDownイベントで矢印キーの押下を捕捉しようとしたのですが、できませんでした。Buttonコントロールで矢印キーが押されたことを知る方法はありますか?
【回答】
System.Windows.Forms.ButtonクラスのProcessDialogKeyメソッド(あるいはProcessCmdKeyメソッド等)をオーバーライドすれば、矢印キーやTab、Enter、Escキーが押されたことを知ることができます。
まず次のようなSystem.Windows.Forms.Buttonクラスの派生クラスを作成し、ProcessDialogKeyメソッドをオーバーライドします。ここでは、左キーが押された時に、メッセージボックスを表示するようにしています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| | Public Class MyButton
Inherits Button
Protected Overrides Function ProcessDialogKey( _
ByVal keyData As Keys) As Boolean
If (keyData And Keys.KeyCode) = Keys.Left Then
MessageBox.Show("左キーが押されました。")
End If
Return MyBase.ProcessDialogKey(keyData)
End Function
End Class
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| | public class MyButton : Button
{
protected override bool ProcessDialogKey(Keys keyData)
{
if ((keyData & Keys.KeyCode) == Keys.Left)
{
MessageBox.Show("左キーが押されました。");
}
return base.ProcessDialogKey(keyData);
}
}
|
この様にして作成したMyButtonクラスをSystem.Windows.Forms.Buttonクラスの代わりに使うようにします。具体的には、"System.Windows.Forms.Button"を"MyButton"に文字列置換すれば大抵の場合大丈夫でしょう。
○この記事の基になった掲示板のスレッド
○この記事の基になった掲示板のスレッド
Buttonコントロールにフォーカスがあるとフォームで矢印キーのキーイベントが発生しない †
【質問】
フォームのKeyPreviewプロパティをtrueにして、KeyDownやKeyUpなどのキーイベントをフォームで受け取るようにしています。しかしButtonコントロールにフォーカスがあると矢印キーやタブキーの押下でキーイベントが発生しません。何か良い解決法はありませんか?
【回答】
矢印キーが押されたかをフォームで知る場合は、先の「Buttonコントロールで矢印キーが押されたことを知るには?」と同様に、フォームクラスのProcessDialogKeyメソッドをオーバーライドします。この場合はフォームデザイナで作成されたコードを変更する必要が無いため、先の方法より簡単です。
具体的には、次のようなコードをフォームクラスに追加します。この例では、左キーとタブキーが押された時に、メッセージボックスを表示するようにしています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| | Protected Overrides Function ProcessDialogKey( _
ByVal keyData As Keys) As Boolean
If (keyData And Keys.KeyCode) = Keys.Left Then
MessageBox.Show("左キーが押されました。")
Return True
ElseIf (keyData And Keys.KeyCode) = Keys.Tab Then
MessageBox.Show("Tabキーが押されました。")
Return True
End If
Return MyBase.ProcessDialogKey(keyData)
End Function
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| | protected override bool ProcessDialogKey(Keys keyData)
{
if ((keyData & Keys.KeyCode) == Keys.Left)
{
MessageBox.Show("左キーが押されました。");
return true;
}
else if ((keyData & Keys.KeyCode) == Keys.Tab)
{
MessageBox.Show("Tabキーが押されました。");
return true;
}
return base.ProcessDialogKey(keyData);
}
|
なおタブキーが押されたかを調べる場合は、ButtonのあるフォームのProcessTabKeyメソッドをオーバーライドする方法もあります。フォームクラスに次のようなコードを追加することにより、Tabキーが押された時にメッセージボックスを表示し、次のコントロールがアクティブにならないようにすることができます。
1
2
3
4
5
| | Protected Overrides Function ProcessTabKey( _
ByVal forward As Boolean) As Boolean
MessageBox.Show("Tabキーが押されました。")
Return True
End Function
|
1
2
3
4
5
| | protected override bool ProcessTabKey(bool forward)
{
MessageBox.Show("Tabキーが押されました。");
return true;
}
|
○この記事の基になった掲示板のスレッド
画面をキャプチャするには? †
【質問】
画面をキャプチャ(ハードコピー)し、イメージをBitmapで取得したいのですが、どのような方法がありますか?
【回答】
最も簡単な方法は、Print ScreenキーストロークをSendKeys.SendWait(またはSend)メソッドで送信し、クリップボードにコピーされたイメージを取得する方法です。Ctrl+PrintScreenキーストローク("^{PRTSC}")で画面全体がキャプチャされ、Alt+PrintScreenキーストローク("%{PRTSC}")でアクティブなウィンドウがキャプチャされます(PrintScreenキーストロークのみでもアクティブなウィンドウがキャプチャされるようです)。
ただしこの方法では確実に画面のイメージを取得できる保障はありません(実際に失敗することも多いようです)。
補足:MSDNには、「{PRTSC} (今後使用するために予約されている)」と書かれています。
この方法により画面全体のイメージを取得し、PictureBox(PictureBox1)に表示するサンプルを以下に示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| | SendKeys.SendWait("^{PRTSC}")
Dim d As IDataObject = Clipboard.GetDataObject()
Dim img As Image = CType(d.GetData(DataFormats.Bitmap), Image)
If Not (img Is Nothing) Then
PictureBox1.Image = img
Clipboard.SetDataObject(New DataObject)
End If
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| | SendKeys.SendWait("^{PRTSC}");
IDataObject d = Clipboard.GetDataObject();
Image img = (Image) d.GetData(DataFormats.Bitmap);
if (img != null)
{
PictureBox1.Image = img;
Clipboard.SetDataObject(new DataObject());
}
|
ちゃんとした画面キャプチャを行うには、Win32 APIを使うことになります。この方法関しては、ウェブ上で優れたサンプルがいくつも公開されています。その一部を紹介します。
以下はC#のサンプルです。
以下はVB.NETのサンプルです。
以下に画面全体をキャプチャするメソッド(CaptureScreen)と、アクティブなウィンドウをキャプチャするメソッド(CaptureActiveWindow)のごく簡単なサンプルを紹介します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
| |
Const SRCCOPY As Integer = 13369376
<DllImport("user32.dll")> _
Private Shared Function GetDC(ByVal hwnd As IntPtr) As IntPtr
End Function
<DllImport("gdi32.dll")> _
Private Shared Function BitBlt(ByVal hDestDC As IntPtr, _
ByVal x As Integer, ByVal y As Integer, _
ByVal nWidth As Integer, ByVal nHeight As Integer, _
ByVal hSrcDC As IntPtr, _
ByVal xSrc As Integer, ByVal ySrc As Integer, _
ByVal dwRop As Integer) As Integer
End Function
<DllImport("user32.dll")> _
Private Shared Function ReleaseDC(ByVal hwnd As IntPtr, _
ByVal hdc As IntPtr) As IntPtr
End Function
Public Shared Function CaptureScreen() As Bitmap
Dim disDC As IntPtr = GetDC(IntPtr.Zero)
Dim bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, _
Screen.PrimaryScreen.Bounds.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
Dim hDC As IntPtr = g.GetHdc()
BitBlt(hDC, 0, 0, bmp.Width, bmp.Height, disDC, 0, 0, SRCCOPY)
g.ReleaseHdc(hDC)
g.Dispose()
ReleaseDC(IntPtr.Zero, disDC)
Return bmp
End Function
<StructLayout(LayoutKind.Sequential)> _
Private Structure RECT
Public left As Integer
Public top As Integer
Public right As Integer
Public bottom As Integer
End Structure
<DllImport("user32.dll")> _
Private Shared Function GetWindowDC(ByVal hwnd As IntPtr) As IntPtr
End Function
<DllImport("user32.dll")> _
Private Shared Function GetForegroundWindow() As IntPtr
End Function
<DllImport("user32.dll")> _
Private Shared Function GetWindowRect(ByVal hwnd As IntPtr, _
ByRef lpRect As RECT) As Integer
End Function
Public Shared Function CaptureActiveWindow() As Bitmap
Dim hWnd As IntPtr = GetForegroundWindow()
Dim winDC As IntPtr = GetWindowDC(hWnd)
Dim winRect As New RECT
GetWindowRect(hWnd, winRect)
Dim bmp As New Bitmap(winRect.right - winRect.left, _
winRect.bottom - winRect.top)
Dim g As Graphics = Graphics.FromImage(bmp)
Dim hDC As IntPtr = g.GetHdc()
BitBlt(hDC, 0, 0, bmp.Width, bmp.Height, winDC, 0, 0, SRCCOPY)
g.ReleaseHdc(hDC)
g.Dispose()
ReleaseDC(hWnd, winDC)
Return bmp
End Function
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
| |
private const int SRCCOPY = 13369376;
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("gdi32.dll")]
private static extern int BitBlt(IntPtr hDestDC,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hSrcDC,
int xSrc,
int ySrc,
int dwRop);
[DllImport("user32.dll")]
private static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);
public static Bitmap CaptureScreen()
{
IntPtr disDC = GetDC(IntPtr.Zero);
Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height);
Graphics g = Graphics.FromImage(bmp);
IntPtr hDC = g.GetHdc();
BitBlt(hDC, 0, 0, bmp.Width, bmp.Height,
disDC, 0, 0, SRCCOPY);
g.ReleaseHdc(hDC);
g.Dispose();
ReleaseDC(IntPtr.Zero, disDC);
return bmp;
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern int GetWindowRect(IntPtr hwnd,
ref RECT lpRect);
public static Bitmap CaptureActiveWindow()
{
IntPtr hWnd = GetForegroundWindow();
IntPtr winDC = GetWindowDC(hWnd);
RECT winRect = new RECT();
GetWindowRect(hWnd, ref winRect);
Bitmap bmp = new Bitmap(winRect.right - winRect.left,
winRect.bottom - winRect.top);
Graphics g = Graphics.FromImage(bmp);
IntPtr hDC = g.GetHdc();
BitBlt(hDC, 0, 0, bmp.Width, bmp.Height,
winDC, 0, 0, SRCCOPY);
g.ReleaseHdc(hDC);
g.Dispose();
ReleaseDC(hWnd, winDC);
return bmp;
}
|
○この記事の基になった掲示板のスレッド
複数のRTFファイルを連結してRichTextBoxに表示するには? †
【質問】
複数のRTFファイルを連結したくて、RTFファイルをテキストとして読み込み、文字列を連結し、RichTextBoxのRtfプロパティに代入したのですが、うまくいきません。複数のRTFファイルを連結してRichTextBoxに表示するにはどのようにすればよいのでしょうか?
【回答】
RichTextBoxにRTFを挿入するには、RichTextBox.SelectedRtfプロパティを使用しますが、RTFファイルのテキストをSelectedRtfプロパティに代入することにより、そのフォーマットされた内容がRichTextBoxに挿入されます。つまり複数のRTFファイルを連結してRichTextBoxに表示するには、RTFファイルをテキストとして読み込み、RichTextBoxのSelectionStartを末尾にし、SelectedRtfにRTFファイルのRTFを設定するという作業を繰り返せばよいということになります。
次にRTFファイル"C:\1.rtf"、"C:\2.rtf"、"C:\3.rtf"を連結し、RichTextBox(RichTextBox1)に表示するコードを示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| | Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
RichTextBox1.Clear()
Dim i As Integer
For i = 1 To 3
Dim sr As New System.IO.StreamReader( _
"C:\" + i.ToString() + ".rtf", _
System.Text.Encoding.GetEncoding(932))
Dim rtf As String = sr.ReadToEnd()
sr.Close()
AppendRtfToRichTextBox(RichTextBox1, rtf)
Next i
End Sub
Public Shared Sub AppendRtfToRichTextBox( _
ByVal rtb As RichTextBox, ByVal rtfText As String)
rtb.SelectionStart = rtb.TextLength
rtb.SelectedRtf = rtfText
End Sub
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| | private void Button1_Click(object sender, System.EventArgs e)
{
RichTextBox1.Clear();
for (int i = 1; i <= 3; i++)
{
System.IO.StreamReader sr =
new System.IO.StreamReader(
"C:\\" + i.ToString() + ".rtf",
System.Text.Encoding.GetEncoding(932));
string rtf = sr.ReadToEnd();
sr.Close();
//RichTextBox1に追加する
AppendRtfToRichTextBox(RichTextBox1, rtf);
}
}
/// <summary>
/// RichTextBoxの末尾にRTFを追加
/// </summary>
/// <param name="rtb">RTFを追加するRichTextBox</param>
/// <param name="rtfText">追加するRTF文字列</param>
public static void AppendRtfToRichTextBox(
RichTextBox rtb, string rtfText)
{
rtb.SelectionStart = rtb.TextLength;
rtb.SelectedRtf = rtfText;
}
|
参考:
○この記事の基になった掲示板のスレッド
コメント †