ジメジメする梅雨のお悩み、一挙解決! >>

C#、listboxについての質問です。

二つのリストボックスがあるとします。
・listBox1
・listBox2

listBox1にはアイテムが複数セットされている状態です。
アイテムが選択されいている状態でrightbuttonをクリックすると
listBox2にアイテムが移動します(lisytBox1でそのアイテムはremove)

もしかしたら間違えてlistBox2に移動する可能性もあるので2から1へ
アイテムを戻すlefghtbuttonも用意します。

そこで質問です。
そのときに2から1へ戻ったとき、普通にAdd()するのではなく、移動する前の状態の位置に戻したいのです。

普通にやると末端に追加されます。

ロジックが思いつきません。
お力添えのほどよろしくお願いいたします。

A 回答 (4件)

listBox1に追加するオブジェクトに,本来の並び順を保持させておいて,


戻す時にはオブジェクトの並び順を見てInsertする位置を決めればよいでしょう。

ListBoxに追加できるのは文字列だけでなく,どんなオブジェクトでも追加できます。
また,要素の表示はListBoxのDisplayMemberで決定されますが,DisplayMemberを指定していない場合はToStringが使われます。

なので,
class Item : IComparable<Item>
{
public Item (string display, int defaultOrder)
{
Display = display;
DefaultOrder = defaultOrder;
}

public string Display { get; private set; }
public int DefaultOrder { get; private set; }

int IComparable<Item>.CompareTo (Item other)
{
if (other == null) { return 1; }
return DefaultOrder.CompareTo(other.DefaultOrder);
}

public override string ToString ()
{
return Display;
}
}
というようなクラスを作り,このItemクラスをlistBox1, listBox2の要素としておけば,
var pos = listBox1.Items.Cast<Item>().ToList().BinarySearch(addItem);
if (pos < 0) { pos = ~pos; }
listBox1.Items.Insert(pos, addItem);
で戻すことができます。
    • good
    • 0

というワケで…簡単に作ってみました。


検証不十分と思われますので、地道に検証してくださいな。

ちなみに、プロパティでbutton1(rightbutton相当)とbutton2(lefghtbutton相当)のEnabledはfalseに、
listBox1のItemsにはあらかじめデータ入れておいてください。
あと、全角空白でインデントしていますのでよろしく処理してください。
コメントも特に入れていないので自力で読んでください。

public partial class Form1 : Form
{
 private Stack<MoveItemHistory> History;
 public Form1()
 {
  InitializeComponent();
  History = new Stack<MoveItemHistory>();
 }
 private void button1_Click(object sender, EventArgs e)
 {
  MoveItemHistory temp = new MoveItemHistory();

  temp.Index = listBox1.SelectedIndex;
  temp.ItemString = (string)listBox1.Items[temp.Index];
  listBox2.Items.Add(temp.ItemString);
  listBox1.Items.RemoveAt(temp.Index);
  listBox1.SelectedIndex = -1;
  History.Push(temp);
  button2.Enabled = true;
 }
 private void button2_Click(object sender, EventArgs e)
 {
  MoveItemHistory temp = History.Pop();

  button2.Enabled = (History.Count > 0);
  listBox2.Items.Remove(temp.ItemString);
  listBox1.Items.Insert(temp.Index, temp.ItemString);
 }
 private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
 {
  button1.Enabled = (listBox1.SelectedIndex != -1);
 }
}
public class MoveItemHistory
{
 public int Index;
 public string ItemString;
}
    • good
    • 0

>そうするとlistBox1の5番目[りんご]


>をlistBox2に移動し、他のアイテムも複数移動したら
>listBox1の配列のCountは(例えば)2つとかになりますよね。
>listBox2からlistBox1に戻すときに5番目、(移動するときに持っていたindex=5)にインサートしたら、配列範囲外になりませんか?

だから、「最後の1つだけ…とか制限付くと思いますけども。」と書いたのですが……。

そういう制限なしでやりたいというのであれば、履歴を持ち続けるしかないでしょうね。
で、lefghtbuttonのたびに履歴から操作することに。
# 履歴を格納する構造体なり作って、List構造として記録…でしょうかねぇ。
# List<T>とかで。
# スタック構造でもいいのか…そういうのがあったかはちょっと不明ですが。
# 「C# アンドゥ 実装」辺りで検索するとよさげなものが見つかるかも知れませんね。
    • good
    • 0

