コンボボックスにファイルをドラッグ&ドロップするには? – プログラミング – Home

コンボボックスにファイルをドラッグ&ド...
 
通知
すべてクリア

コンボボックスにファイルをドラッグ&ドロップするには?

固定ページ 1 / 4

リンク
 リンク
(@リンク)
ゲスト
結合: 22年前
投稿: 35
Topic starter  

こんにちわ。
VC++6.0ダイアログベースで、
ドロップダウンリスト型コンボボックスに
エクスプローラからファイルをドラッグ&ドロップして
そのファイル名をコンボボックスのリストボックスの項目に
追加し選択したいのですがどうすればいいですか?

【WM_DROPFILES】というメッセージが関係あると思うのですが
コンボボックスではないのでしょうか?
ダイアログでドラッグ&ドロップはできそうなのですが・・・
教えて下さい。


引用解決済
トピックタグ
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

1.リソースのコンボボックスのプロパティの ドラックドロップを許可 にチェックを入
れる。

2.CComboBoxのサブクラス(説明しやすいようにCDropComboBoxとする)を新規作成し、
WM_DROPFILES ハンドラを作成する。

下記のURLはCEditの場合です。参考にはなると思います。
http://homepage2.nifty.com/DSS/VCPP/MFC/CEdit/CEditFileDrop.htm

3.ダイアログクラスにCDropComboBox型のコントロール変数を追加する。

って感じでどうでしょうか?


返信引用
リンク
 リンク
(@リンク)
ゲスト
結合: 22年前
投稿: 35
Topic starter  

Blueさんありがとうございます。

CDropComboBoxというクラスを基本クラスCComboboxで作成し、WM_DROPFILESの関数を作
成しました。そしてダイアログクラス CSelLogFile で型CDropComboBoxでコンボボック
スのコントロール変数を作成すると、以下のエラーが発生しました。
派生クラスなど作成したことないのでどうすればいいわかりません。色々やってみたん
ですが・・・

\sellogfile.h(22) : error C2146: 構文エラー : ';' が、識別子 'm_DropCmb1_Ctrl' の
前に必要です。
\sellogfile.h(22) : error C2501: 'CDropComboBox' : 識別名を宣言するのに、型が指
定されていません。
\sellogfile.h(22) : error C2501: 'm_DropCmb1_Ctrl' : 識別名を宣言するのに、型が
指定されていません。


返信引用
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

ClassWizardでコントロール変数を追加下ということでよいのですよね?
そうすると、注意を促すメッセージボックスが出ると思うのですけど。

ダイアログクラスのヘッダに #include DropComboBox.h の一文を追加してください。


返信引用
リンク
 リンク
(@リンク)
ゲスト
結合: 22年前
投稿: 35
Topic starter  

ヘッダのほうにインクルードするのですね。
できました。できました。
ありがとうございます。
あとはファイル名を取得できれば解決です。
やってみます。


返信引用
リンク
 リンク
(@リンク)
ゲスト
結合: 22年前
投稿: 35
Topic starter  

Blueさんもうひとつ質問いいですか?
ファイル名はBlueさんの例のおかげで取得できたのですが
新規作成したCDropComboBoxクラス内関数OnDropFiles()内で
ダイアログクラス CSelLogFile のメンバ変数(さきほど作成した_DropCmb1_Ctrl)
を用いてCComboBox::InsertStringなどの関数を使いたいのですがどうやるのでしょう
か?
さきほどから色々やってるのですがうまくいかなくて・・・


返信引用
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

自分自身(this)ではなくて?

例えば

void CDropComboBox::OnDropFiles(HDROP hDropInfo)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォル
トの処理を呼び出してください
UINT files;
TCHAR path[ MAX_PATH ];

// ドロップされたファイル数を取得
files = ::DragQueryFile( hDropInfo, UINT_MAX, NULL, 0);

for ( UINT i = 0; i < files; i++ )
{
::DragQueryFile( hDropInfo, i, path, sizeof( path ) / sizeof(
TCHAR ) );
this->AddString( path ); // 末尾に追加
if ( !i ) this->SetWindowText( path );
}

CComboBox::OnDropFiles(hDropInfo);
}


返信引用
リンク
 リンク
(@リンク)
ゲスト
結合: 22年前
投稿: 35
Topic starter  

えっ?このCDropComboBoxクラス内では
すでにコンボボックスのコントロール扱いになるのですか?

私がやりたかったのは通常コンボボックスを操作する時
コントロール変数を作成し(例えばm_DropCmb1_Ctrl)、

