2017年6月24日土曜日

C++でWindowsフォームアプリケーションどこに行ったか分からず再入門@VisualStudio2013


C++でWindowsFormを作りたかったが、VisualStudio2013に、昔あったような「Windowsフォームアプリケーション」が存在しない。

http://takacity.blog.fc2.com/blog-entry-85.html
によると「C++ Windows Forms」が新しいプロジェクトのオンラインにあるとのことだが、2017/6/15時点のVisualStudio2013には見つからず。
http://takacity.blog.fc2.com/blog-entry-84.html
を参考にさせていただき、進めてみる。

「新しいプロジェクト」から、「Visual C++」の「CLR」の「空のCLRプロジェクト」を選択する。名前は「ImageAnalysisModule」と付けておく。



右のプロジェクト名を右クリックし、「追加」の「新しい項目」をクリックする。
VisualC++のUIの「Windowsフォーム」を選択する。
名前は「TopForm.h」としておく。


 フォームができて、TopForm.cpp、TopForm.hができて、左側のTopForm.hデザインが開いている。


ソリューションのビルドを行うと、「error LNK1561:エントリーポイントを定義しなければなりません。」エラー。



TopForm.cppを開くと、#include "FopForm.h"しか書かれていないので、http://takacity.blog.fc2.com/blog-entry-84.htmlhttp://y-okamoto-psy1949.la.coocan.jp/booksetc/introvcpp/vs2012FormApp/ を参考に、埋める。
[STAThreadAttribute]を書く理由は、https://dobon.net/vb/dotnet/form/stathread.html が詳しい。




#include "TopForm.h"

using namespace ImageAnaylysisModule;

[STAThreadAttribute]
int main(){
    TopForm ^tm = gcnew TopForm();
    tm->ShowDialog();
    return 0;
}



ビルドが通った。デバッグ開始。


コマンドプロンプトの上にFormが表示される。Formを×で閉じると両方消えた。