>そこで質問です。


>そのときに2から1へ戻ったとき、普通にAdd()するのではなく、移動する前の状態の位置に戻したいのです。

ListBox.Items.Insert()ですかね。

最後の1つだけ…とか制限付くと思いますけども。
rightbuttonで移動(というかlistBox1から削除)する前にインデックスを記憶…
lefghtbuttonで戻す時に記録していたインデックスを元にInsert()
ってところでしょうかね。

listBox1の先頭のアイテムや最後のアイテムだった場合に正しく動作するか?
というのはちゃんと確認してくださいな。

この回答への補足

listBox1の総数を5こだとします。
そうするとlistBox1の5番目[りんご]
をlistBox2に移動し、他のアイテムも複数移動したら
listBox1の配列のCountは(例えば)2つとかになりますよね。
listBox2からlistBox1に戻すときに5番目、(移動するときに持っていたindex=5)にインサートしたら、配列範囲外になりませんか?

また、listbox1から2へいくつか移動した後から戻したとすると、
indexは混同しませんか?

という感じで悩んでおります。。。
未熟者故、うまいロジックが思いつかないのです。

せっかく教えて下さったのですが、今一度お力添えをお願いいたします><

補足日時:2014/08/20 16:31
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QC#にて別クラスの関数を使いたい

C#にて、別クラスの関数を使用する方法を教えてほしいです。

下記のような、構造体を受け取るメソッドを作りました。

*****************************
private struct MyPoint
{
public int x;
public int y;
}

private void proc1(MyPoint pt)
{
MessageBox.Show("座標:" ; pt.x + "," + pt.y + "実行結果");
}

private void button1_Click(object sender ,System.EventArgs e)
{

MyPoint pt;
pt.x = 10;
pt.y = 20;
proc(pt);
}
*****************************

別のフォームのクラスから、proc1を呼び出したいのですが、やり方がわかりません。
どうか、教えてください。

Aベストアンサー

同じ定義をしたとしても別の名前空間に書いた構造体は同一とはみなされません。

呼び出し先クラスでの構造体を private では無く、public で宣言して下さい。

呼び出し元では、

MyClass.MyPoint pt;

のようにして実体を作ります。

QC#「オブジェクト参照が必要です」(初心者)

Visual C# 2008を学習中なんですが、とりあえず何か作ってみようと思って、パラパラマンガに挑戦してみました。
Form1にpictureBox1を作り、waitを入れてイメージを書き換えるという単純なものです。
ところが実行しようと思ったら、「静的でないフィールド、メソッド、またはプロパティ’WindowsFormApplication1.Form1.pictureBox1’でオブジェクト参照が必要です」というエラーが出ます。その際のフォーカスは、main()内の
Form1.pictureBox1.image = Image.FromFile("motion1.png");
”Form1.pictureBox1”に当てられています。

何が原因と考えられるでしょうか。
もし情報不足であればご指摘いただくか、あるいはこの目的においてやらなければいけないこと、を大雑把に教えていただくだけでも幸いです。
よろしくお願いします。

Aベストアンサー

main()内に記述されているとのことですので、たぶん、
Form1.pictureBox1.Image=Image.FromFile("motion1.png");
Application.Run(new Form1());
と書いているのではないでしょうか?

連載 改訂版 C#入門 第3章 クラスとインスタンス
http://www.atmarkit.co.jp/fdotnet/csharp_abc2/csabc2_003/cs2_003_01.html#cs0302

ここであるように、オブジェクト指向にはクラスとインスタンスという概念があります。
今のコードでは、Form1クラスを操作しようとしているのでそのようなエラーが出ます。

具体的な解決方法としては、PictureBoxに初期画像を設定する処理をForm1のコンストラクタでやるのがいいと思います。
その際、redfox63さんがおっしゃられるように
this.pictureBox1
と記述することが必要です。(thisは自分自身のインスタンスを指します)