m_DropCmb1_Ctrl.AddString;

と記述すると思いますが、
CDropComboBoxクラス内でこのようにアクセスするとえらーになります。
今閃いたのですが、この時は元のダイアログクラスのヘッダをインクルードし、

CSelLogFile dlg;

dlg.m_DropCmb1_Ctrl.AddString;

と記述すればできると思うんですが・・

これってBlueさんのthisのやり方と同じことですよね?


返信引用
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

> えっ?このCDropComboBoxクラス内では
> すでにコンボボックスのコントロール扱いになるのですか?
そうです。
ただ、どのコンボボックスかというのは、実体をつくらないとわかりませんけど。

> これってBlueさんのthisのやり方と同じことですよね?
全然違いますよ。
そのやりかただと、そのダイアログのコンボボックスだけにしか対応できません。
例えば、ダイアログに 3つ CDropComboBox を配置したらどうなりますか?


返信引用
リンク
 リンク
(@リンク)
ゲスト
結合: 22年前
投稿: 35
Topic starter  

>ただ、どのコンボボックスかというのは、実体をつくらないとわかりませんけど。

なるほど。ようするにCDropComboBoxでコントロール変数を宣言している全てのコンボボ
ックスに対してアクセス可能というわけですね。
しかし実体とやらを作るのはどうやるのでしょうか?

>例えば、ダイアログに 3つ CDropComboBox を配置したらどうなりますか?

CSelLogFile dlg;

dlg.m_DropCmb1_Ctrl.AddString;
dlg.m_DropCmb2_Ctrl.AddString;
dlg.m_DropCmb3_Ctrl.AddString;

ではだめですかね?

ちなみに私がやりたいことの詳細は、
--------------------------------------------------------------
CSelLogFileにはコンボボックス1つとボタン1つしかありません。
ボタン押下でコモンダイアログを表示しファイルを選択します。
また、ドラッグ&ドロップもできるようにします。
コンボボックスの項目数は最大5つです。
項目が5つある時ファイルが選択されたら最古文字列を削除し、
項目の先頭に今選択されたファイルを追加したいのです。
---------------------------------------------------------------
このような仕様の場合、どういうやり方が最適だと思いますか?


返信引用
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

> ではだめですかね?
うーむ。。。

わかりにくいかもしれませんがMFC関係なしのサンプルです。
mainをダイアログ, barをCDropComboBox, TestメソッドはDropイベントとして考えてみ
てください。

#pragma warning( disable : 4786 )

#include <vector>
#include <string>
#include <iostream>

using namespace std;

class Foo
{
private:
vector< string > m_list; // 文字列リスト
public:

void AddString( const string& s ) // 追加
{
m_list.push_back( s );
}
void ShowList() const // 表示
{
cout << ----------------- << endl;
for ( vector< string >::const_iterator it = m_list.begin(); it !=
m_list.end(); ++it )
{
cout << *it << endl;
}
cout << ----------------- << endl;
}
};

class Bar : public Foo
{
public:
void Test() // 任意のメソッド
{
AddString( TEST );
AddString( test );
}
};

int main()
{
Bar b1, b2, b3;

b1.AddString( abc );
b2.AddString( abc );
b3.AddString( abc );

b1.AddString( efg );
b2.AddString( efg );
b3.AddString( efg );

b1.Test();
b3.Test();

cout << b1 << endl;
b1.ShowList();

cout << b2 << endl;
b2.ShowList();

cout << b3 << endl;
b3.ShowList();

return 0;
}

> このような仕様の場合、どういうやり方が最適だと思いますか?
の場合、AddStringメソッドのようなCComboBoxの持っているメソッドではなく、
自作のメソッドで文字列追加をするようにすれば良いでしょう。
(そのメソッドからはCCombBox::AddStringを呼ぶが。)

> コンボボックスの項目数は最大5つです。
というのも、CDropComboBoxのメンバにするとか。


返信引用
リンク
 リンク
(@リンク)
ゲスト
結合: 22年前
投稿: 35
Topic starter  

>の場合、AddStringメソッドのようなCComboBoxの持っているメソッドではなく、
自作のメソッドで文字列追加をするようにすれば良いでしょう。
(そのメソッドからはCCombBox::AddStringを呼ぶが。)

ダイアログクラスでやっている処理と同じ処理をドラッグ&ドロップ時も行いたいので
この処理をメンバ関数にして両方でコールするというのはどうでしょうか?
以下はボタン押下時の処理です。
このファイルパス取得以後の処理をサブルーチン化し引数にファイル名を。

