C#初心者の質問

タグの編集
投稿者 kai  (高校生) 投稿日時 2024/8/6 17:02:44
C#初めてそんなに立っていないのですが、継承を使った処理を書いてみたくて作ったプログラムで、ボタンを押すとテキストのカードをFormに出して、そのカードはマウスでドラッグ移動できるみたいな感じで作りたかったんですが、うまくできませんでした。

public DraggableControl() : base()が参照0と表示されてるので多分動いてなくてこれが原因だと思いますが。

初心者の書いたよくわからないプログラムを見てくれる方がいたらお願いします。
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using static マルチメモ帳.MainSystem;
namespace マルチメモ帳
{
    public partial class MainSystem : Form
    {
        private List<DraggableRichTextBox> Textcards = new List<DraggableRichTextBox>();
        private List<ImageCard> Imagecards = new List<ImageCard>();
        public MainSystem()
        {
            InitializeComponent();
        }
        #region ボタン
        private void AddCardButton_Click(object sender, EventArgs e)
        {
            DraggableRichTextBox newDraggableRichTextBox = new DraggableRichTextBox();
            //RichTextBoxのサイズを決定
            newDraggableRichTextBox.Size = new Size(200, 100);
            newDraggableRichTextBox.Location = new Point(10, 30 + ((Textcards.Count + Imagecards.Count) * 120));

            //RichTetxtBoxの初期プロパティを設定
            newDraggableRichTextBox.BackColor = Color.White;
            newDraggableRichTextBox.ForeColor = Color.Black;

            //フォームに表示
            this.cardPanel.Controls.Add(newDraggableRichTextBox);

            //リストの内容を増やす
            Textcards.Add(newDraggableRichTextBox);
        }
        private void AddImageButton_Click(object sender, EventArgs e)
        {

        }
        #endregion
    }
    #region 生成
    // DraggableControlクラス

    // DraggableRichTextBoxクラス
    public class DraggableRichTextBox : DraggableControl
    {
        public RichTextBox newRichTextBox = new RichTextBox();

        public DraggableRichTextBox()
        {
            newRichTextBox.Dock = DockStyle.Fill;
            newRichTextBox.BackColor = Color.White;
            newRichTextBox.ForeColor = Color.Black;
            newRichTextBox.BorderStyle = BorderStyle.Fixed3D;

            this.Controls.Add(newRichTextBox);
        }
    }
    // ImageCardクラス
    public class ImageCard : DraggableControl
    {
        private PictureBox newImageCard = new PictureBox();

        public ImageCard()
        {
            newImageCard.Dock = DockStyle.Fill;
            newImageCard.SizeMode = PictureBoxSizeMode.StretchImage;

            this.Controls.Add(newImageCard);
            this.Size = newImageCard.Size;  // ドラッグ可能なサイズに設定
        }

        public Image Image
        {
            get { return newImageCard.Image; }
            set { newImageCard.Image = value; }
        }
    }


    public class DraggableControl : Control
    {
        private Point mouseDownLocation;

        public DraggableControl() : base()
        {
            this.MouseDown += DraggableControl_MouseDown;
            this.MouseMove += DraggableControl_MouseMove;
            this.MouseUp += DraggableControl_MouseUp;
        }

        private void DraggableControl_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                mouseDownLocation = e.Location;
            }
        }

        private void DraggableControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                this.Left += e.X - mouseDownLocation.X;
                this.Top += e.Y - mouseDownLocation.Y;
            }
        }

        private void DraggableControl_MouseUp(object sender, MouseEventArgs e)
        {
            // ドラッグ終了時の処理があればここに追加
        }
    }

    #endregion
}


わからなくてGPTで生成した部分が一部入ってるのでコメントとかのやつは気にしないでください。
public class DraggableControl : Controlは動いたことがないので、動作するかもわかってないです
投稿者 (削除されました)  () 投稿日時 2024/8/6 18:02:13
(削除されました)
投稿者 KOZ  (社会人) 投稿日時 2024/8/6 18:13:08
これでどうでしょうか?

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public partial class MainForm : Form
{
    public MainForm() {
        InitializeComponent();
    }

    private const int WM_SYSCOMMAND = 0x0112;
    private const int SC_MOVE = 0xF010;
    private const int HTCAPTION = 0x0002;

    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

    private void AddCardButton_Click(object sender, EventArgs e) {
        RichTextBox newRichTextBox = new RichTextBox {
            Size = new Size(200, 100),
            Location = new Point(10, 30 + (cardPanel.Controls.Count * 120)),
            BackColor = Color.White,
            ForeColor = Color.Black
        };
        newRichTextBox.MouseDown += NewRichTextBox_MouseDown;
        cardPanel.Controls.Add(newRichTextBox);
    }

    private void NewRichTextBox_MouseDown(object sender, MouseEventArgs e) {
        RichTextBox rtx = (RichTextBox)sender;
        rtx.Capture = false;
        SendMessage(rtx.Handle, WM_SYSCOMMAND, new IntPtr(SC_MOVE | HTCAPTION), IntPtr.Zero);
    }

}

