質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

4回答

4128閲覧

C# Windowsフォームアプリケーション開発、描いた直線を残したまま、再度直線を描画したい。

Nathalie_22

総合スコア10

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2020/02/08 03:56

前提・実現したいこと

現在、Windowsフォームアプリケーションを開発しています。
コード記述のプログラミング言語はC#です。
今の時点で実現できていることは直線の始点を左クリックして、もう一度左クリックすることで終点を決め、その二点を結ぶ直線を描くことはできています。
DrawLineメソッドです。
pictureBox内に表示させています。

実装したいこと
直線を一つ描画はできるのですが、線と線をつないで図形を描きたい場合など複数描ける必要があります。
しかし、同記述していけばいいかわからなかったので、どなたか助けていただけないでしょうか?
以下がソースコードです。

発生している問題・エラーメッセージ

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Console;

public partial class Form1 : Form
{

/// <summary> /// 各変数の定義など /// </summary> //描画する線の種類のボタンがクリックされた場合の機能を実装するためのスイッチON/OFFを観察するための変数 private bool btnSolidWasClicked = false;

     //左クリックで始点(lsp)と終点(lep)を選択するために変数定義
//MouseButtons.Left
private Point lsp = new Point();
private Point lep = new Point();
//左クリックされたときにtrueかfalseかどうかで始点か終点か判断
private Boolean lsp_flag;

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (btnSolidWasClicked )
{
//描画先とするImageオブジェクトを作成
Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);
//ImageオブジェクトのGraphicsオブジェクトを作成
Graphics g = Graphics.FromImage(canvas);
//線を滑らかにする
g.SmoothingMode = SmoothingMode.AntiAlias;
//Penオブジェクトの作成
Pen GreenPen = new Pen(Color.White, 3);

//直線の種類は実線 GreenPen.DashStyle = DashStyle.Solid; //座標の表示 label1.Text = string.Format("Screen Position : {0:d}, {1:d}", Cursor.Position.X, Cursor.Position.Y); if (lsp_flag) //終点の処理 { lep = e.Location; g.DrawLine(GreenPen, lsp, lep); //リソースを開放 GreenPen.Dispose(); g.Dispose(); lsp_flag = false; //Picture1に表示 pictureBox1.Image = canvas; } else //始点の処理 { lsp = e.Location; g.DrawRectangle(GreenPen, lsp.X, lsp.Y, 0.1f, 0.1f); //リソースを開放 GreenPen.Dispose(); g.Dispose(); lsp_flag = true; //Picture1に表示 pictureBox1.Image = canvas; } }

     }
}

試したこと

始点の処理と終点の処理を分けて書こうと思い、始点をMouseDownイベント、終点の処理をMouseUpイベントで書きましたがうまくいきませんでした。

現在はすべてMouseDownイベント内に書いています。

補足情報(FW/ツールのバージョンなど)

開発環境 Visual studio2019 community edition
C# windows form application

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YAmaGNZ

2020/02/08 04:18

3回クリックしたら、その3点を直線で繋ぐ(直線を2本引く)ということですか?
guest

回答4

0

ベストアンサー

問題点は

直線を一つ描画はできるのですが、線と線をつないで図形を描きたい場合など複数描ける必要があります。

ということで私が思うに 「線が一度はかけるけど複数回書き足すことができないとうい意味だと理解しました。」

その点に絞って解答させていただきます。

pictureBox1と同じサイズのcanvasを作成し、描画後
pictureBox1.Image = canvas;
でpictureBox1.Imageに反映させていますが、これだと常に新しいキャンバスが生成されそれを
pictureBox1.Imageに代入します。この流れが間違えているのではないでしょうか?

前回の続きで処理をするならば、canvasを新しく生成せず。保持する(引継ぐ)べきですよ。

投稿2020/02/08 04:44

kgreenjp

総合スコア97

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YAmaGNZ

2020/02/08 04:47