後は、Windowsフォームで一定間隔での処理をするための「Timerコンポーネント」について調べてみたらいいと思います。

タイマにより一定時間間隔で処理を行うには?(Windowsタイマ編)
http://www.atmarkit.co.jp/fdotnet/dotnettips/372formstimer/formstimer.html

MSDNライブラリ Timerクラス
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.timer.aspx

参考URL:http://www.atmarkit.co.jp/fdotnet/csharp_abc2/index/

main()内に記述されているとのことですので、たぶん、
Form1.pictureBox1.Image=Image.FromFile("motion1.png");
Application.Run(new Form1());
と書いているのではないでしょうか?

連載 改訂版 C#入門 第3章 クラスとインスタンス
http://www.atmarkit.co.jp/fdotnet/csharp_abc2/csabc2_003/cs2_003_01.html#cs0302

ここであるように、オブジェクト指向にはクラスとインスタンスという概念があります。
今のコードでは、Form1クラスを操作しようとしているのでそのようなエラーが出ます。

具...続きを読む

Qc#で(",")区切りのcsvファイルから読み込みを行うには?

駆け出しの初心者です。
以前c言語を少々勉強していてcsvファイルの読み込み、書き出しを練習していたのですが、最近c#を使うようになり、その便利さに圧倒されております。

今回c#で読み込みたいcsvファイルは以下のようになっております
"abc","123","あいうえお"

ただのカンマ区切りであれば読み込みは簡単ですが、
上記のようにダブルクオーテーションでそれぞれの文字列が囲まれている場合に文字列だけを読み込み、配列に代入していくのに何かスムーズな方法はありませんでしょうか?


ちなみに現在単純にカンマ区切りのcsvファイルを読み込むコードを
書いた所ですので、載せておきます
これをいじってスムーズにいければうれしいのですが、いかがでしょうか?

private void LoadData()
{
string path = "Data.csv";
string delimStr = ",";//区切り文字
char[] delimiter = delimStr.ToCharArray();
string[] strData;//分解後の文字用変数
string strLine;//1行分のデータ
Boolean fileExists = System.IO.File.Exists(path);
if (fileExists)
{
System.IO.StreamReader sr = new System.IO.StreamReader(
path,
System.Text.Encoding.Default);
while (sr.Peek() >= 0)
{
strLine = sr.ReadLine();
strData = strLine.Split(delimiter);
DataSet.DataTable.AddDataTableRow(
DateTime.Parse(strData[0]),
strData[1],
   strData[2],
int.Parse(strData[3]),
strData[4]);
}

sr.Close();
}


}


いつも丁寧な回答で協力してくれる皆様には心から感謝しております。
どうぞよろしくお願いします。

駆け出しの初心者です。
以前c言語を少々勉強していてcsvファイルの読み込み、書き出しを練習していたのですが、最近c#を使うようになり、その便利さに圧倒されております。

今回c#で読み込みたいcsvファイルは以下のようになっております
"abc","123","あいうえお"

ただのカンマ区切りであれば読み込みは簡単ですが、
上記のようにダブルクオーテーションでそれぞれの文字列が囲まれている場合に文字列だけを読み込み、配列に代入していくのに何かスムーズな方法はありませんでしょうか?


ちなみに...続きを読む

Aベストアンサー

こう応用するとよいです。
以下に全コードを載せておきますが、ポイントはこの一行です。
strData = strLine.Split(delimiter);

strData = CsvToArrayList1(strLine)[0];


private void LoadData() {
string path = "Data.csv";
string[] strData;//分解後の文字用変数
string strLine;//1行分のデータ
Boolean fileExists = System.IO.File.Exists(path);
if(fileExists) {
System.IO.StreamReader sr = new System.IO.StreamReader(path,System.Text.Encoding.Default);
while(sr.Peek() >= 0) {
strLine = sr.ReadLine();
strData = CsvToArrayList1(strLine)[0];//変更点
DataSet.DataTable.AddDataTableRow(
DateTime.Parse(strData[0]),
strData[1],
strData[2],
int.Parse(strData[3]),
strData[4]);
}

sr.Close();
}
}