コマンドプロンプトを消すには、プロジェクトを右クリックしてプロパティを選択し、「構成プロパティ」の「リンカー」の「システム」の、「サブシステム」を、デフォルトは空っぽなのを、「Windows (/SUBSYSTEM:WINDOWS)」を選択し、「構成プロパティ」の「リンカー」の「詳細設定」の、「エントリポイント」を、デフォルトは空っぽなのを、<編集>を選択し、「main」と入力する。
「適用」ボタンを押し、再度ビルド、デバッグ開始すると、コマンドプロンプトが出なくなる。(http://takacity.blog.fc2.com/blog-entry-84.htmlhttp://y-okamoto-psy1949.la.coocan.jp/booksetc/introvcpp/vs2012FormApp/










 ここから、なんとなくフォームにファイルをドラッグ&ドロップすると、リストにファイル名が追加され、ラベルにファイル名が入るようなものにしてみる。

Formにメニューを追加してみる。(参考:https://dobon.net/vb/dotnet/control/menustrip.html
左のバーから「ツールボックス」をクリックし、「全般」内の「MenuStrip」を、TopForm.hにドラッグ&ドロップする。左上のあたり。


クリックすると入力可能になるので、「ファイル(&F)」と入力する。表示は「ファイル(F)」になる。(Fはショートカットキー。)その下に「開く(&O)...」を入力する。参考URLによると、ダイアログボックスが開く場合にはピリオド3つつけるお作法があるとのこと。



ショートカットキーを画面に表示する場合、「開く」を右クリックしてプロパティを開いて、ShortcutKeyプロパティを変更する。デフォルトは「NONE」なので、Ctrlにチェック入れて、キーはOを選ぶ。「開く(O)...」の右隣りにCtrl+Oと追加される。




進捗状況を表示するステータスバーを作ってみる。(参考:https://dobon.net/vb/dotnet/control/sbprogresspanel.html
同様に左のバーから「ツールボックス」をクリックし、「全般」内の「statusStrip」を、TopForm.hにドラッグ&ドロップする。▼をクリックし、ProgresBarを選択する。ProgressBarの形になる。





全体的なレイアウト画面を作る。TableLayoutPanelで作ってみることにする。(参考:https://dobon.net/vb/dotnet/control/tlbeginning.html
左のバーから「ツールボックス」をクリックし、「全般」内の「TableLayoutPanel」を、TopForm.hの中にドラッグ&ドロップする。




デフォルトで2*2なので、列を追加してみる。右下のプロパティに「列の追加」があるのでクリックする。即座に列が追加される。

TableLayoutPanelの右下にListBoxを追加する。(ドラッグ&ドロップしたファイル名を次々表示する場所)


ToolTipを追加する。右向き▼をクリックし、DockをTopから左中央に変更する。ToolTipが横長から縦長に変更された。



ビルド、デバッグするとシンプルにこんな感じ。

上中央にラベルを置く。(今開いているファイル名を表示する)

次にドラッグ&ドロップしたファイル名をListBoxに追加、Labelにファイル名フルパスを記載してみる。(参考:https://dobon.net/vb/dotnet/control/droppedfile.html
TopFormをクリックし、プロパティの「AllowDrop」がデフォルトで「False」になっているので、「True」に変更する。


イベントボタン(プロパティにある黒い雷みたいなアイコン)をクリックする。
「ドラッグアンドドロップ内」、DragEnter(コントロールのクライアント領域内に、マウスポインターでアイテムをドラッグしたときに発生します)をダブルクリックする。
TopForm.hに行が追加される。





 #pragma endregion
    private: System::Void TopForm_DragEnter(System::Object^  sender, System::Windows::Forms::DragEventArgs^  e) {
    }
}; 


https://support.microsoft.com/ja-jp/help/815667/how-to-provide-file-drag-and-drop-functionality-in-a-visual-c-net-application-or-in-a-visual-c-2005-application に従い、コードを追加する。

#pragma endregion
    private: System::Void TopForm_DragEnter(System::Object^  sender, System::Windows::Forms::DragEventArgs^  e) {
                 if (e->Data->GetDataPresent(DataFormats::FileDrop)){
                     e->Effect = DragDropEffects::All;
                 }
                 else {
                     e->Effect = DragDropEffects::None;
                 }
    }
};


TopForm.h[デザイン]に戻り、次はlistBox1のプロパティを開き、イベントボタン(黒い雷)をクリックし、DragDropをダブルクリックする。

コードが自動生成される。

private: System::Void listBox1_DragDrop(System::Object^  sender, System::Windows::Forms::DragEventArgs^  e) {

}




コードを追加する。

String *fileDropList[] = (String *[]) e->Data->GetData(DataFormats::FileDrop, false); ←この書き方ではエラーが出て動かなかった(https://support.microsoft.com/ja-jp/help/815667/how-to-provide-file-drag-and-drop-functionality-in-a-visual-c-net-application-or-in-a-visual-c-2005-application を参考にしたが古い。)
http://blog.goo.ne.jp/uiweo8864/e/b49e5e8eb6992a1cbf6f3d199218912f もコンパイル通らず。
array^ strDropFile = (array<String^>^)e->Data->GetData( ::DataFormats::FileDrop, false );(http://www.program-lab.jp/blog/progmemo/archives/2006/04/dragdrop.html)のarray方法もコンパイル通らず。


 

結局、https://www.daniweb.com/programming/software-development/threads/341685/drag-and-drop の書き方がエラーが出なかった。
  array<String^> ^fileDropList = (array<String^>^) e->Data->GetData(DataFormats::FileDrop);

ただ、これではドラッグ&ドロップしても反応が無く、
http://www.program-lab.jp/blog/progmemo/archives/2006/04/dragdrop.html を参考に、以下の1行を追加すると、無事に表示されるようになった。
            this->DragEnter += gcnew System::Windows::Forms::DragEventHandler(this, &TopForm::TopForm_DragEnter); ←これは自動で入っていた
            this->DragDrop += gcnew System::Windows::Forms::DragEventHandler(this, &TopForm::listBox1_DragDrop); ←これが自動で入っていなかった



出力は、以下でメッセージボックスにフルパス、

for (int i = 0; i < fileDropList->Length; i++){
 MessageBox::Show(fileDropList[i], "test", MessageBoxButtons::OK, MessageBoxIcon::Information);
}




以下で、リストボックスにフルパス。

 listBox1->Items->Add(fileDropList[0]);
 


以下で、ラベルにフルパス。

label1->Text = fileDropList[0]; 



以下、ここまでの全コード。(TopForm.h)


#pragma once

#include <array>

namespace ImageAnaylysisModule {

    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;

    /// <summary>
    /// TopForm の概要
    /// </summary>
    public ref class TopForm : public System::Windows::Forms::Form
    {
    public:
        TopForm(void)
        {
            InitializeComponent();
            //
            //TODO: ここにコンストラクター コードを追加します
            //
        }

    protected:
        /// <summary>
        /// 使用中のリソースをすべてクリーンアップします。
        /// </summary>
        ~TopForm()
        {
            if (components)
            {
                delete components;
            }
        }
    private: System::Windows::Forms::MenuStrip^  menuStrip1;
    protected:
    private: System::Windows::Forms::ToolStripMenuItem^  ファイルFToolStripMenuItem;
    private: System::Windows::Forms::ToolStripMenuItem^  開くOToolStripMenuItem;
    private: System::Windows::Forms::StatusStrip^  statusStrip1;
    private: System::Windows::Forms::ToolStripProgressBar^  toolStripProgressBar1;
    private: System::Windows::Forms::TableLayoutPanel^  tableLayoutPanel1;
    private: System::Windows::Forms::ListBox^  listBox1;
    private: System::Windows::Forms::ToolStrip^  toolStrip1;
    private: System::Windows::Forms::Label^  label1;

    protected:

    private:
        /// <summary>
        /// 必要なデザイナー変数です。
        /// </summary>
        System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
        /// <summary>
        /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディターで変更しないでください。
        /// </summary>
        void InitializeComponent(void)
        {
            this->menuStrip1 = (gcnew System::Windows::Forms::MenuStrip());
            this->ファイルFToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
            this->開くOToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
            this->statusStrip1 = (gcnew System::Windows::Forms::StatusStrip());
            this->toolStripProgressBar1 = (gcnew System::Windows::Forms::ToolStripProgressBar());
            this->tableLayoutPanel1 = (gcnew System::Windows::Forms::TableLayoutPanel());
            this->listBox1 = (gcnew System::Windows::Forms::ListBox());
            this->label1 = (gcnew System::Windows::Forms::Label());
            this->toolStrip1 = (gcnew System::Windows::Forms::ToolStrip());
            this->menuStrip1->SuspendLayout();
            this->statusStrip1->SuspendLayout();
            this->tableLayoutPanel1->SuspendLayout();
            this->SuspendLayout();
            //
            // menuStrip1
            //
            this->menuStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(1) { this->ファイルFToolStripMenuItem });
            this->menuStrip1->Location = System::Drawing::Point(0, 0);
            this->menuStrip1->Name = L"menuStrip1";
            this->menuStrip1->Size = System::Drawing::Size(503, 26);
            this->menuStrip1->TabIndex = 0;
            this->menuStrip1->Text = L"menuStrip1";
            //
            // ファイルFToolStripMenuItem
            //
            this->ファイルFToolStripMenuItem->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(1) { this->開くOToolStripMenuItem });
            this->ファイルFToolStripMenuItem->Name = L"ファイルFToolStripMenuItem";
            this->ファイルFToolStripMenuItem->Size = System::Drawing::Size(85, 22);
            this->ファイルFToolStripMenuItem->Text = L"ファイル(&F)";
            //
            // 開くOToolStripMenuItem
            //
            this->開くOToolStripMenuItem->Name = L"開くOToolStripMenuItem";
            this->開くOToolStripMenuItem->ShortcutKeys = static_cast<System::Windows::Forms::Keys>((System::Windows::Forms::Keys::Control | System::Windows::Forms::Keys::O));
            this->開くOToolStripMenuItem->Size = System::Drawing::Size(179, 22);
            this->開くOToolStripMenuItem->Text = L"開く(&O)...";
            //
            // statusStrip1
            //
            this->statusStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(1) { this->toolStripProgressBar1 });
            this->statusStrip1->Location = System::Drawing::Point(0, 240);
            this->statusStrip1->Name = L"statusStrip1";
            this->statusStrip1->Size = System::Drawing::Size(503, 22);
            this->statusStrip1->TabIndex = 1;
            this->statusStrip1->Text = L"statusStrip1";
            //
            // toolStripProgressBar1
            //
            this->toolStripProgressBar1->Name = L"toolStripProgressBar1";
            this->toolStripProgressBar1->Size = System::Drawing::Size(100, 16);
            //
            // tableLayoutPanel1
            //
            this->tableLayoutPanel1->ColumnCount = 3;
            this->tableLayoutPanel1->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Percent,
                8.051948F)));
            this->tableLayoutPanel1->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Percent,
                91.94805F)));
            this->tableLayoutPanel1->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute,
                94)));
            this->tableLayoutPanel1->Controls->Add(this->listBox1, 2, 1);
            this->tableLayoutPanel1->Controls->Add(this->label1, 1, 0);
            this->tableLayoutPanel1->Location = System::Drawing::Point(29, 29);
            this->tableLayoutPanel1->Name = L"tableLayoutPanel1";
            this->tableLayoutPanel1->RowCount = 2;
            this->tableLayoutPanel1->RowStyles->Add((gcnew System::Windows::Forms::RowStyle(System::Windows::Forms::SizeType::Percent, 13.46154F)));
            this->tableLayoutPanel1->RowStyles->Add((gcnew System::Windows::Forms::RowStyle(System::Windows::Forms::SizeType::Percent, 86.53846F)));
            this->tableLayoutPanel1->Size = System::Drawing::Size(462, 208);
            this->tableLayoutPanel1->TabIndex = 2;
            //
            // listBox1
            //
            this->listBox1->FormattingEnabled = true;
            this->listBox1->ItemHeight = 12;
            this->listBox1->Location = System::Drawing::Point(370, 31);
            this->listBox1->Name = L"listBox1";
            this->listBox1->Size = System::Drawing::Size(88, 88);
            this->listBox1->TabIndex = 0;
            this->listBox1->DragDrop += gcnew System::Windows::Forms::DragEventHandler(this, &TopForm::listBox1_DragDrop);
            //
            // label1
            //
            this->label1->AutoSize = true;
            this->label1->Location = System::Drawing::Point(32, 0);
            this->label1->Name = L"label1";
            this->label1->Size = System::Drawing::Size(35, 12);
            this->label1->TabIndex = 1;
            this->label1->Text = L"label1";
            //
            // toolStrip1
            //
            this->toolStrip1->Dock = System::Windows::Forms::DockStyle::Left;
            this->toolStrip1->Location = System::Drawing::Point(0, 26);
            this->toolStrip1->Name = L"toolStrip1";
            this->toolStrip1->Size = System::Drawing::Size(26, 214);
            this->toolStrip1->TabIndex = 3;
            this->toolStrip1->Text = L"toolStrip1";
            //
            // TopForm
            //
            this->AllowDrop = true;
            this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
            this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
            this->ClientSize = System::Drawing::Size(503, 262);
            this->Controls->Add(this->toolStrip1);
            this->Controls->Add(this->tableLayoutPanel1);
            this->Controls->Add(this->statusStrip1);
            this->Controls->Add(this->menuStrip1);
            this->MainMenuStrip = this->menuStrip1;
            this->Name = L"TopForm";
            this->Text = L"TopForm";
            this->DragEnter += gcnew System::Windows::Forms::DragEventHandler(this, &TopForm::TopForm_DragEnter);
            this->DragDrop += gcnew System::Windows::Forms::DragEventHandler(this, &TopForm::listBox1_DragDrop);
            this->menuStrip1->ResumeLayout(false);
            this->menuStrip1->PerformLayout();
            this->statusStrip1->ResumeLayout(false);
            this->statusStrip1->PerformLayout();
            this->tableLayoutPanel1->ResumeLayout(false);
            this->tableLayoutPanel1->PerformLayout();
            this->ResumeLayout(false);
            this->PerformLayout();

        }
#pragma endregion
    private: System::Void TopForm_DragEnter(System::Object^  sender, System::Windows::Forms::DragEventArgs^  e) {
                 if (e->Data->GetDataPresent(DataFormats::FileDrop)){
                     e->Effect = DragDropEffects::All;
                    // e->Effect = DragDropEffects::Move;
                 }
                 else {
                     e->Effect = DragDropEffects::None;
                 }
    }
    private: System::Void listBox1_DragDrop(System::Object^  sender, System::Windows::Forms::DragEventArgs^  e) {
                 array<String^> ^fileDropList = (array<String^>^) e->Data->GetData(DataFormats::FileDrop);
                if (!fileDropList)
                    return;
                // for (int i = 0; i < fileDropList->Length; i++){
                //     MessageBox::Show(fileDropList[i], "test", MessageBoxButtons::OK, MessageBoxIcon::Information);
                // }
                 listBox1->Items->Add(fileDropList[0]);
                 label1->Text = fileDropList[0];



                //String *fileDropList[] = (String *[]) e->Data->GetData(DataFormats::FileDrop, false);
                //listBox1->Items->Add(fileDropList[0]);
    }
};
}