確かにそうですね。 そこまでソースを見てませんでした。
kgreenjp

2020/02/08 04:56

お気になさらず。質問者の手助けになればOKだと私は思っています。 コメントありがとうございます。
guest

0

いじっていたら跡形がなくなってしまったのですが、何かの参考になれば。

始点をMouseDownイベント、終点の処理をMouseUpイベント

線の引き方にこだわりはなさそうなので「ペイント」のようなドラッグ方式です。

cs:Form1.cs

1using System; 2using System.Drawing; 3using System.Drawing.Drawing2D; 4using System.Linq; 5using System.Windows.Forms; 6 7namespace Questions240161 8{ 9 public partial class Form1 : Form 10 { 11 private readonly ToolStripButton[] modeButtons; 12 private readonly ToolStripButton[] colorButtons; 13 14 private Point startPoint; 15 private Point endPoint; 16 17 private Color penColor = Color.Black; 18 private int penSize => (int)toolStripComboBox1.SelectedItem; 19 20 private bool isPencilMode => toolStripButton1.Checked; 21 private bool isLineMode => toolStripButton2.Checked; 22 private bool isLineDragging; 23 24 public Form1() 25 { 26 InitializeComponent(); 27 28 pictureBox1.Image = new Bitmap(800, 600); 29 30 modeButtons = new[] { toolStripButton1, toolStripButton2, }; 31 modeButtons[0].Checked = true; 32 33 toolStripComboBox1.ComboBox.DataSource = Enumerable.Range(1, 10).ToList(); 34 toolStripComboBox1.SelectedIndex = 2; 35 36 colorButtons = new[] { toolStripButton3, toolStripButton4, }; 37 colorButtons[0].Checked = true; 38 } 39 40 private void PictureBox1_Paint(object sender, PaintEventArgs e) 41 { 42 if(!pictureBox1.Capture) return; 43 if(!isLineDragging) return; 44 45 using(var pen = new Pen(penColor, penSize)) 46 { 47 e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; 48 e.Graphics.DrawLine(pen, startPoint, endPoint); 49 } 50 } 51 private void PictureBox1_MouseDown(object sender, MouseEventArgs e) 52 { 53 startPoint = e.Location; 54 if(isLineMode) isLineDragging = true; 55 } 56 private void PictureBox1_MouseMove(object sender, MouseEventArgs e) 57 { 58 SetMessage($"Position : {e.X}, {e.Y}"); 59 if(!pictureBox1.Capture) return; 60 61 endPoint = e.Location; 62 if(isPencilMode) 63 { 64 DrawLine(LineCap.Round); 65 startPoint = endPoint; 66 } 67 68 if(isLineMode) pictureBox1.Invalidate(); 69 } 70 private void PictureBox1_MouseUp(object sender, MouseEventArgs e) 71 { 72 if(!isLineDragging) return; 73 74 isLineDragging = false; 75 if(isLineMode) DrawLine(); 76 } 77 78 private void DrawLine(LineCap lineCap = LineCap.Flat) 79 { 80 using(var g = Graphics.FromImage(pictureBox1.Image)) 81 using(var pen = new Pen(penColor, penSize) { StartCap = lineCap, EndCap = lineCap }) 82 { 83 g.SmoothingMode = SmoothingMode.AntiAlias; 84 g.DrawLine(pen, startPoint, endPoint); 85 pictureBox1.Image = pictureBox1.Image; // 再割り当てしないと反映されない?? 86 } 87 } 88 89 private void ToolStripModeButton_Click(object sender, EventArgs e) 90 { 91 foreach(var b in modeButtons) b.Checked = sender == b; 92 } 93 private void ToolStripColorButton_Click(object sender, EventArgs e) 94 { 95 foreach(var b in colorButtons) b.Checked = sender == b; 96 97 penColor = ((ToolStripButton)sender).ForeColor; 98 } 99 100 private void SetMessage(string value) => toolStripStatusLabel1.Text = value; 101 } 102}

cs:Form1.Designer.cs

1namespace Questions240161 2{ 3 partial class Form1 4 { 5 private System.ComponentModel.IContainer components = null; 6 7 protected override void Dispose(bool disposing) 8 { 9 if(disposing && (components != null)) 10 { 11 components.Dispose(); 12 } 13 base.Dispose(disposing); 14 } 15 16 #region Windows フォーム デザイナーで生成されたコード 17 private void InitializeComponent() 18 { 19 this.pictureBox1 = new System.Windows.Forms.PictureBox(); 20 this.panel1 = new System.Windows.Forms.Panel(); 21 this.toolStrip1 = new System.Windows.Forms.ToolStrip(); 22 this.toolStripButton1 = new System.Windows.Forms.ToolStripButton(); 23 this.toolStripButton2 = new System.Windows.Forms.ToolStripButton(); 24 this.toolStripComboBox1 = new System.Windows.Forms.ToolStripComboBox(); 25 this.toolStripButton3 = new System.Windows.Forms.ToolStripButton(); 26 this.toolStripButton4 = new System.Windows.Forms.ToolStripButton(); 27 this.statusStrip1 = new System.Windows.Forms.StatusStrip(); 28 this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); 29 ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); 30 this.panel1.SuspendLayout(); 31 this.toolStrip1.SuspendLayout(); 32 this.statusStrip1.SuspendLayout(); 33 this.SuspendLayout(); 34 35 this.pictureBox1.BackColor = System.Drawing.Color.White; 36 this.pictureBox1.Location = new System.Drawing.Point(0, 0); 37 this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; 38 this.pictureBox1.TabStop = false; 39 this.pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.PictureBox1_Paint); 40 this.pictureBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.PictureBox1_MouseDown); 41 this.pictureBox1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PictureBox1_MouseMove); 42 this.pictureBox1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.PictureBox1_MouseUp); 43 44 this.panel1.AutoScroll = true; 45 this.panel1.Controls.Add(this.pictureBox1); 46 this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; 47 48 this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 49 this.toolStripButton1, 50 this.toolStripButton2, 51 this.toolStripComboBox1, 52 this.toolStripButton3, 53 this.toolStripButton4}); 54 55 this.toolStripButton1.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; 56 this.toolStripButton1.Text = "Pen"; 57 this.toolStripButton1.Click += new System.EventHandler(this.ToolStripModeButton_Click); 58 59 this.toolStripButton2.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; 60 this.toolStripButton2.Text = "Line"; 61 this.toolStripButton2.Click += new System.EventHandler(this.ToolStripModeButton_Click); 62 63 this.toolStripComboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 64 65 this.toolStripButton3.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; 66 this.toolStripButton3.Font = new System.Drawing.Font("メイリオ", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128))); 67 this.toolStripButton3.ForeColor = System.Drawing.Color.Black; 68 this.toolStripButton3.Text = "■"; 69 this.toolStripButton3.Click += new System.EventHandler(this.ToolStripColorButton_Click); 70 71 this.toolStripButton4.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; 72 this.toolStripButton4.ForeColor = System.Drawing.Color.Red; 73 this.toolStripButton4.Text = "■"; 74 this.toolStripButton4.Click += new System.EventHandler(this.ToolStripColorButton_Click); 75 76 this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 77 this.toolStripStatusLabel1}); 78 79 this.ClientSize = new System.Drawing.Size(800, 450); 80 this.Controls.Add(this.panel1); 81 this.Controls.Add(this.statusStrip1); 82 this.Controls.Add(this.toolStrip1); 83 ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); 84 this.panel1.ResumeLayout(false); 85 this.panel1.PerformLayout(); 86 this.toolStrip1.ResumeLayout(false); 87 this.toolStrip1.PerformLayout(); 88 this.statusStrip1.ResumeLayout(false); 89 this.statusStrip1.PerformLayout(); 90 this.ResumeLayout(false); 91 this.PerformLayout(); 92 93 } 94 #endregion 95 96 private System.Windows.Forms.PictureBox pictureBox1; 97 private System.Windows.Forms.Panel panel1; 98 private System.Windows.Forms.ToolStrip toolStrip1; 99 private System.Windows.Forms.ToolStripButton toolStripButton1; 100 private System.Windows.Forms.ToolStripButton toolStripButton2; 101 private System.Windows.Forms.ToolStripComboBox toolStripComboBox1; 102 private System.Windows.Forms.ToolStripButton toolStripButton3; 103 private System.Windows.Forms.ToolStripButton toolStripButton4; 104 private System.Windows.Forms.StatusStrip statusStrip1; 105 private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; 106 } 107}

Designer.csを限界まで削ったので何か不具合があるかもしれません^^;

投稿2020/02/11 12:39

編集2023/07/20 12:57
TN8001

総合スコア9862

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Imageオブジェクトを使わずにGraphicsオブジェクトを採用しました。また、線の描画の後、始点の更新など追加したことで無事複数の線を描画することができました。
下記が修正後のコードを一部抜粋したものです。
ご回答してくださった方々ありがとうございました。

C#

1private void pictureBox1_MouseDown(object sender, MouseEventArgs e) 2 { 3 4 5 6 7 if (btnSolidWasClicked) 8 { 9 //Graphicsオブジェクトを作成 10 Graphics g = this.pictureBox1.CreateGraphics(); 11 g.SmoothingMode = SmoothingMode.AntiAlias; 12 //Penオブジェクトの作成 13 Pen GreenPen = new Pen(Color.White, 3); 14 //破線 15 GreenPen.DashStyle = DashStyle.Solid; 16 //座標の表示 17 label1.Text = string.Format("Screen Position : {0:d}, {1:d}", 18 Cursor.Position.X, Cursor.Position.Y); 19 20 if (lsp_flag) 21 { 22 lep = e.Location; 23 g.DrawLine(GreenPen, lsp, lep); 24 lsp = lep; 25 g.Dispose(); 26 GreenPen.Dispose(); 27 } else 28 { 29 lsp = e.Location; 30 g.DrawRectangle(GreenPen, lsp.X, lsp.Y, 0.1f, 0.1f); 31 g.Dispose(); 32 GreenPen.Dispose(); 33 lsp_flag = true; 34 } 35 //右クリックで終点判断 36 if (e.Button == MouseButtons.Right) 37 { 38 lsp_flag = false; 39 } 40 41 42 } 43}

投稿2020/02/11 10:19

Nathalie_22

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2020/02/11 11:03

ウィンドウのリサイズや最小化から戻したときなどで、線が消えてしまいませんか? それで十分ならすいません。
YAmaGNZ

2020/02/11 11:23

pictureBox1.CreateGraphicsだとPicutreBox自体の描画に使われるGraphicsオブジェクトなのでImageプロパティにセットする画像と関係ない部分での描画となります。 この為、再描画が行われると標準のコントロールの描画が行われて、描いた線が消えます。 Imageプロパティに設定した画像からGraphicsオブジェクトを作成すべきです。
guest

0

点Aをクリック
点Bをクリック(点A-点Bの直線を描画)
点Cをクリック(点B-点Cの直線を描画)

という動作であれば

・最初のクリック
始点保持のフラグが立っていないので始点としてクリック座標を記憶
始点を保持したとフラグを立てる

・2回目以降のクリック
始点保持のフラグが立っているので始点とクリック座標間で直線を描画
クリック座標を始点として保持

このような処理を行えばいいのではないでしょうか。

もし、この後にUNDO機能など考えているのであれば、クリックされた座標をList<Point>なりで保持しGraphics.DrawLinesメソッドにて描画するなど考えた方がいいかもしれません。

投稿2020/02/08 04:34

YAmaGNZ

総合スコア10489

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問