投稿者 とくま  (社会人) 投稿日時 2024/8/7 09:11:03
とりあえず、原因としては、Draggable なコントロールを new したときに、
Draggable じゃない普通のコントロールを Fill して埋めちゃってるから、
Draggable のコードに反応する部分が普通のコントロールの下に隠れちゃって
るという感じかな?Fill しないで余白を作って、どの部分に自分のコードが
反映されているか確認すると良いと思うよ。

Draggable の機能を別途(共通部品として)コーディングしたいなら、継承より
インターフェースでくっつけてやる感じのほうがスッキリするかもだけど、
継承でやるなら、RichTextBox を継承して Draggable の機能を追加してやる
ことだね。

既存のコントロールが
Control >【継承】> RichTextBox
となっちゃってて、継承元を変えるには、Microsoftの用意したライブラリ内に
ある、RichTextBoxクラスを直接変えないといけないよね?っていう所を
頭の中で整理しないといけない。
普通は、
Control >【継承】> RichTextBox >【継承】> DraggableRichTextBox
とやるしかないよね?っていうこと。
継承元で既に定義されている関数を上書き(override)するから、共通部品には
ならないかな。
Control >【継承】> PictureBox >【継承】> DraggableImageCard
を別途コーディングしないと。
投稿者 kai  (高校生) 投稿日時 2024/8/13 19:07:45
いろいろな意見ありがとうございます。
意見を参考にもう一回調べ直したりして書き直してみました。
namespace マルチメモ帳
{
    public partial class MainSystem : Form
    {
        private List<DraggableRichTextBox> Textcards = new List<DraggableRichTextBox>();
        private List<DraggablePictureBox> Imagecards = new List<DraggablePictureBox>();
        public MainSystem()
        {
            InitializeComponent();
        }

        private void AddCardButton_Click(object sender, EventArgs e)
        {
            //RichTetxtBoxの初期プロパティを設定
            DraggableRichTextBox newDraggableRichTextBox = new DraggableRichTextBox()
            {
                Size = new Size(200, 100),
                Location = new Point(10, 30 + ((Textcards.Count + Imagecards.Count) * 120)),
                BackColor = Color.White,
                ForeColor = Color.Black,
                BorderStyle = BorderStyle.Fixed3D,
            };
            this.cardPanel.Controls.Add(newDraggableRichTextBox);
           Textcards.Add(newDraggableRichTextBox);
        }
        private void AddImageButton_Click(object sender, EventArgs e)
        {

            // OpenFileDialogのインスタンスを作成
            OpenFileDialog openFileDialog = new OpenFileDialog
            {
                Filter = "画像ファイル|*.jpg;*.jpeg;*.png;*.bmp"
            };

            // ダイアログを表示
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                // 選択されたファイルのパスを取得
                string selectedFilePath = openFileDialog.FileName;

                // ImageCardのインスタンスを作成
                DraggablePictureBox newpictureBox = new DraggablePictureBox()
                {
                    Size = new Size(200, 200),
                    Location = new Point(10, 30 + ((Textcards.Count + Imagecards.Count) * 120)),
                    BorderStyle = BorderStyle.Fixed3D,
                };


                // 画像を設定
                newpictureBox.Image = Image.FromFile(selectedFilePath);
                newpictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
                // フォームに表示
                this.cardPanel.Controls.Add(newpictureBox);
            }
        }
    }
    public class DraggableRichTextBox : RichTextBox
    {
        private DragHandler dragHandler = new DragHandler();

        public DraggableRichTextBox()
        {
            this.MouseDown += new MouseEventHandler(dragHandler.HandleMouseDown);
            this.MouseMove += new MouseEventHandler(dragHandler.HandleMouseMove);
            this.MouseUp += new MouseEventHandler(dragHandler.HandleMouseUp);
        }
    }
    public class DraggablePictureBox : PictureBox
    {
        private DragHandler dragHandler = new DragHandler();

        public DraggablePictureBox()
        {
            this.MouseDown += new MouseEventHandler(dragHandler.HandleMouseDown);
            this.MouseMove += new MouseEventHandler(dragHandler.HandleMouseMove);
            this.MouseUp += new MouseEventHandler(dragHandler.HandleMouseUp);
        }
    }
    public class DragHandler
    {
        private bool isDragging = false;
        private Point startPoint;

        public void HandleMouseDown(object sender, MouseEventArgs e)
        {
            isDragging = true;
            startPoint = e.Location;
            
        }

        public void HandleMouseMove(object sender, MouseEventArgs e)
        {
            if (isDragging)
            {
                Control ctrl = sender as Control;
                ctrl.BringToFront();
                ctrl.Left += e.X - startPoint.X;
                ctrl.Top += e.Y - startPoint.Y;
            }
        }

        public void HandleMouseUp(object sender, MouseEventArgs e)
        {
            isDragging = false;
        }
    }
}
これ自体はやりたいことの条件を満たしているのですが,意見をもらっての疑問で、
インタフェースの処理が良いとの意見があって最初はそちらでやろうとしたのですが、調べてもインタフェースの活用がわからなかったので教えてほしいです。