//参照先<http://dobon.net/vb/dotnet/file/readcsvfile.html>
//参照先だとArrayListを返し値にしていますが使いづらいので、List<string[]>に変更しています。
public static System.Collections.Generic.List<string[]> CsvToArrayList1(string csvText) {
System.Collections.Generic.List<string[]> csvRecords =
new System.Collections.Generic.List<string[]>();

//前後の改行を削除しておく
csvText = csvText.Trim(new char[] { '\r', '\n' });

//一行取り出すための正規表現
System.Text.RegularExpressions.Regex regLine =
new System.Text.RegularExpressions.Regex(
"^.*(?:\\n|$)",
System.Text.RegularExpressions.RegexOptions.Multiline);

//1行のCSVから各フィールドを取得するための正規表現
System.Text.RegularExpressions.Regex regCsv =
new System.Text.RegularExpressions.Regex(
"\\s*(\"(?:[^\"]|\"\")*\"|[^,]*)\\s*,",
System.Text.RegularExpressions.RegexOptions.None);

System.Text.RegularExpressions.Match mLine = regLine.Match(csvText);
while(mLine.Success) {
//一行取り出す
string line = mLine.Value;
//改行記号が"で囲まれているか調べる
while((CountString(line, "\"") % 2) == 1) {
mLine = mLine.NextMatch();
if(!mLine.Success) {
throw new ApplicationException("不正なCSV");
}
line += mLine.Value;
}
//行の最後の改行記号を削除
line = line.TrimEnd(new char[] { '\r', '\n' });
//最後に「,」をつける
line += ",";

//1つの行からフィールドを取り出す
System.Collections.Generic.List<string> csvFields =
new System.Collections.Generic.List<string>();
System.Text.RegularExpressions.Match m = regCsv.Match(line);
while(m.Success) {
string field = m.Groups[1].Value;
//前後の空白を削除
field = field.Trim();
//"で囲まれている時
if(field.StartsWith("\"") && field.EndsWith("\"")) {
//前後の"を取る
field = field.Substring(1, field.Length - 2);
//「""」を「"」にする
field = field.Replace("\"\"", "\"");
}
csvFields.Add(field);
m = m.NextMatch();
}

csvFields.TrimExcess();
csvRecords.Add(csvFields.ToArray());

mLine = mLine.NextMatch();
}

csvRecords.TrimExcess();
return csvRecords;
}

/// <summary>
/// 指定された文字列内にある文字列が幾つあるか数える
/// </summary>
/// <param name="strInput">strFindが幾つあるか数える文字列</param>
/// <param name="strFind">数える文字列</param>
/// <returns>strInput内にstrFindが幾つあったか</returns>
public static int CountString(string strInput, string strFind) {
int foundCount = 0;
int sPos = strInput.IndexOf(strFind);
while(sPos > -1) {
foundCount++;
sPos = strInput.IndexOf(strFind, sPos + 1);
}

return foundCount;
}

こう応用するとよいです。
以下に全コードを載せておきますが、ポイントはこの一行です。
strData = strLine.Split(delimiter);

strData = CsvToArrayList1(strLine)[0];