void CSelLogFile::OnButton1Commonfile()
{
// TODO: この位置にコントロール通知ハンドラ用のコードを追加してくださ

CString str;
int ret, i, num;
CFileDialog dlg( TRUE, NULL, NULL, OFN_HIDEREADONLY |
OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST, szFilter, NULL );
dlg.m_ofn.lpstrTitle = ログファイルの選択;

// キャンセルボタンが押された時
if( dlg.DoModal() != IDOK ) return;

// 選択されたファイルのフルパスを取得する
str = dlg.GetPathName();

// コンボボックスのリストボックスに選択されたファイルがあるか検索する
ret = m_DropCmb1_Ctrl.SelectString(-1,str);

// 見つからなかったとき
if( CB_ERR == ret ){
// コンボボックスの項目数を取得する
num = m_DropCmb1_Ctrl.GetCount();

// 最大コンボボックスの項目数以上のとき
if(num >= MAX_COMBO_LIST_NUM ){
// 項目削除
for( i=(MAX_COMBO_LIST_NUM-1); i<num; i++ ){
m_DropCmb1_Ctrl.DeleteString(i);
}
}

// リストボックスの先頭に追加し、選択する
m_DropCmb1_Ctrl.InsertString(0,str);
m_DropCmb1_Ctrl.SetCurSel(0);
}
else{
// 見つかったファイルを項目から削除し、先頭に追加し、選択する
m_DropCmb1_Ctrl.DeleteString(ret);
m_DropCmb1_Ctrl.InsertString(0, str);
m_DropCmb1_Ctrl.SetCurSel(0);
}
}


返信引用
REE
 REE
(@REE)
ゲスト
結合: 23年前
投稿: 240
 

>えっ?このCDropComboBoxクラス内では
>すでにコンボボックスのコントロール扱いになるのですか?

というか、このクラスはコンボボックスのコントロールそのものです。
このクラスは、CComboBoxを派生していますので、その機能をそのまま持っています。

m_DropCmb1_Ctrlの型もCDropComboBoxになっているはずですので確認してみてください。

>CSelLogFile dlg;
>dlg.m_DropCmb1_Ctrl.AddString;

ちなみにこれは問題外です。
なぜかというと、これでは、新しくダイアログを作り、その中のコンボボックス
(当然ドロップされたコンボボックスとは別のもの)に追加することになってしまいます。


返信引用
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

> 自作のメソッドで文字列追加をするようにすれば良いでしょう。
> (そのメソッドからはCCombBox::AddStringを呼ぶが。)
AddStringをオーバーライドするとこんな感じ。

// DropComboBox.h : ヘッダー ファイル
・・・
class CDropComboBox : public CComboBox
{
・・・
public:
int m_Max; // 最大ストック数
int AddString( LPCTSTR lpszString );
};

---------------------------------------------------------

// DropComboBox.cpp : インプリメンテーション ファイル
・・・

int CDropComboBox::AddString( LPCTSTR lpszString )
{
// 重複
if ( this->FindString( -1, lpszString ) != CB_ERR )
{
return CB_ERR;
}
// ストック数
if ( this->m_Max )
{
if ( this->m_Max == this->GetCount() )
{
this->DeleteString( 0 );
}
}
return ( ( CComboBox* )this )->AddString( lpszString );
}

---------------------------------------------------------
// SelLogFile.cpp : インプリメンテーション ファイル
・・・
BOOL CSelLogFile::OnInitDialog()
{
・・・
// TODO: 特別な初期化を行う時はこの場所に追加してください。
this->m_Test.m_Max = 5; // 最大数設定

return TRUE; // TRUE を返すとコントロールに設定したフォーカスは失われませ
ん。
}

void CSelLogFile::OnButton1Commonfile()
{
// このなかでは、数や重複のことは気にしないで、AddStringで追加していく。
}


返信引用
リンク
 リンク
(@リンク)
ゲスト
結合: 22年前
投稿: 35
Topic starter  

>なぜかというと、これでは、新しくダイアログを作り、その中のコンボボックス
(当然ドロップされたコンボボックスとは別のもの)に追加することになってしまいま
す。

え?そんなことはないと思うんですが・・・

CSelLogFile dlg;
dlg.m_DropCmb1_Ctrl.AddString

こうすると、CSelLogFileのメンバ変数を参照できるはずですけど。
dlgはCSelLogFile クラスのthisポインタと同じ働きになると認識しています。
実際、このやり方で他クラスのメンバ変数に値を代入したりリードしたりしたことがあ
るのですが!?


返信引用
固定ページ 1 / 4

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました