MSFlexGridをDataGridViewに変更

タグの編集
投稿者 abc  (社会人) 投稿日時 2023/8/7 16:36:47
vb.net (VB2022最新環境)で開発をします。開発経験が3ヶ月程度で、vb6を少しやってます。

vb.netにマイグレーション作業しています。
不明な点があるのでわかる方いたらよろしくお願いいたします。

MSFlexGridのIFMSFlexGrid.col =0 Then の記述の場合DataGridViewではcolの代わりは何でしょうか。
.Colsの場合Columncountでした。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/8/7 17:56:32
直接指定する場合は、
 DataGridView1.RowCount = 10
 DataGridView1.ColumnCount = 10
 DataGridView1(2, 3).Value = "あいうえお"
のように書けます。

そもそも MSFlexGrid や MSHFlexGrid は編集機能がなく、ReadOnly だったので、
機能的には DataGridView の方が充実はしていますが、その分、使い方に注意が必要です。


本来、DataGridView はデータバインド手法に向いたコントロールです。
(デザイン時または実行時に DataSource プロパティを割り当てて使用します)

一応、MSFlexGrid/MSHFlexGrid のような使い方もできなくはないのですが、
どちらかというと DBGrid/DataGrid コントロールのように、
「連続した行データを管理するためのグリッドコントロール」だと思ってください。

MSFlexGrid のような使い方(たとえば、同じ列でも、行によって異なるデータを持たせるなど)も
可能ですが、そのような使い方は「重くなる」ため、件数が多い場合は避けるべきです。
https://learn.microsoft.com/ja-jp/dotnet/desktop/winforms/controls/performance-tuning-in-the-windows-forms-datagridview-control


なお標準機能で無くても良いのであれば、フリーソフトの ReoGrid を NuGet して使う手もあります。
https://github.com/unvell/ReoGrid
https://reogrid.net/jp/document/installation/
投稿者 とくま  (社会人) 投稿日時 2023/8/8 08:15:54
datagridview アクティブセル
で検索すればサンプルが簡単に見つかると思います。
MSFlexGrid の詳細は知りませんが、DataGridView はアクティブセルが
null の場合の対応を入れるべきだと思います。
投稿者 abc  (社会人) 投稿日時 2023/8/8 09:06:38
ご回答くださった方々、ありがとうございます。
指摘いただいた点に気を付けます。
参考になりました。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/8/8 09:24:42
移植時に厄介な点としては、MSGlexGrid1.MergeCells プロパティが挙げられます。
http://mochokun.blog121.fc2.com/blog%EF%BC%8Dentry%EF%BC%8D72.html

セル結合を必要としていない(flexMergeNever) のならば良いのですが、
セル結合を表現しようとした場合、残念ながら DataGridView には
そうした機能が標準では搭載されていないのです。

ですから CellPainting イベントを用いて、 複数領域にまたがる領域を算出し、
そこに自分で「背景色」「枠線」「前景文字列」を自力描画するコードを書くことになります。
もっとも、先人達のサンプルが Web 上に幾つかあるので、やってやれないことは無いですが。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/8/8 09:53:27
あと、MSFlexGrid からの移植時に考慮するべきは編集機能。

MSHFlexGrid や MSFlexGrid は編集機能を持たないため、VB6 時代には、
グリッド上に別の TextBox などを重ね合わせて、疑似編集機能を実装することが
しばしば行われてきました。(MSFlexGrid ではなく VSFlexGrid なら編集できるのですが)

たとえば下記は、同名の「abc」さんが FlexGrid について質問されているものですが、
MSFlexGrid には編集機能が無いので、TextBox を重ねて編集機能を作りこんでいます。
https://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=159


しかし DataGridView の場合は、標準で編集機能を持ち合わせているため、
それらのコードを移植する場合、全面的に書き換えが必要になってきます。
入力チェックのイベントとかも変わってきますしね。

それで単純なテキストボックスやドロップダウンリストとかであれば、さほど難しくは無いのですが、
DataGridView の標準の編集機能では再現できない場合にどうするのか。

たとえば VB6 で、TextBox ではなく MaskedTextBox や DTPicker を重ねていたような場合、
それを DataGridView で表現する場合は、上にコントロールを重ねる方式ではなく、
IDataGridViewEditionControl インターフェイスを継承した編集用コントールを
用意するのが正攻法です。

[DataGridViewでDateTimePickerを使って日付編集を行う]
http://www.ria-lab.com/archives/508

[How to: Windows フォーム DataGridView Cells でコントロールをホストする]
https://learn.microsoft.com/ja-jp/dotnet/desktop/winforms/controls/how-to-host-controls-in-windows-forms-datagridview-cells
投稿者 abc  (社会人) 投稿日時 2023/8/9 18:00:11
魔界の仮面弁士さん
ご回答ありがとうございます。
TextBoxでの疑似編集てきなものがいくつかあり修正しています。

TextBoxとMSFlexGridのエラーで以下のものがありましたが意味がいまいちわからないです。
分かる方いらっしゃいますか?

vb6をマイグレーションすると下記になります。
textbox.Left = MSFlexGrid.CellLeft + MSFlexGrid.Left
textbox.Top = MSFlexGrid.CellTop + MSFlexGrid.Top
textbox.Width = MSFlexGrid.CellWidth
textbox.Height = MSFlexGrid.CellHeight



textbox.Left = VB6.TwipsToPixelsX(MSFlexGrid.CellLeft + VB6.PixelsToTwipsX(MSFlexGrid.Left))
textbox.Top = VB6.TwipsToPixelsY(MSFlexGrid.CellTop + VB6.PixelsToTwipsY(MSFlexGrid.Top))
textbox.Width = VB6.TwipsToPixelsX(MSFlexGrid.CellWidth)
textbox.Height = VB6.TwipsToPixelsY(MSFlexGrid.CellHeight)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/8/9 18:45:27
「TextBox を上に重ねる手法」は、そのままマイグレーションしないでください。
代わりに、DataGridView そのものの編集機能を使うようにします。

面倒に感じるかもしれませんが、DataGridView 本来のスクロールやリサイズ処理、
フォーカス制御などを考慮することを考えると、コントロールを重ねる手法を
再現する方が、かえって問題を広げてしまったりします。経験上。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/8/9 18:55:28
別案としては、MSFlexGrid や MSHFlexGrid の ocx を、
引き続き VB.NET でも利用する手法があります。
この場合、マイグレーションの工数を削減できるかと思います。
(ActiveX への依存性が残るので、後ろ向きな対応になってしまいますが…)
http://hanatyan.sakura.ne.jp/dotnet/msfgfram.htm

・VB6 付属の ocx を VB.NET で使う場合、開発環境には Visual Studio だけでなく
 VB6 開発環境もインストールされている必要があります。
 (実行時ライセンスと開発時ライセンスは異なります)

・VB2022 の開発環境は 64bit のため、VB6 の 32bit OCX は恐らく使えません。
 32bit 開発環境である VB.NET 2002~VB2019 を使う必要があると思います。
 (試したことは無いですが、多分、フォームデザイナー側が対応してくれないと予想)
投稿者 abc  (社会人) 投稿日時 2023/8/10 09:38:38
魔界の仮面弁士さん
様々なアドバイスをありがとうございます。

DataGridViewの編集機能を使用し、TextBoxを使用するのをやめます。
別案についても考えてみます。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/8/10 10:44:57
> TextBoxとMSFlexGridのエラーで以下のものがありましたが意味がいまいちわからないです。
> 分かる方いらっしゃいますか?
一応説明しておくと:

> textbox.Left = MSFlexGrid.CellLeft + MSFlexGrid.Left
> textbox.Top = MSFlexGrid.CellTop + MSFlexGrid.Top
> textbox.Width = MSFlexGrid.CellWidth
> textbox.Height = MSFlexGrid.CellHeight

CellLeft, CellTop, CellWidth, CellHeight は、
Col, Row で示される現在のセルの座標とサイズを示します。
http://hanatyan.sakura.ne.jp/vbhlp/msfgrefe.htm

その座標は MSFlexGrid に対する相対座標なので、
MSFlexGrid 自体の Left , Top プロパティを加算することで、
コンテナ(Form や Frame など)から見た座標に変換しています。

VB6 の場合、この座標系は既定では Twips 単位系ですが、
.NET では Pixel 単位系です。そのため、マイグレーション時には
TwipsToPixelsX や TwipsToPixelsY といった互換メソッドを用いて変換されます。



さて、DataGridView の場合は、セルの座標を知るために
GetCellDisplayRectangle メソッドで測定できます。

Dim pos = DataGridView1.CurrentCellAddress
TextBox1.Visible = (pos.X >= 0 AndAlso pos.Y >= 0)
If Not TextBox1.Visible Then Return

Dim cutOverflow = True '溢れた領域を切り捨てるかどうか 
Dim r As Rectangle = DataGridView1.GetCellDisplayRectangle(pos.X, pos.Y, cutOverflow)

TextBox1.SetBounds(r.Left, r.Top, r.Width, r.Height)


ここで取得されるセル座標は、VB6 の時と同様に
DataGridView から見た相対座標となりますが、Form の Load 時などに
 TextBox1.Parent = DataGridView1
などとして、TextBox を DataGridView の上に直接貼ってしまえば、座標の調整が不要です。
こうすると、現在のセルが画面外までスクロールしていた場合などにも対処しやすいです。


なお、TextBox の高さは、通常はフォント依存で固定ですが、
Load イベントなどで、隠しプロパティの
 TextBox1.AutoSize = False
を設定しておくと、高さを変更できるようになります。


…とはいえ、これが良い方法ではないことは先に述べた通り。
DataGridView の EditMode を EditOnEnter あたりにしておけば、
自動的に編集機能が使えるわけですからね。
https://atmarkit.itmedia.co.jp/bbs/phpBB/viewtopic.php?topic=41019&forum=7

セルタイプにはテキストボックス型だけでなく、ドロップダウンリスト型や
チェックボックス型、ボタン型、画像型、ハイパーリンク型が選べます。

それ以外のコントロールで編集したい場合は、おととい 8 日に紹介した
> [How to: Windows フォーム DataGridView Cells でコントロールをホストする]
> https://learn.microsoft.com/ja-jp/dotnet/desktop/winforms/controls/how-to-host-controls-in-windows-forms-datagridview-cells
を参照してみてください。