private void LoadData() {
string path = "Data.csv";
string[] strData;//分解後の文字用変数
string strLine;//1行分のデータ
Boolean fileExists = System.IO.File.Exists(path);
if(fileExists) {
System.IO.StreamReader sr = new System.IO.StreamReader(path,System.Text.Encoding.Default);
while(sr.Peek() >= 0...続きを読む

QC# ログイン画面からメイン画面への画面遷移について

C# ログイン画面からメイン画面への画面遷移について

C#での画面遷移に関する質問です。
ログイン画面からメイン画面に遷移する場合、どの様な方法で遷移すれば良いのか
迷っています。

現状では以下の方法で遷移していますが、より適切な方法をご存じの場合
ご教示下さい。

(1)Program.csにおいてApplication.Run(new LoginDialog())で
ログイン画面を表示

(2)ログインボタンクリックメソッドでログイン成功時、
メイン画面インスタンスを生成・表示し、ログイン画面を非表示。
(後でログイン画面を再表示することがある為)

---------------------------------------------------------------------
private void LoginButton_Click(object sender, EventArgs e)
{
   /* ログイン処理 */

   //ログイン成功時
   //メイン画面インスタンス生成
   MainForm mainForm = new MainForm();
   //ログイン画面インスタンスを代入
   mainForm.loginForm = this;
   //メイン画面表示
   mainForm.Show();
   //ログイン画面非表示
   this.Visible = false;
}
---------------------------------------------------------------------

また上記の方法だとメイン画面を閉じても、アプリケーションは終了しない為
メイン画面の閉じるボタンを押した場合に以下の処理を行っています。

---------------------------------------------------------------------
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
   //ログイン画面クローズ
   loginForm.Close();
}
---------------------------------------------------------------------

以上、宜しくお願いします。

C# ログイン画面からメイン画面への画面遷移について

C#での画面遷移に関する質問です。
ログイン画面からメイン画面に遷移する場合、どの様な方法で遷移すれば良いのか
迷っています。

現状では以下の方法で遷移していますが、より適切な方法をご存じの場合
ご教示下さい。

(1)Program.csにおいてApplication.Run(new LoginDialog())で
ログイン画面を表示

(2)ログインボタンクリックメソッドでログイン成功時、
メイン画面インスタンスを生成・表示し、ログイン画面を非表示。
(後でログイン画面を再表示す...続きを読む

Aベストアンサー

#2です。
最初にログイン画面のみを表示したいなら
メイン画面のForm_menu_Load(loadイベント処理)
の中で、ログイン画面をモーダル表示し、
NGならメイン画面のcloseのほうがよいかも知れません。

QMAX値を条件にデータを取得するには?

SQL文で困っています。
ご教授下さい。


下記のようなデータがあった場合、それぞれの区分毎に
年月が最大(最新)のデータを取得したいです。
(実際には1レコードにその他項目があり、それらも取得します。)
<検索対象データ>
区分 年月   金額
-----------------------------
A   200412  600
A   200503  560
B   200311  600
B   200508  1000
B   200504  560
C   200508  400
C   200301  1100


<取得したいデータ>

区分 年月   金額
-----------------------------
A   200503  560
B   200508  1000
C   200508  400

よろしくお願いします。

Aベストアンサー

テーブル名をXXXとすると次のようなSQLでよいと思います。(最善の方法かどうかは自信がないですが)

select B.* from (select 区分, max(年月) as 年月 from XXX group by 区分) As A
inner join XXX as B on A.区分 = B.区分 and A.年月 = B.年月
order by B.区分

QC# 別なフォームへ値を渡す (初心者です)

メインのフォームからサブのフォームを呼び出して、
サブのフォ-ムからさらにクラスを呼び出し、
クラスからメインのテキストボックスのテキストに書き込むプログラムを作成中です。

ですが、テキストボックスがパブリックにも関わらず、表示されません。
デバックで見る限り、テキストボックスのテキストには値が入っているのですが、
フォームを見ると表示されていません。

知恵をお貸しください。

Aベストアンサー

普通にメソッドに変数を渡すのと一緒の感じでいいですよ。
例えば、フォームのコンストラクタに渡す感じで。
A_Form : メインフォームの型
B_Form : サブフォームの型
C_Form : 子フォームの型
とします。
class B_Form : Form
{
 private A_Form main_form;
 public B_Form(A_Form a)
 {
  main_form = a;
 }
}

class C_Form : Form
{
 private A_Form main_form;
 public C_Form(A_Form a)
 {
  main_form = a;
 }
}

public void some_function()
{
 A_Form a = new A_Form();
 B_Form b = new B_Form(a);
 C_Form c = new C_Form(a);
}

といった感じになるかと。
最後のメソッドはたとえばなので、参考程度に。

http://www.stackasterisk.jp/tech/dotNet/csharp02_01.jsp

普通にメソッドに変数を渡すのと一緒の感じでいいですよ。
例えば、フォームのコンストラクタに渡す感じで。
A_Form : メインフォームの型
B_Form : サブフォームの型
C_Form : 子フォームの型
とします。
class B_Form : Form
{
 private A_Form main_form;
 public B_Form(A_Form a)
 {
  main_form = a;
 }
}

class C_Form : Form
{
 private A_Form main_form;
 public C_Form(A_Form a)
 {
  main_form = a;
 }
}

public void some_function()
{
 A_Form a = new A...続きを読む

QC#で別のFormへ複数の値を返そうとしているのですがうまくいきません

Form間の一データの受け渡しがうまくいったので、複数の値を返すために構造体を使って次のようにプログラムを作りましたがエラー表示(赤い波線)が出ます。どこがおかしいのでしょうか?
(参考にしたのは次のサイトです)
また、
http://sairoutine.hatenablog.com/entry/2014/02/12/204508

//----------------------------------------

//Form1
namespace SendVariable_Test
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void submitButton_Click(object sender, EventArgs e)
{
//Form2に送るテキスト
string sendText = SendtextBox.Text;

//Form2から送られてきたテキストを受け取る。
Form2.St_Btn_data receiveText = Form2.ShowMiniForm(sendText); //Form2を開く

//Form2から受け取ったテキストをForm1で表示する。
ReceivetextBox.Text = receiveText.string1;// ここでエラー
//string1のところに「...アクセスできない保護レベルになっています」と表示されます。

}
}
}

//-----------------------------------------------
//Form2
namespace SendVariable_Test
{
public partial class Form2 : Form
{
private string[] argumentValues; //Form1から受け取った引数
public St_Btn_data ReturnValue; //Form1に返す戻り値

public struct St_Btn_data
{
string string1;
string string2;
}

public Form2(params string[] argumentValues)
{
//Form1から受け取ったデータをForm2インスタンスのメンバに格納
this.argumentValues = argumentValues;

InitializeComponent();
}

private void Form2_Load(object sender, EventArgs e)
{
//Form1から送られてきたテキストをForm2で表示
this.F2ReceivetextBox.Text = argumentValues[0];

}

static public St_Btn_data ShowMiniForm(string s)
{

Form2 f = new Form2(s);
f.ShowDialog();
St_Btn_data receiveText = f.ReturnValue;
f.Dispose();

return receiveText;

}

private void Closebutton_Click(object sender, EventArgs e)
{
//戻り値をセット
this.ReturnValue = { string1 = F2SendtextBox1.Text, string2 = F2SendtextBox2.Text};// ここでエラー

this.Close();
}

}
}

Form間の一データの受け渡しがうまくいったので、複数の値を返すために構造体を使って次のようにプログラムを作りましたがエラー表示(赤い波線)が出ます。どこがおかしいのでしょうか?
(参考にしたのは次のサイトです)
また、
http://sairoutine.hatenablog.com/entry/2014/02/12/204508

//----------------------------------------

//Form1
namespace SendVariable_Test
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent...続きを読む

Aベストアンサー

public struct St_Btn_data
{
public string string1;
public string string2;
}

// ...

this.ReturnValue.string1 = F2SendtextBox1.Text;
this.ReturnValue.string2 = F2SendtextBox2.Text;

QDoEvents関数って何?

こんにちは。

VBAやプログラミングに詳しい皆様に
教えていただきたい質問があります。

cells(1,1)からcells(5000,1)までの値を消去するときに
処理の進行状況を表示するためにuserform上にプログレスバーを表示したいと思います。

そこで下記のようなコードを入力しました。

userform1.show
for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
next i
unload userform1

しかしこれだとuserformの背景が真っ白になってしまい
ラベルの文字も消えてしまいます。
そこで「EXCEL VBA パーフェクトマスター」という本を見たら

for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
DoEvents
next i
unload userform1
と入力すれば解決することがわかりました。

しかし「DoEvents」についてあまり詳しく書いていなかったのでDoEvents関数をヘルプで見ると、
「発生したイベントがオペレーティング システムによって処理されるように、プログラムで占有していた制御をオペレーティング システムに渡すフロー制御関数です。」

と書いてあるのですが正直、書いてあることがよくわかりません。

どなたかDoEvents関数について、
もう少しわかりやすく教えていただけませんか。
それから、最初に書いたコードで実行すると
ユーザーフォームの背景が真っ白になってしまう原因も
教えていただけませんか?

よろしくお願いいたします。

こんにちは。

VBAやプログラミングに詳しい皆様に
教えていただきたい質問があります。

cells(1,1)からcells(5000,1)までの値を消去するときに
処理の進行状況を表示するためにuserform上にプログレスバーを表示したいと思います。

そこで下記のようなコードを入力しました。

userform1.show
for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
next i
unload userform1

しかしこれだとuserformの背景が真っ白になってしまい
ラベルの文字も消えてしまいます。
そ...続きを読む

Aベストアンサー

簡単に言うと、
OS に制御を渡すってことです。(ヘルプそのまんま)
時間が掛かるループ処理などの場合、ループが終わるまで制御は独占されてしまいます。
ですのでループ中は OS や Excel そのものにも再描画をさせる暇さえ与えません。
途中に DoEvents を入れると制御が OS に渡るので、OS は溜まっていた処理をそこで行うことができます。
結果、フォームの再描画などが行われることになります。

注意点ですが、
Private Sub CommandButton1_Click()
  Dim i As Long

  For i = 1 To 50000
    DoEvents
    Cells(i,1) = ""
  Next i
End Sub

Private Sub CommandButton2_Click()
  MsgBox "hoge"
End Sub

っていうフォームのコードがあった場合、
DoEvents を入れることによって、ループ中にユーザーがCommandButton2 を押すことによって CommandButton2 のクリック イベントも動いちゃいます。
CommandButton1 のクリック イベントではループの前に
CommandButton1.Enabled = False
CommandButton2.Enabled = False
を書いてフォーム上の CommandButton を無効にしておき、ループが終わったら
CommandButton1.Enabled = True
CommandButton2.Enabled = True
と書いて CommandButton を有効に戻してください。

これを工夫すれば、CommandButton2 で CommandButton1 のループを途中キャンセルする処理もすることができます。

Private Canceled As Boolean

Private Sub CommandButton1_Click()

  CommandButton2.Enabled = False

  Dim i As Long
  For i = 1 To 50000
    DoEvents

    If Canceled = True Then
      MsgBox "キャンセルしました"
      Exit Sub
    End If

    Cells(i, 1).Value = ""
  Next i
End Sub

Private CommandButton2_Click()
  Canceled = True
End Sub



コードの行頭にあるスペースは見易さのために全角スペースで作成していますので、これをこのままコピペするとエラーになるかもしれません。
コピペするなら行頭の全角スペースを半角スペースに直してください。

簡単に言うと、
OS に制御を渡すってことです。(ヘルプそのまんま)
時間が掛かるループ処理などの場合、ループが終わるまで制御は独占されてしまいます。
ですのでループ中は OS や Excel そのものにも再描画をさせる暇さえ与えません。
途中に DoEvents を入れると制御が OS に渡るので、OS は溜まっていた処理をそこで行うことができます。
結果、フォームの再描画などが行われることになります。

注意点ですが、
Private Sub CommandButton1_Click()
  Dim i As Long

  For i = 1 To 50000
...続きを読む

QDataGridViewの、選択されている行を取り出したい

いつもお世話になっております。

DataGridViewに関して、選択されているレコードをDataRow型で別フォームに渡してから、各項目をテキストボックスに表示したいのですがうまくいきません(DataRow型にこだわっているわけではないのですが、レコード1件丸ごと取得する型を他に知らないので例として挙げました)。

DataGridViewのCurrentRowプロパティや、SelectedRows(0)をDataRow型に代入する試みをしましたが、型変換できませんでした。

DataGridViewで選択されているレコード一件まるごと変数に渡す方法というのはあるのでしょうか?

ちなみに、SelectionModeはSelectFullRowに、MultiSelectはFalseにしてあります。

ご存知の方ご教授いただけると助かります。
よろしくお願いします。

Aベストアンサー

>おっしゃるとおりやってみたのですが、どうもやはり型変換ができませんでした。
>参照しているのはDataTable型なわけですから、DataRowも取り出せそうな気はするのですが。。。

えー・・・スイマセン
今度はコーディングして確認してみたところ、
なにやら、1ステップすっ飛ばしていました

下記の手順にて取得可能です

[C#]
System.Windows.Forms.DataGridViewRow dgr = this.DataGridView1.CurrentRow;
System.Data.DataRowView drv = (System.Data.DataRowView)dgr.DataBoundItem;
System.Data.DataRow dr = (System.Data.DataRow)drv.Row;

[VB2005]
Dim dgr As System.Windows.Forms.DataGridViewRow = Me.DataGridView1.CurrentRow
Dim drv As System.Data.DataRowView = CType(dgr.DataBoundItem, System.Data.DataRowView)
Dim dr As System.Data.DataRow = CType(drv.Row, System.Data.DataRow)

※最後のキャストを変更すれば、型付データセットにも対応可能のはずです

>おっしゃるとおりやってみたのですが、どうもやはり型変換ができませんでした。
>参照しているのはDataTable型なわけですから、DataRowも取り出せそうな気はするのですが。。。

えー・・・スイマセン
今度はコーディングして確認してみたところ、
なにやら、1ステップすっ飛ばしていました

下記の手順にて取得可能です

[C#]
System.Windows.Forms.DataGridViewRow dgr = this.DataGridView1.CurrentRow;
System.Data.DataRowView drv = (System.Data.DataRowView)dgr.DataBoundItem;
System.Data...続きを読む

QC# get set

C#でのget setの意味、使い方を教えてください
初心者のため、調べても意味が良く分からず、またどういった場面で利用されるかも分かりません。
有識者の方、よろしくお願い致します。

Aベストアンサー

C#のプロパティという機能はご存知でしょうか?
get、setは、プロパティを実装する際に利用するものです。
getは値の取得、setは値の設定をするものです。

get、setの意味というよりも、プロパティの意味を知ることが大切かと思います。

○意味

プロパティとは、クラスのメンバ変数であるかのようにアクセス可能でありながら、
処理の内容を自分で記述できる機能、、、です(@ITより)。

クラスのメンバ変数をpublicにして公開した場合、どうなるでしょう?
外部から好きなようにメンバ変数の値を変更することができてしまい、
オブジェクト指向という考え方から外れてしまいますよね。

例えばエレベータは、行きたい階のボタンを押せば勝手に運んでくれます。
利用する人は、「ボタンを押す」ということだけ知っていればよく、
ボタンが押された後にどのような仕組みで動くのかを知る必要はありません。

メンバ変数をpublicにして公開するというのは、エレベータの内部構造を公開し、
ボタンではなく、内部構造を直接いじって欲しいというのに似ています。
これだとエレベータが壊れてしまったり、正しく動かなかったりするのは明白です。

前置きが長くなりました^^;
このように、内部実装は隠蔽化すべきというのは分かっていただけたでしょうか。
C#のプロパティは、メンバ変数を隠蔽化する場合に利用する機能なのです。

○使い方

あるクラスに次のようなメンバ変数があったとします。

int code;

この変数は、0~1000までの整数が入るようにしたいという要件があったとします。

public int code;

としてしまうと、外部からcode変数を好き勝手いじられてしまうので、
0~1000までの整数が入るようにしたいという要件は満たせませんし、
そもそも、上記のようにメンバ変数を公開することは推奨されません。

この時、メンバ変数をプロパティとして隠蔽化します。

private int code;

public int Code
{
get
{
return this.code;
}
set
{
if(0 <= value && value <= 1000)
this.code = value;
}
}
※スペースが上手くいれられず申し訳ありません。

#1の方の回答にある

> 代入しようとする値が正しいかどうかチェックする

は、上記ようにsetの処理でチェックを行うことが出来るということです。

利用の仕方は、TextBoxなどのコントロールを使ったことであれば分かりますよね?

長くなってしまいまして、申し訳ありません。
疑問が解消されないようでしたら、その旨をおっしゃってくださいね。

C#のプロパティという機能はご存知でしょうか?
get、setは、プロパティを実装する際に利用するものです。
getは値の取得、setは値の設定をするものです。

get、setの意味というよりも、プロパティの意味を知ることが大切かと思います。

○意味

プロパティとは、クラスのメンバ変数であるかのようにアクセス可能でありながら、
処理の内容を自分で記述できる機能、、、です(@ITより)。

クラスのメンバ変数をpublicにして公開した場合、どうなるでしょう?
外部から好きなようにメンバ変数の値を...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報