C#

コントロールのスクリーン座標(絶対座標)を取得する(C#)

VisualStudio(C#)にて開発が続いていますが、コントロール(Button)絶対座標の取得について気づきがありましたので共有したいと思います。

VisualStudioには標準のカレンダーコントロールはありませんので、MonthCalendarを直接組み入れてVisibleを制御する、もしくはMonthCalendarの別フォームを作成した上でモーダル表示(ShowDialogメソッドを利用)を行い、日付(Datetime)を取得する方法が想定されます。

どの方法でもいいのですが、カレンダー(を含むフォーム)のLocationを制御し、ボタンの直下に表示されるように設定する必要があります。
CalendarControlImage

今回はキーボード操作を独立させたい事と、カレンダー表示中は別操作を禁止させたい事から別フォーム&モーダル表示の方法を選択しています。

さて、各コントロールのプロパティを見みるとそれぞれにLocationがあり、配置はこちらで決定されます。しかし、この値はは親コントロールからの相対座標を示していますので、スクリーン上の絶対座標とは異なります。

コントロールには共通項目してコントロール上の位置(PointToClientメソッド)とスクリーン上の位置(PointToScreenメソッド)がありますので、今回はPointToScreenメソッドを使用します。(各メソッドの詳細はMSDNをご参照ください)

さて、PointToScreenメソッドを使うはいいのですが、どのコントロールを基準にどういった座標を渡せばいいのか?というところで躓いてしましました。
絶対座標の取得について検索してみると概ねクライアント座標を取得してからスクリーン座標に変換していたのですが、この方法では上手く座標が得られなかったのです。

そこで、試しにボタン基準(自分基準)のPointToScreenを取得してみると…上手くいきました。

FormCalendar form = new FormCalendar();
Point pt = this.buttonボタン.PointToScreen(new Point(0,0));

pt.Offset(0, this.buttonボタン.Size.Height); // 高さをオフセット
form.Location = pt;
form.StartPosition = FormStartPosition.Manual;  // 表示位置をマニュアルとする
form.FormBorderStyle = FormBorderStyle.FixedToolWindow; // タスクバーに表示しない
form.ShowInTaskbar = false; // タスクバーに表示しない
form.ShowDialog();

このままですとフォームが画面端に移動したときに正常に表示されませんので実際に利用するにはカレンダー側のShowDialogメソッドで領域修正を行います。

/// <summary>
/// カレンダーを起動
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonボタン_Click(object sender, EventArgs e)
{
    FormCalendar form = new FormCalendar();

    if (form.ShowDialog(this.buttonボタン.PointToScreen(new Point(0, 0)), this.buttonボタン.Size) == DialogResult.OK)
    {
        this.textBox日付.Text = form.Calendar.SelectionStart.ToShortDateString();
    }
    form.Dispose();
}
/// <summary>
/// 座標指定表示
/// </summary>
/// <param name="pt">基準コントロールの絶対座標</param>
/// <param name="sz">基準コントロールのサイズ</param>
/// <returns></returns>
public DialogResult ShowDialog(Point pt, Size sz)
{
    pt.Offset(0, sz.Height); // 基準コントロールの高さ分オフセット移動
    if ((pt.X + this.Width) > Screen.PrimaryScreen.Bounds.Width)
    {
        // カレンダー表示X領域がスクリーン領域を超える場合
        pt.X = Screen.PrimaryScreen.Bounds.Width - this.Size.Width;
    }
    if ((pt.Y + this.Height) > Screen.PrimaryScreen.Bounds.Height)
    {
        // カレンダー表示Y領域がスクリーン領域を超える場合
        pt.Y = Screen.PrimaryScreen.Bounds.Height - this.Size.Height;
    }
    this.Location = pt;
    this.StartPosition = FormStartPosition.Manual;
    this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
    this.ShowInTaskbar = false;

    return this.ShowDialog();
}

上手くいくとこのような感じでボタンの真下にカレンダーフォームが表示されます。
CalendarControlImage2

カレンダーフォームの最大化ボタン、最小化ボタンはあらかじめ非表示にしていますのであしからず。

ABOUT ME
Nozomu.Kon
トータルソフトウェアコーディネーターがあなたのお困りを即時に解決!