for Push.
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
using DocumentFormat.OpenXml.Wordprocessing;
|
||||
using KssSmaPlaLib.Ini;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Color = System.Drawing.Color;
|
||||
|
||||
namespace KssSmaPlaLib.Forms
|
||||
{
|
||||
public static class ColorHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 色選択
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="defaultColor"></param>
|
||||
/// <param name="iniKey"></param>
|
||||
/// <returns></returns>
|
||||
public static Color? SelectColor(Form form, Color defaultColor, string iniKey = "")
|
||||
{
|
||||
using (ColorDialog cd = new ColorDialog())
|
||||
{
|
||||
// 今の色を初期選択にしておく
|
||||
cd.Color = defaultColor;
|
||||
|
||||
if (cd.ShowDialog(form) != DialogResult.OK) return null;
|
||||
|
||||
if (!string.IsNullOrEmpty(iniKey))
|
||||
{
|
||||
// 2. 🔥 Colorを16進数(#RRGGBB)に変換してINIに書き込み
|
||||
string colorHex = ColorTranslator.ToHtml(cd.Color);
|
||||
IniHelper.WriteValue(null, form.Name, iniKey, colorHex);
|
||||
}
|
||||
return cd.Color;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Colorを汎用的なHTML色コード文字列に変換する
|
||||
/// </summary>
|
||||
/// <param name="color"></param>
|
||||
/// <returns></returns>
|
||||
public static string ColorToHtmlColorString(Color color)
|
||||
{
|
||||
return ColorTranslator.ToHtml(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 汎用的なHTML色コード文字列からColorに変換する
|
||||
/// </summary>
|
||||
/// <param name="htmlColorString"></param>
|
||||
/// <returns></returns>
|
||||
public static Color HtmlColorStringToColor(string htmlColorString)
|
||||
{
|
||||
return ColorTranslator.FromHtml(htmlColorString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 背景色から最適な文字色(黒/白)を返すメソッド
|
||||
/// </summary>
|
||||
/// <param name="backColor"></param>
|
||||
/// <returns></returns>
|
||||
public static Color GetContrastColor(Color backColor)
|
||||
{
|
||||
// 輝度計算 (ITU-R BT.601)
|
||||
double luminance = (0.299 * backColor.R) + (0.587 * backColor.G) + (0.114 * backColor.B);
|
||||
return (luminance > 128) ? Color.Black : Color.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using KssSmaPlaLib.Ini;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace KssSmaPlaLib.Forms.ContextMenuFunction
|
||||
{
|
||||
public static class FontUxer
|
||||
{
|
||||
/// <summary>
|
||||
/// フォント選択
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="section"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="defaultFont"></param>
|
||||
/// <param name="resultFont"></param>
|
||||
/// <returns></returns>
|
||||
public static bool SelectFont(Form form, string section, string key, Font defaultFont, out Font resultFont)
|
||||
{
|
||||
// デフォルト値
|
||||
resultFont = new Font(defaultFont, defaultFont.Style);
|
||||
|
||||
using (var dlg = new FontDialog())
|
||||
{
|
||||
var defaultFontCsv =
|
||||
defaultFont.Name + "," +
|
||||
defaultFont.Size.ToString() + "," +
|
||||
defaultFont.Bold.ToString();
|
||||
var iniFontCsv = IniHelper.ReadValue(null, section, key, defaultFontCsv);
|
||||
var fontItems = iniFontCsv.Split(',');
|
||||
if (fontItems.Length != 3) fontItems = defaultFontCsv.Split(',');
|
||||
if (float.TryParse(fontItems[1], out var size) == false) size = defaultFont.Size;
|
||||
if (bool.TryParse(fontItems[2], out var bold) == false) bold = defaultFont.Bold;
|
||||
|
||||
dlg.Font = new Font(fontItems[0], size, bold ? FontStyle.Bold : FontStyle.Regular);
|
||||
dlg.AllowVerticalFonts = false;
|
||||
// 文字飾り(取り消し線と下線)を表示させない
|
||||
dlg.ShowEffects = false;
|
||||
var result = dlg.ShowDialog(form);
|
||||
if (result == DialogResult.Cancel) return false;
|
||||
|
||||
// INI保存
|
||||
var fontCsv =
|
||||
dlg.Font.Name + "," +
|
||||
dlg.Font.Size.ToString() + "," +
|
||||
dlg.Font.Bold.ToString();
|
||||
IniHelper.WriteValue(null, section, key, fontCsv);
|
||||
|
||||
// 出力
|
||||
resultFont = new Font(dlg.Font, dlg.Font.Style);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public static Font GetFont(string section, string key, Font defaultFont)
|
||||
{
|
||||
var defaultFontCsv =
|
||||
defaultFont.Name + "," +
|
||||
defaultFont.Size.ToString() + "," +
|
||||
defaultFont.Bold.ToString();
|
||||
|
||||
var iniFontCsv = IniHelper.ReadValue(null, section, key, defaultFontCsv);
|
||||
var fontItems = iniFontCsv.Split(',');
|
||||
if (fontItems.Length != 3) fontItems = defaultFontCsv.Split(',');
|
||||
if (float.TryParse(fontItems[1], out var size) == false) size = defaultFont.Size;
|
||||
if (bool.TryParse(fontItems[2], out var bold) == false) bold = defaultFont.Bold;
|
||||
return new Font(fontItems[0], size, bold ? FontStyle.Bold : FontStyle.Regular);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
namespace KssSmaPlaLib.Forms.ContextMenuFunction.Gamen
|
||||
{
|
||||
partial class DgvColumnEditorForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.ColumnDgv = new System.Windows.Forms.DataGridView();
|
||||
this.CancelButton2 = new System.Windows.Forms.Button();
|
||||
this.OkButton = new System.Windows.Forms.Button();
|
||||
this.colPropertyName = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colDefaultDisplayName = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.colDisplayName = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.UpButton = new System.Windows.Forms.Button();
|
||||
this.DownButton = new System.Windows.Forms.Button();
|
||||
this.PopupMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.EditDisplayNameMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.VisibleMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
((System.ComponentModel.ISupportInitialize)(this.ColumnDgv)).BeginInit();
|
||||
this.PopupMenu.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// ColumnDgv
|
||||
//
|
||||
this.ColumnDgv.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.ColumnDgv.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.ColumnDgv.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.colPropertyName,
|
||||
this.colDefaultDisplayName,
|
||||
this.colDisplayName});
|
||||
this.ColumnDgv.Location = new System.Drawing.Point(15, 16);
|
||||
this.ColumnDgv.Margin = new System.Windows.Forms.Padding(6, 7, 6, 7);
|
||||
this.ColumnDgv.Name = "ColumnDgv";
|
||||
this.ColumnDgv.RowHeadersWidth = 62;
|
||||
this.ColumnDgv.RowTemplate.Height = 27;
|
||||
this.ColumnDgv.Size = new System.Drawing.Size(505, 429);
|
||||
this.ColumnDgv.TabIndex = 0;
|
||||
this.ColumnDgv.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ColumnDgv_KeyDown);
|
||||
//
|
||||
// CancelButton2
|
||||
//
|
||||
this.CancelButton2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.CancelButton2.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.CancelButton2.Location = new System.Drawing.Point(346, 455);
|
||||
this.CancelButton2.Name = "CancelButton2";
|
||||
this.CancelButton2.Size = new System.Drawing.Size(177, 58);
|
||||
this.CancelButton2.TabIndex = 1;
|
||||
this.CancelButton2.Text = "キャンセル";
|
||||
this.CancelButton2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// OkButton
|
||||
//
|
||||
this.OkButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.OkButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.OkButton.Location = new System.Drawing.Point(163, 455);
|
||||
this.OkButton.Name = "OkButton";
|
||||
this.OkButton.Size = new System.Drawing.Size(177, 58);
|
||||
this.OkButton.TabIndex = 2;
|
||||
this.OkButton.Text = "OK";
|
||||
this.OkButton.UseVisualStyleBackColor = true;
|
||||
this.OkButton.Click += new System.EventHandler(this.OkButton_Click);
|
||||
//
|
||||
// colPropertyName
|
||||
//
|
||||
this.colPropertyName.HeaderText = "識別名";
|
||||
this.colPropertyName.MinimumWidth = 8;
|
||||
this.colPropertyName.Name = "colPropertyName";
|
||||
this.colPropertyName.Width = 150;
|
||||
//
|
||||
// colDefaultDisplayName
|
||||
//
|
||||
this.colDefaultDisplayName.HeaderText = "デフォ表示名";
|
||||
this.colDefaultDisplayName.MinimumWidth = 8;
|
||||
this.colDefaultDisplayName.Name = "colDefaultDisplayName";
|
||||
this.colDefaultDisplayName.Width = 150;
|
||||
//
|
||||
// colDisplayName
|
||||
//
|
||||
this.colDisplayName.HeaderText = "表示名";
|
||||
this.colDisplayName.MinimumWidth = 8;
|
||||
this.colDisplayName.Name = "colDisplayName";
|
||||
this.colDisplayName.Width = 150;
|
||||
//
|
||||
// UpButton
|
||||
//
|
||||
this.UpButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.UpButton.Location = new System.Drawing.Point(15, 455);
|
||||
this.UpButton.Name = "UpButton";
|
||||
this.UpButton.Size = new System.Drawing.Size(59, 58);
|
||||
this.UpButton.TabIndex = 3;
|
||||
this.UpButton.Text = "👆";
|
||||
this.UpButton.UseVisualStyleBackColor = true;
|
||||
this.UpButton.Click += new System.EventHandler(this.UpButton_Click);
|
||||
//
|
||||
// DownButton
|
||||
//
|
||||
this.DownButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.DownButton.Location = new System.Drawing.Point(80, 455);
|
||||
this.DownButton.Name = "DownButton";
|
||||
this.DownButton.Size = new System.Drawing.Size(59, 58);
|
||||
this.DownButton.TabIndex = 4;
|
||||
this.DownButton.Text = "👇";
|
||||
this.DownButton.UseVisualStyleBackColor = true;
|
||||
this.DownButton.Click += new System.EventHandler(this.DownButton_Click);
|
||||
//
|
||||
// PopupMenu
|
||||
//
|
||||
this.PopupMenu.Font = new System.Drawing.Font("メイリオ", 14F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
|
||||
this.PopupMenu.ImageScalingSize = new System.Drawing.Size(24, 24);
|
||||
this.PopupMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.EditDisplayNameMenu,
|
||||
this.VisibleMenu});
|
||||
this.PopupMenu.Name = "PopupMenu";
|
||||
this.PopupMenu.Size = new System.Drawing.Size(394, 133);
|
||||
//
|
||||
// EditDisplayNameMenu
|
||||
//
|
||||
this.EditDisplayNameMenu.Name = "EditDisplayNameMenu";
|
||||
this.EditDisplayNameMenu.Size = new System.Drawing.Size(393, 48);
|
||||
this.EditDisplayNameMenu.Text = "表示名の編集...";
|
||||
this.EditDisplayNameMenu.Click += new System.EventHandler(this.EditDisplayNameMenu_Click);
|
||||
//
|
||||
// VisibleMenu
|
||||
//
|
||||
this.VisibleMenu.Name = "VisibleMenu";
|
||||
this.VisibleMenu.Size = new System.Drawing.Size(393, 48);
|
||||
this.VisibleMenu.Text = "表示/非表示の切り替え";
|
||||
this.VisibleMenu.Click += new System.EventHandler(this.VisibleMenu_Click);
|
||||
//
|
||||
// DgvColumnEditorForm
|
||||
//
|
||||
this.AcceptButton = this.OkButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(19F, 42F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.White;
|
||||
this.CancelButton = this.CancelButton2;
|
||||
this.ClientSize = new System.Drawing.Size(535, 525);
|
||||
this.ContextMenuStrip = this.PopupMenu;
|
||||
this.Controls.Add(this.DownButton);
|
||||
this.Controls.Add(this.UpButton);
|
||||
this.Controls.Add(this.OkButton);
|
||||
this.Controls.Add(this.CancelButton2);
|
||||
this.Controls.Add(this.ColumnDgv);
|
||||
this.Font = new System.Drawing.Font("メイリオ", 14F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
|
||||
this.Margin = new System.Windows.Forms.Padding(6, 7, 6, 7);
|
||||
this.Name = "DgvColumnEditorForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
||||
this.Text = "列一覧💖";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.DgvColumnEditorForm_FormClosing);
|
||||
this.Load += new System.EventHandler(this.DgvColumnEditorForm_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.ColumnDgv)).EndInit();
|
||||
this.PopupMenu.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.DataGridView ColumnDgv;
|
||||
private System.Windows.Forms.Button CancelButton2;
|
||||
private System.Windows.Forms.Button OkButton;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colPropertyName;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colDefaultDisplayName;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn colDisplayName;
|
||||
private System.Windows.Forms.Button UpButton;
|
||||
private System.Windows.Forms.Button DownButton;
|
||||
private System.Windows.Forms.ContextMenuStrip PopupMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem EditDisplayNameMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem VisibleMenu;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
using KssSmaPlaLib.Commons;
|
||||
using KssSmaPlaLib.Forms;
|
||||
using KssSmaPlaLib.Ini;
|
||||
using KssSmaPlaLib.Input.Gamen;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace KssSmaPlaLib.Forms.ContextMenuFunction.Gamen
|
||||
{
|
||||
public partial class DgvColumnEditorForm : Form
|
||||
{
|
||||
private const string COL_NAME_PROPERTY_NAME = "colPropertyName";
|
||||
private const string COL_NAME_DEFAULT_DISPLAY_NAME = "colDefaultDisplayName";
|
||||
private const string COL_NAME_DISPLAY_NAME = "colDisplayName";
|
||||
|
||||
/// <summary>
|
||||
/// 対象のDGV
|
||||
/// </summary>
|
||||
private DataGridView _targetDgv = null;
|
||||
|
||||
/// <summary>
|
||||
/// 対象DGVの列名から列インデックスを取得する辞書
|
||||
/// (後ほど列インデックスが全てゼロになる事象が起きるため)
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, int> _colNameToRowIndexDic = null;
|
||||
|
||||
/// <summary>
|
||||
/// コンストラクタ
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public DgvColumnEditorForm(DataGridView dgv)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_targetDgv = dgv;
|
||||
|
||||
// 列名から列インデックスを取得する辞書の作成(後ほど列インデックスが全てゼロになる事象が起きるため)
|
||||
_colNameToRowIndexDic = new Dictionary<string, int>();
|
||||
foreach (DataGridViewColumn col in _targetDgv.Columns) _colNameToRowIndexDic.Add(col.Name, col.Index);
|
||||
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
|
||||
DgvHelper.Initialize(ColumnDgv);
|
||||
|
||||
ColumnDgv.Rows.Clear();
|
||||
|
||||
// 編集した表示名
|
||||
var csv = IniHelper.ReadValue(null, _targetDgv.Parent.Name + "." + _targetDgv.Name, KEY_NAME_DISPLAY_NAME_CSV);
|
||||
|
||||
// 表示順のリストを作る
|
||||
var cols = new DataGridViewColumn[_targetDgv.Columns.Count];
|
||||
_targetDgv.Columns.CopyTo(cols, 0);
|
||||
Array.Sort(cols, (a, b) => a.DisplayIndex.CompareTo(b.DisplayIndex));
|
||||
|
||||
foreach (var col in cols)
|
||||
{
|
||||
var index = ColumnDgv.Rows.Add();
|
||||
string propertyName = string.Empty;
|
||||
string defaultDisplayName = string.Empty;
|
||||
bool visible = true;
|
||||
var colIndex = col.Index;
|
||||
var displayIndex = col.DisplayIndex;
|
||||
if (col.Tag == null || !(col.Tag is PropertyDescriptor))
|
||||
{
|
||||
propertyName = col.Name;
|
||||
defaultDisplayName = propertyName;
|
||||
}
|
||||
else
|
||||
{
|
||||
PropertyDescriptor pd = col.Tag as PropertyDescriptor;
|
||||
propertyName = pd.Name;
|
||||
defaultDisplayName = pd.DisplayName;
|
||||
var browsableAttr = pd.Attributes.OfType<BrowsableAttribute>().FirstOrDefault();
|
||||
if (browsableAttr != null && !browsableAttr.Browsable)
|
||||
{
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
//string displayName = col.HeaderText;
|
||||
string displayName =
|
||||
StringUxer.GetStringByIndexFormCsv(csv, colIndex, string.Empty)
|
||||
.Replace("@@@COMMA@@@", ",");
|
||||
|
||||
ColumnDgv.Rows[index].Tag = col;
|
||||
ColumnDgv.Rows[index].Cells[COL_NAME_PROPERTY_NAME].Value = (!visible ? "【非】" : "") + propertyName;
|
||||
ColumnDgv.Rows[index].Cells[COL_NAME_DEFAULT_DISPLAY_NAME].Value = defaultDisplayName;
|
||||
ColumnDgv.Rows[index].Cells[COL_NAME_DISPLAY_NAME].Value = displayName == defaultDisplayName ? "" : displayName;
|
||||
|
||||
SetVisible(index, col.Visible);
|
||||
}
|
||||
|
||||
//// タグに入れておく(PropertyDescriptor型)
|
||||
//col.Tag = pd;
|
||||
|
||||
//// 列ヘッダーを [DisplayName] に
|
||||
//col.HeaderText = pd.DisplayName;
|
||||
|
||||
//// [Browsable(false)] の列は非表示(AutoGenerateでも列が立つ場合の保険)
|
||||
//var browsableAttr = pd.Attributes.OfType<BrowsableAttribute>().FirstOrDefault();
|
||||
//if (browsableAttr != null && !browsableAttr.Browsable)
|
||||
//{
|
||||
// col.Visible = false;
|
||||
// continue;
|
||||
//}
|
||||
|
||||
// DGV列幅復元
|
||||
DgvHelper.DgvLoadColWidth(ColumnDgv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォームロード
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void DgvColumnEditorForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
// バウンズ復元
|
||||
FormHelper.LoadFormBounds(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 👆ボタンクリック時
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void UpButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
// 対象外状況判断
|
||||
if (ColumnDgv.SelectedRows.Count < 1) return;
|
||||
if (ColumnDgv.SelectedRows[0].Index == 0) return;
|
||||
|
||||
// 事前取得
|
||||
var row = ColumnDgv.SelectedRows[0];
|
||||
var index = row.Index; // Removeしたら-1になるからその前に取得しておく
|
||||
|
||||
// 行移動の実行
|
||||
ColumnDgv.Rows.Remove(row);
|
||||
ColumnDgv.Rows.Insert(index - 1, row);
|
||||
|
||||
// 行選択
|
||||
ColumnDgv.ClearSelection();
|
||||
ColumnDgv.Rows[index - 1].Selected = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 👇ボタンクリック時
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void DownButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
// 対象外状況判断
|
||||
if (ColumnDgv.SelectedRows.Count < 1) return;
|
||||
if (ColumnDgv.SelectedRows[0].Index == ColumnDgv.RowCount - 1) return;
|
||||
|
||||
// 事前取得
|
||||
var row = ColumnDgv.SelectedRows[0];
|
||||
var index = row.Index; // Removeしたら-1になるからその前に取得しておく
|
||||
|
||||
// 行移動の実行
|
||||
ColumnDgv.Rows.Remove(row);
|
||||
ColumnDgv.Rows.Insert(index + 1, row);
|
||||
|
||||
// 行選択
|
||||
ColumnDgv.ClearSelection();
|
||||
ColumnDgv.Rows[index + 1].Selected = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DGVキー押下イベント
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ColumnDgv_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Alt && (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down))
|
||||
{
|
||||
if (e.KeyCode == Keys.Up)
|
||||
{
|
||||
UpButton_Click(sender, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
DownButton_Click(sender, e);
|
||||
}
|
||||
|
||||
// 既定動作抑止(メニュー呼び/ビープを止める)
|
||||
e.Handled = true;
|
||||
e.SuppressKeyPress = true;
|
||||
}
|
||||
}
|
||||
|
||||
private const string KEY_NAME_DISPLAY_INDEX_CSV = "DisplayIndexCsv";
|
||||
private const string KEY_NAME_COLUMN_VISIBLE_CSV = "ColumnVisibleCsv";
|
||||
private const string KEY_NAME_DISPLAY_NAME_CSV = "DisplayNameCsv";
|
||||
|
||||
/// <summary>
|
||||
/// OKボタンクリック時
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void OkButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
//List<int> indexList = new List<int>();
|
||||
//foreach (DataGridViewRow row in ColumnDgv.Rows) indexList.Add(((DataGridViewColumn)row.Tag).Index);
|
||||
////MessageBox.Show(string.Join(" ", indexList));
|
||||
//if (indexList.Max() != ColumnDgv.Rows.Count - 1)
|
||||
if (_colNameToRowIndexDic.Values.Max() != ColumnDgv.Rows.Count - 1)
|
||||
{
|
||||
MessageBox.Show(this, $"_colNameToRowIndexDicがおかしい![_colNameToRowIndexDicのMax:{_colNameToRowIndexDic.Values.Max()},グリッド行数:{ColumnDgv.Rows.Count}]");
|
||||
this.DialogResult = DialogResult.None;
|
||||
return;
|
||||
}
|
||||
|
||||
// 表示順
|
||||
int[] displayIndexArray = new int[ColumnDgv.Rows.Count];
|
||||
foreach (DataGridViewRow row in ColumnDgv.Rows)
|
||||
displayIndexArray[_colNameToRowIndexDic[((DataGridViewRow)row).Cells[0].Value.ToString()]]
|
||||
= ((DataGridViewRow)row).Index;
|
||||
// INI書き込み
|
||||
IniHelper.WriteValue(null, _targetDgv.Parent.Name + "." + _targetDgv.Name, KEY_NAME_DISPLAY_INDEX_CSV, string.Join(",", displayIndexArray));
|
||||
|
||||
// 表示非表示
|
||||
bool[] visibleArray = new bool[ColumnDgv.Rows.Count];
|
||||
foreach (DataGridViewRow row in ColumnDgv.Rows)
|
||||
visibleArray[_colNameToRowIndexDic[((DataGridViewRow)row).Cells[0].Value.ToString()]]
|
||||
= IsVisible(((DataGridViewRow)row).Index);
|
||||
// INI書き込み
|
||||
IniHelper.WriteValue(null, _targetDgv.Parent.Name + "." + _targetDgv.Name, KEY_NAME_COLUMN_VISIBLE_CSV, string.Join(",", visibleArray));
|
||||
|
||||
// 表示名称
|
||||
string[] nameArray = new string[ColumnDgv.Rows.Count];
|
||||
foreach (DataGridViewRow row in ColumnDgv.Rows)
|
||||
{
|
||||
var name = string.Empty;
|
||||
if (row.Cells[COL_NAME_DISPLAY_NAME].Value.ToString() != row.Cells[COL_NAME_DEFAULT_DISPLAY_NAME].Value.ToString())
|
||||
{
|
||||
name = row.Cells[COL_NAME_DISPLAY_NAME]
|
||||
.Value
|
||||
.ToString()
|
||||
.Replace(",", "@@@COMMA@@@");
|
||||
}
|
||||
nameArray[_colNameToRowIndexDic[((DataGridViewRow)row).Cells[0].Value.ToString()]] = name;
|
||||
}
|
||||
// INI書き込み
|
||||
IniHelper.WriteValue(null, _targetDgv.Parent.Name + "." + _targetDgv.Name, KEY_NAME_DISPLAY_NAME_CSV, string.Join(",", nameArray));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォーム閉じるとき
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void DgvColumnEditorForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
// バウンズの保存
|
||||
FormHelper.SaveFormBounds(this);
|
||||
|
||||
// DGV列幅保存
|
||||
DgvHelper.DgvSaveColWidth(ColumnDgv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示名の編集メニュークリック
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void EditDisplayNameMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ColumnDgv.SelectedRows.Count < 1) return;
|
||||
var rowIndex = ColumnDgv.SelectedRows[0].Index;
|
||||
var text = ColumnDgv[COL_NAME_DISPLAY_NAME,rowIndex].Value.ToString();
|
||||
var defaultText= ColumnDgv[COL_NAME_DEFAULT_DISPLAY_NAME, rowIndex].Value.ToString();
|
||||
if (string.IsNullOrEmpty(text)) text = defaultText;
|
||||
using (var form = new TextInputForm(text))
|
||||
{
|
||||
if (form.ShowDialog() == DialogResult.Cancel) return;
|
||||
|
||||
ColumnDgv[COL_NAME_DISPLAY_NAME, rowIndex].Value = form.EditedText == defaultText ? "" : form.EditedText;
|
||||
}
|
||||
}
|
||||
|
||||
private void VisibleMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ColumnDgv.SelectedRows.Count < 1) return;
|
||||
var rowIndex = ColumnDgv.SelectedRows[0].Index;
|
||||
SetVisible(rowIndex, !IsVisible(rowIndex));
|
||||
}
|
||||
|
||||
private bool IsVisible(int rowIndex)
|
||||
{
|
||||
if (rowIndex < 0 || rowIndex >= ColumnDgv.Rows.Count) return true;
|
||||
if (ColumnDgv.Rows[rowIndex].DefaultCellStyle == null) return true;
|
||||
if (ColumnDgv.Rows[rowIndex].DefaultCellStyle.Font == null) return true;
|
||||
var style = ColumnDgv.Rows[rowIndex].DefaultCellStyle.Font.Style;
|
||||
return !((style & FontStyle.Strikeout) == FontStyle.Strikeout);
|
||||
}
|
||||
private void SetVisible(int rowIndex, bool visible)
|
||||
{
|
||||
if (rowIndex < 0 || rowIndex >= ColumnDgv.Rows.Count) return;
|
||||
if (ColumnDgv.Rows[rowIndex].DefaultCellStyle == null) return;
|
||||
Font font;
|
||||
if (ColumnDgv.Rows[rowIndex].DefaultCellStyle.Font != null)
|
||||
{
|
||||
font = ColumnDgv.Rows[rowIndex].DefaultCellStyle.Font;
|
||||
}
|
||||
else
|
||||
{
|
||||
font = ColumnDgv.DefaultCellStyle.Font;
|
||||
}
|
||||
var style = font.Style;
|
||||
if (visible)
|
||||
{
|
||||
style &= ~FontStyle.Strikeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
style |= FontStyle.Strikeout;
|
||||
}
|
||||
ColumnDgv.Rows[rowIndex].DefaultCellStyle.Font = new Font(font, style);
|
||||
|
||||
// 背景色
|
||||
ColumnDgv.Rows[rowIndex].DefaultCellStyle.BackColor = visible ? Color.Empty : Color.DarkGray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="colPropertyName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="colDefaultDisplayName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="colDisplayName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="PopupMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -0,0 +1,332 @@
|
||||
using DocumentFormat.OpenXml.Office2010.CustomUI;
|
||||
using KssSmaPlaLib.Forms.ContextMenuFunction;
|
||||
using KssSmaPlaLib.Ini;
|
||||
using KssSmaPlaLib.Input.Gamen;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Windows.UI.Popups;
|
||||
|
||||
namespace KssSmaPlaLib.Forms
|
||||
{
|
||||
public static class ContextMenuHelper
|
||||
{
|
||||
private const string INI_KEY_TITLE = "Title";
|
||||
private const string INI_KEY_BACK_COLOR = "BackColor";
|
||||
|
||||
/// <summary>
|
||||
/// フォーム背景色選択
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
public static void SelectBackColor(Form form)
|
||||
{
|
||||
using (ColorDialog cd = new ColorDialog())
|
||||
{
|
||||
// 今の色を初期選択にしておく
|
||||
cd.Color = form.BackColor;
|
||||
|
||||
if (cd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
// 1. フォームの背景色を即時変更
|
||||
form.BackColor = cd.Color;
|
||||
|
||||
// 2. 🔥 Colorを16進数(#RRGGBB)に変換してINIに書き込み
|
||||
string colorHex = ColorTranslator.ToHtml(cd.Color);
|
||||
IniHelper.WriteValue(null, form.Name, INI_KEY_BACK_COLOR, colorHex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 背景色をINIから取得して設定
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
public static void SetBackColorFromIni(Form form)
|
||||
{
|
||||
var colorHex = IniHelper.ReadValue(null, form.Name, INI_KEY_BACK_COLOR, ColorTranslator.ToHtml(form.BackColor));
|
||||
form.BackColor = ColorTranslator.FromHtml(colorHex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// INIに登録されている色選択
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
public static void SelectIniColor(Form form, string key, Color defaultColor)
|
||||
{
|
||||
var colorHex = IniHelper.ReadValue(null, form.Name, key, ColorTranslator.ToHtml(defaultColor));
|
||||
var color = ColorTranslator.FromHtml(colorHex);
|
||||
|
||||
using (ColorDialog cd = new ColorDialog())
|
||||
{
|
||||
// 今の色を初期選択にしておく
|
||||
cd.Color = color;
|
||||
|
||||
if (cd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
// 2. 🔥 Colorを16進数(#RRGGBB)に変換してINIに書き込み
|
||||
colorHex = ColorTranslator.ToHtml(cd.Color);
|
||||
IniHelper.WriteValue(null, form.Name, key, colorHex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// INIに設定されている色取得
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="defaultColor"></param>
|
||||
/// <returns></returns>
|
||||
public static Color GetIniColor(Form form, string key, Color defaultColor)
|
||||
{
|
||||
var colorHex = IniHelper.ReadValue(null, form.Name, key, ColorTranslator.ToHtml(defaultColor));
|
||||
return ColorTranslator.FromHtml(colorHex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// チェックボックスのメニュー項目のチェック値のロード
|
||||
/// </summary>
|
||||
/// <param name="frm"></param>
|
||||
/// <param name="menuItem"></param>
|
||||
public static void MenuCheckBoxItemLoad(Form frm, ToolStripMenuItem menuItem)
|
||||
{
|
||||
menuItem.Checked =
|
||||
//bool.TryParse(
|
||||
// IniHelper.ReadValue(
|
||||
// null, frm.Name, menuItem.Name, false.ToString()),
|
||||
// out var boolVal) ? boolVal : false;
|
||||
IniHelper.ReadBoolValue(null, frm.Name, menuItem.Name, false);
|
||||
}
|
||||
|
||||
public static void LoadAllMenuStates(Form form, ContextMenuStrip contextMenu)
|
||||
{
|
||||
foreach (ToolStripItem item in contextMenu.Items)
|
||||
ProcessMenuItemLoad(form, item);
|
||||
}
|
||||
|
||||
private static void ProcessMenuItemLoad(Form form, ToolStripItem item)
|
||||
{
|
||||
// ToolStripMenuItem かつ CheckOnClick が true の場合のみ処理
|
||||
if (item is ToolStripMenuItem menuItem && menuItem.CheckOnClick)
|
||||
{
|
||||
// 🚀 ご提示のヘルパーメソッドを1行呼び出すだけ!
|
||||
ContextMenuHelper.MenuCheckBoxItemLoad(form, menuItem);
|
||||
}
|
||||
|
||||
// 子メニュー(階層)がある場合は再帰的に奥まで処理
|
||||
if (item is ToolStripDropDownItem dropDownItem && dropDownItem.HasDropDownItems)
|
||||
{
|
||||
foreach (ToolStripItem subItem in dropDownItem.DropDownItems)
|
||||
ProcessMenuItemLoad(form, subItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// メニューのチェックボックスアイテムのクリック時
|
||||
/// </summary>
|
||||
/// <param name="frm"></param>
|
||||
/// <param name="menuItem"></param>
|
||||
public static void MenuCheckBoxItemClick(Form frm, ToolStripMenuItem menuItem)
|
||||
{
|
||||
menuItem.Checked = !menuItem.Checked;
|
||||
IniHelper.WriteValue(null, frm.Name, menuItem.Name, menuItem.Checked.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// メニューのフォント設定
|
||||
/// ※フォームロードでCallしてください
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="menu"></param>
|
||||
public static void SetFont(Form form, ContextMenuStrip menu)
|
||||
{
|
||||
menu.Font = FontUxer.GetFont(form.Name, menu.Name + ".Font", menu.Font);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// コントロール(ラベル等)のフォント設定
|
||||
/// ※フォームロードでCallしてください
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="menu"></param>
|
||||
public static void SetControlFont(Form form, Control control)
|
||||
{
|
||||
control.Font = FontUxer.GetFont(form.Name, control.Name + ".Font", control.Font);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// メニュー自身のフォント選択
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="menu"></param>
|
||||
public static void SelectMenuFont(Form form, ContextMenuStrip menu)
|
||||
{
|
||||
if (FontUxer.SelectFont(form, form.Name, menu.Name + ".Font", menu.Font, out var font))
|
||||
menu.Font = font;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// コントロール(ラベル等)のフォント選択
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="control"></param>
|
||||
public static void SelectControlFont(Form form, Control control)
|
||||
{
|
||||
if (FontUxer.SelectFont(form, form.Name, control.Name + ".Font", control.Font, out var font))
|
||||
control.Font = font;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォームのタイトル設定
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
public static void SetFormTitle(Form form)
|
||||
{
|
||||
var title = IniHelper.ReadValue(null, form.Name, INI_KEY_TITLE, form.Text);
|
||||
using (var dlg = new TextInputForm(title))
|
||||
{
|
||||
if (dlg.ShowDialog() == DialogResult.Cancel) return;
|
||||
IniHelper.WriteValue(null, form.Name, INI_KEY_TITLE, dlg.EditedText);
|
||||
form.Text = IniHelper.ReadValue(null, form.Name, INI_KEY_TITLE, form.Text);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// バージョン表示
|
||||
/// </summary>
|
||||
/// <param name="menuItem"></param>
|
||||
public static void DispVersion(ToolStripMenuItem menuItem, bool isDispCraftedBy = true)
|
||||
{
|
||||
// バージョン
|
||||
menuItem.Font = new Font(menuItem.Font.FontFamily, 8.0f);
|
||||
menuItem.Enabled = false;
|
||||
menuItem.Text = "Ver." + Application.ProductVersion + (isDispCraftedBy ? " | Crafted by のぼぼ工房" : "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ショートカットキーで動作するようにする
|
||||
/// ※フォームのKeyPreviewをtrueにして、
|
||||
/// フォームのKeyDownイベントでCallしてください。
|
||||
/// private void Form1_KeyDown(object sender, KeyEventArgs e)
|
||||
// {
|
||||
// // メニューのEnabledを制御している場合、そのOpeningを呼んでおく。
|
||||
// contextMenuStrip1_Opening(contextMenuStrip1, new System.ComponentModel.CancelEventArgs());
|
||||
//
|
||||
// if (ExecuteShortcutWithEnabledCheck(contextMenuStrip1.Items, e.KeyData))
|
||||
// {
|
||||
// e.Handled = true;
|
||||
// }
|
||||
// }
|
||||
/// </summary>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="keyData"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ExecuteShortcutWithEnabledCheck(ToolStripItemCollection items, Keys keyData)
|
||||
{
|
||||
foreach (ToolStripItem item in items)
|
||||
{
|
||||
if (item is ToolStripMenuItem menuItem)
|
||||
{
|
||||
// ショートカットが一致し、かつ「有効(Enabled)」な時だけ実行!
|
||||
if (menuItem.ShortcutKeys == keyData && menuItem.Enabled)
|
||||
{
|
||||
menuItem.PerformClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (menuItem.HasDropDownItems)
|
||||
{
|
||||
if (ExecuteShortcutWithEnabledCheck(menuItem.DropDownItems, keyData)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// コンボメニューの選択値をINIに保存
|
||||
/// (ToolStripComboBoxのSelectedIndexChangedでCallしてね!💖)
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="combo"></param>
|
||||
public static void SaveComboMenuToIni(Form form, ToolStripComboBox combo)
|
||||
{
|
||||
IniHelper.WriteValue(null, form.Name, combo.Name + ".Values", combo.Text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// コンボメニューの選択値をINIから復元
|
||||
/// (FormのLoadでCallしてね💖)
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="combo"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
public static void LoadComboMenuFromIni(Form form, ToolStripComboBox combo, string defaultValue)
|
||||
{
|
||||
combo.Text = IniHelper.ReadValue(null, form.Name, combo.Name + ".Values", defaultValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// コンボメニューの選択値をINIから取得
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="combo"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
/// <returns></returns>
|
||||
public static string ComboMenuFromIni(Form form, ToolStripComboBox combo, string defaultValue)
|
||||
{
|
||||
return IniHelper.ReadValue(null, form.Name, combo.Name + ".Values", defaultValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォームガチャ
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task FormGacha(Form form)
|
||||
{
|
||||
// 現在の状態をバックアップ
|
||||
var originalState = form.Controls.Cast<Control>()
|
||||
.Select(c => new { Ctrl = c, Loc = c.Location, Txt = c.Text, Font = c.Font }).ToList();
|
||||
var formLoc = form.Location;
|
||||
|
||||
Random rng = new Random();
|
||||
|
||||
// 5秒間の狂宴(癒し)
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// 1. フォーム自体が震える
|
||||
form.Location = new Point(formLoc.X + rng.Next(-20, 21), formLoc.Y + rng.Next(-20, 21));
|
||||
|
||||
foreach (var item in originalState)
|
||||
{
|
||||
// 2. コントロールがバラバラに踊る
|
||||
item.Ctrl.Location = new Point(item.Loc.X + rng.Next(-15, 16), item.Loc.Y + rng.Next(-15, 16));
|
||||
|
||||
// 3. ラベルが叫び、ボタンが点滅する
|
||||
if (item.Ctrl is System.Windows.Forms.Label) item.Ctrl.Text = "がちゃ!";
|
||||
item.Ctrl.BackColor = Color.FromArgb(rng.Next(256), rng.Next(256), rng.Next(256));
|
||||
}
|
||||
|
||||
// 4. マウスカーソルを中央に拘束(逃がさない)
|
||||
Cursor.Position = form.PointToScreen(new Point(form.Width / 2, form.Height / 2));
|
||||
|
||||
await Task.Delay(30);
|
||||
}
|
||||
|
||||
// 祭りのあと(完全復旧)
|
||||
form.Location = formLoc;
|
||||
foreach (var item in originalState)
|
||||
{
|
||||
item.Ctrl.Location = item.Loc;
|
||||
item.Ctrl.Text = item.Txt;
|
||||
item.Ctrl.Font = item.Font;
|
||||
item.Ctrl.BackColor = SystemColors.Control;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace KssSmaPlaLib.Forms.Controls
|
||||
{
|
||||
public class PoiDgv : DataGridView
|
||||
{
|
||||
private IContainer components;
|
||||
|
||||
[Category("Poi拡張"), Description("共通メニューを自動で追加するかどうか")]
|
||||
public bool EnablePoiMenu { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// コンストラクタ
|
||||
/// </summary>
|
||||
public PoiDgv()
|
||||
{
|
||||
// これが今回の本命!
|
||||
this.DoubleBuffered = true;
|
||||
|
||||
// DGB初期設定
|
||||
this.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
|
||||
this.RowHeadersVisible = false;
|
||||
this.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
this.AllowUserToAddRows = false;
|
||||
this.AllowUserToDeleteRows = false;
|
||||
this.AllowUserToOrderColumns = true;
|
||||
this.AllowUserToResizeColumns = true;
|
||||
this.AllowUserToResizeRows = false;
|
||||
this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// コンテキストメニュー設定時
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected override void OnContextMenuStripChanged(EventArgs e)
|
||||
{
|
||||
base.OnContextMenuStripChanged(e);
|
||||
|
||||
// ユーザーがデザイナーでセットしたメニューに「Poi」のスパイスを加える
|
||||
if (EnablePoiMenu && this.ContextMenuStrip != null)
|
||||
{
|
||||
var menu = this.ContextMenuStrip;
|
||||
|
||||
//// 重複防止チェック
|
||||
//if (menu.Items.Find("poiItem_AutoFit", true).Length == 0)
|
||||
//{
|
||||
// if (menu.Items.Count > 0) menu.Items.Add(new ToolStripSeparator());
|
||||
|
||||
// var fitItem = new ToolStripMenuItem("列幅をぽいっと自動調整");
|
||||
// fitItem.Name = "poiItem_AutoFit";
|
||||
// fitItem.Click += (s, ev) => this.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
|
||||
|
||||
// menu.Items.Add(fitItem);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
((System.ComponentModel.ISupportInitialize)(this)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// PoiDgv
|
||||
//
|
||||
this.RowTemplate.Height = 21;
|
||||
((System.ComponentModel.ISupportInitialize)(this)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -0,0 +1,588 @@
|
||||
using DocumentFormat.OpenXml.VariantTypes;
|
||||
using KssSmaPlaLib.Ini;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Windows.Media.Streaming.Adaptive;
|
||||
|
||||
namespace KssSmaPlaLib.Forms.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Poiメインフォーム
|
||||
/// </summary>
|
||||
public class PoiMainForm : Form
|
||||
{
|
||||
protected Label TitleLabel;
|
||||
protected PoiDgv MainDgv;
|
||||
protected ContextMenuStrip MainContextMenu;
|
||||
protected ToolStripMenuItem TitleVisibleCheckMenu;
|
||||
private ToolStripMenuItem _versionMenu;
|
||||
private NumericUpDown _titleLabelYohakuHorizonNumeric = new NumericUpDown { Width = 60 };
|
||||
private NumericUpDown _titleLabelYohakuVarticalNumeric = new NumericUpDown { Width = 60 };
|
||||
// 👇遅延書き込みしようかと思ったがやめた!
|
||||
//private Timer _saveDelayTimer = new Timer { Interval = 1000 };
|
||||
private string _title = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// コンストラクタ
|
||||
/// </summary>
|
||||
public PoiMainForm(string title = "", string name = "")
|
||||
{
|
||||
// Name
|
||||
this.Name = string.IsNullOrEmpty(name) ? this.GetType().Name : name;
|
||||
|
||||
// タイトル
|
||||
_title = string.IsNullOrEmpty(title) ? this.Name : title;
|
||||
this.Text = _title;
|
||||
|
||||
// フォームイベント
|
||||
this.Load += PoiMainForm_Load;
|
||||
this.FormClosing += PoiMainForm_FormClosing;
|
||||
|
||||
// コントロールの生成と配置
|
||||
TitleLabel = new Label
|
||||
{
|
||||
Name = "TitleLabel",
|
||||
AutoSize = true,
|
||||
Dock = DockStyle.Top,
|
||||
Text = "サンプルです💖",
|
||||
};
|
||||
TitleLabel.Padding = new Padding(20, 5, 8, 20);
|
||||
MainDgv = new PoiDgv
|
||||
{
|
||||
Name = "MainDgv",
|
||||
Dock = DockStyle.Fill
|
||||
};
|
||||
MainContextMenu = new ContextMenuStrip
|
||||
{
|
||||
Name = "MainContextMenu",
|
||||
};
|
||||
this.ContextMenuStrip = MainContextMenu;
|
||||
this.Controls.Add(MainDgv);
|
||||
this.Controls.Add(TitleLabel);
|
||||
|
||||
// デフォルトのメニュー項目登録
|
||||
CreateDefaultMenu();
|
||||
|
||||
DgvHelper.DgvLoadFontFromIni(MainDgv);
|
||||
//ContextMenuHelper.MenuCheckBoxItemLoad(this, TitleVisibleCheckMenu);
|
||||
TitleLabel.Visible = TitleVisibleCheckMenu.Checked;
|
||||
ContextMenuHelper.SetControlFont(this, TitleLabel);
|
||||
ContextMenuHelper.DispVersion(_versionMenu);
|
||||
|
||||
// ソート無効
|
||||
foreach (DataGridViewColumn column in MainDgv.Columns) column.SortMode = DataGridViewColumnSortMode.NotSortable;
|
||||
//// 日の列はセンタリング
|
||||
//for (var day = 1; day <= 31; day++) MainDgv.Columns[$"ColDay{day}"].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
|
||||
// TOTAL列は右寄せ
|
||||
//MainDgv.Columns["ColTotal"].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
|
||||
// ヘッダ行のデザインはOSのデザインを反映させる機能を解除
|
||||
MainDgv.EnableHeadersVisualStyles = false;
|
||||
|
||||
// 👇やろうかと思ったけどやめた!
|
||||
//// 遅延書き込みタイマー
|
||||
//_saveDelayTimer.Tick += (s, e) =>
|
||||
//{
|
||||
// _saveDelayTimer.Stop(); // タイマーを止める
|
||||
// // 👑 ここでINIファイルへの書き込みを実行!
|
||||
// // スピンボタン連打が「止まってから1秒後」に1回だけ綺麗に保存されます。
|
||||
// aaaaaaa
|
||||
//};
|
||||
//LoadDataAsync();
|
||||
|
||||
// タイトル文字列設定
|
||||
//TitleLabel.Text = GetTitle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォームロード時
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private void PoiMainForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
FormHelper.LoadFormBounds(this);
|
||||
DgvHelper.DgvLoadFontFromIni(MainDgv);
|
||||
DgvHelper.DgvLoadColWidth(MainDgv);
|
||||
DgvHelper.DgvLoadHeaderHeight(MainDgv);
|
||||
DgvHelper.DgvLoadColVisible(MainDgv);
|
||||
DgvHelper.DgvLoadColDisplayIndex(MainDgv);
|
||||
DgvHelper.DgvLoadColFrozen(MainDgv);
|
||||
DgvHelper.DgvSetHeaderBackColorFromIni(this, MainDgv);
|
||||
//DgvHelper.DgvSetHeaderBackColorFromIniWithNameMatch(this, MainDgv, "ColDay*", INI_KEY_HEADER_DAY_COLUMN_BACK_COLOR);
|
||||
|
||||
// 👇これはLoadでやらないと、子で作ってるメニューアイテムに反映されない!
|
||||
ContextMenuHelper.LoadAllMenuStates(this, MainContextMenu);
|
||||
ContextMenuHelper.SetFont(this, MainContextMenu);
|
||||
var vertical =
|
||||
int.TryParse(
|
||||
IniHelper.ReadValue(null, this.Name, _titleLabelYohakuVarticalNumeric.Name, "0"),
|
||||
out var intVal) ? intVal : 0;
|
||||
var horizon =
|
||||
int.TryParse(
|
||||
IniHelper.ReadValue(null, this.Name, _titleLabelYohakuHorizonNumeric.Name, "0"),
|
||||
out intVal) ? intVal : 0;
|
||||
TitleLabel.Padding = new Padding(horizon, vertical, horizon, vertical);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォーム閉じるとき
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private void PoiMainForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
FormHelper.SaveFormBounds(this);
|
||||
DgvHelper.DgvSaveFontToIni(MainDgv);
|
||||
DgvHelper.DgvSaveColWidth(MainDgv);
|
||||
DgvHelper.DgvSaveHeaderHeight(MainDgv);
|
||||
DgvHelper.DgvSaveColVisible(MainDgv);
|
||||
DgvHelper.DgvSaveColDisplayIndex(MainDgv);
|
||||
DgvHelper.DgvSaveColFrozen(MainDgv);
|
||||
IniHelper.WriteValue(
|
||||
null, this.Name,
|
||||
_titleLabelYohakuHorizonNumeric.Name,
|
||||
_titleLabelYohakuHorizonNumeric.Value.ToString());
|
||||
IniHelper.WriteValue(
|
||||
null, this.Name,
|
||||
_titleLabelYohakuVarticalNumeric.Name,
|
||||
_titleLabelYohakuVarticalNumeric.Value.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// デフォルトのメニュー項目(表示設定など)を作成
|
||||
/// </summary>
|
||||
private void CreateDefaultMenu()
|
||||
{
|
||||
// 仕切り線
|
||||
MainContextMenu.Items.Add(new ToolStripSeparator());
|
||||
|
||||
// 表示設定(親)
|
||||
var hyojiSetteiMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "HyojiSetteiMenu",
|
||||
Text = "表示設定",
|
||||
};
|
||||
MainContextMenu.Items.Add(hyojiSetteiMenu);
|
||||
|
||||
// メニューのフォント(クリック動作)
|
||||
var menuFontMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "MenuFontMenu",
|
||||
Text = "メニューのフォント...",
|
||||
};
|
||||
menuFontMenu.Click += (s, e)=>
|
||||
{
|
||||
ContextMenuHelper.SelectMenuFont(this, MainContextMenu);
|
||||
};
|
||||
hyojiSetteiMenu.DropDownItems.Add(menuFontMenu);
|
||||
|
||||
// グリッドメニュー(親)
|
||||
var gridMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "GridMenu",
|
||||
Text = "グリッド",
|
||||
};
|
||||
hyojiSetteiMenu.DropDownItems.Add(gridMenu);
|
||||
|
||||
// グリッドフォントメニュー(クリック動作)
|
||||
var gridFontMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "GridFontMenu",
|
||||
Text = "フォント...",
|
||||
};
|
||||
gridFontMenu.Click += (s, e) =>
|
||||
{
|
||||
DgvHelper.DgvSelectFont(this, MainDgv);
|
||||
};
|
||||
gridMenu.DropDownItems.Add(gridFontMenu);
|
||||
|
||||
// グリッド列非表示メニュー(クリック動作)
|
||||
var gridColumnDisabledMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "GridColumnDisabledMenu",
|
||||
Text = "この列を非表示にする",
|
||||
};
|
||||
gridColumnDisabledMenu.Click += (s, e) =>
|
||||
{
|
||||
if (MainDgv.CurrentCell is null) return;
|
||||
MainDgv.Columns[MainDgv.CurrentCell.ColumnIndex].Visible = false;
|
||||
};
|
||||
gridMenu.DropDownItems.Add(gridColumnDisabledMenu);
|
||||
|
||||
// グリッド列再表示メニュー(クリック動作)
|
||||
var gridColumnRedispMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "GridColumnRedispMenu",
|
||||
Text = "列の再表示",
|
||||
};
|
||||
gridColumnRedispMenu.Click += (s, e) =>
|
||||
{
|
||||
DgvHelper.DgvRedispAllColumn(MainDgv);
|
||||
};
|
||||
gridMenu.DropDownItems.Add(gridColumnRedispMenu);
|
||||
|
||||
// グリッド列幅自動調整メニュー(クリック動作)
|
||||
var columnWidthAutoAdjustMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "ColumnWidthAutoAdjustMenu",
|
||||
Text = "列幅の自動調整",
|
||||
};
|
||||
columnWidthAutoAdjustMenu.Click += (s, e) =>
|
||||
{
|
||||
DgvHelper.DgvColumnWidthAutoAdjust(MainDgv);
|
||||
};
|
||||
gridMenu.DropDownItems.Add(columnWidthAutoAdjustMenu);
|
||||
|
||||
// グリッド列固定メニュー(クリック動作)
|
||||
var gridColumnFixMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "GridColumnFixMenu",
|
||||
Text = "列固定",
|
||||
};
|
||||
gridColumnFixMenu.Click += (s, e) =>
|
||||
{
|
||||
DgvHelper.DgvColumnFix(MainDgv);
|
||||
};
|
||||
gridMenu.DropDownItems.Add(gridColumnFixMenu);
|
||||
|
||||
// グリッド列固定解除メニュー(クリック動作)
|
||||
var gridColumnFixKaijoMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "GridColumnFixKaijoMenu",
|
||||
Text = "列固定解除",
|
||||
};
|
||||
gridColumnFixKaijoMenu.Click += (s, e) =>
|
||||
{
|
||||
DgvHelper.DgvColumnFixKaijo(MainDgv);
|
||||
};
|
||||
gridMenu.DropDownItems.Add(gridColumnFixKaijoMenu);
|
||||
|
||||
// グリッドのヘッダ(親)
|
||||
//this.GridHeaderMenu});
|
||||
var gridHeaderMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "GridHeaderMenu",
|
||||
Text = "ヘッダ",
|
||||
};
|
||||
gridMenu.DropDownItems.Add(gridHeaderMenu);
|
||||
|
||||
// グリッドヘッダ背景色(クリック動作)
|
||||
var gridHeaderBackColorMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "GridHeaderBackColorMenu",
|
||||
Text = "ヘッダ背景色...",
|
||||
};
|
||||
gridHeaderBackColorMenu.Click += (s, e) =>
|
||||
{
|
||||
DgvHelper.DgvSelectHeaderBackColor(this, MainDgv);
|
||||
};
|
||||
gridHeaderMenu.DropDownItems.Add(gridHeaderBackColorMenu);
|
||||
|
||||
// グリッドヘッダの日の背景色(クリック動作)
|
||||
var gridHeaderDayBackColorMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "GridHeaderDayBackColorMenu",
|
||||
Text = "日の背景色...",
|
||||
Enabled = false, // デフォルトは非活性
|
||||
};
|
||||
gridHeaderDayBackColorMenu.Click += (s, e) =>
|
||||
{
|
||||
DgvHelper.DgvSelectHeaderBackColorWithNameMatch(this, MainDgv, "ColDay*", gridHeaderDayBackColorMenu.Name);
|
||||
};
|
||||
gridHeaderMenu.DropDownItems.Add(gridHeaderDayBackColorMenu);
|
||||
|
||||
// グリッドヘッダの非稼働日の背景色(クリック動作)
|
||||
var gridHeaderHikadobiBackColorMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "GridHeaderHikadobiBackColorMenu",
|
||||
Text = "非稼働日の背景色...",
|
||||
Enabled = false, // デフォルトは非活性
|
||||
};
|
||||
gridHeaderHikadobiBackColorMenu.Click += (s, e) =>
|
||||
{
|
||||
// Comming soon!
|
||||
MessageBox.Show(this,"カミングスーン!",this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
};
|
||||
gridHeaderMenu.DropDownItems.Add(gridHeaderHikadobiBackColorMenu);
|
||||
|
||||
//this.GridHeaderMenu.DropDownItems.AddRange(
|
||||
// new System.Windows.Forms.ToolStripItem[] {
|
||||
//this.,
|
||||
//this.,
|
||||
//this.});
|
||||
|
||||
// グリッドメニューを開くときの制御
|
||||
gridMenu.DropDownOpening += (s, e) =>
|
||||
{
|
||||
// 「この列の非表示」はアクティブセルがあるときだけ有効
|
||||
gridColumnDisabledMenu.Enabled = !(MainDgv.CurrentCell is null);
|
||||
// 「列の再表示」は非表示列があるときだけ有効
|
||||
gridColumnRedispMenu.Enabled =
|
||||
MainDgv.Columns.GetColumnCount(DataGridViewElementStates.Visible)
|
||||
!= MainDgv.Columns.Count;
|
||||
// 「列固定」はアクティブセルがあるときだけ有効
|
||||
gridColumnFixMenu.Enabled = !(MainDgv.CurrentCell is null);
|
||||
// 「列固定解除」は列固定がされているときだけ有効
|
||||
gridColumnFixKaijoMenu.Enabled = MainDgv.Columns
|
||||
.Cast<DataGridViewColumn>()
|
||||
.Any(c => c.Frozen);
|
||||
};
|
||||
|
||||
// タイトル(親)
|
||||
var titleMenu =
|
||||
new ToolStripMenuItem()
|
||||
{
|
||||
Name = "TitleMenu",
|
||||
Text = "タイトル",
|
||||
};
|
||||
hyojiSetteiMenu.DropDownItems.Add(titleMenu);
|
||||
|
||||
// タイトル表示(チェックボックス)
|
||||
TitleVisibleCheckMenu =
|
||||
new ToolStripMenuItem()
|
||||
{
|
||||
Name = "TitleVisibleCheckMenu",
|
||||
Text = "タイトル表示?",
|
||||
CheckOnClick = true,
|
||||
};
|
||||
TitleVisibleCheckMenu.CheckedChanged += (s, e) =>
|
||||
{
|
||||
var mi = (ToolStripMenuItem)s;
|
||||
IniHelper.WriteBoolValue(null, this.Name, mi.Name,
|
||||
mi.Checked);
|
||||
TitleLabel.Visible = mi.Checked;
|
||||
};
|
||||
titleMenu.DropDownItems.Add(TitleVisibleCheckMenu);
|
||||
|
||||
// タイトルフォントメニュー(クリック動作)
|
||||
var titleFontMenu =
|
||||
new ToolStripMenuItem()
|
||||
{
|
||||
Name = "TitleFontMenu",
|
||||
Text = "フォント...",
|
||||
};
|
||||
titleFontMenu.Click += (s, e) =>
|
||||
{
|
||||
ContextMenuHelper.SelectControlFont(this, TitleLabel);
|
||||
};
|
||||
titleMenu.DropDownItems.Add(titleFontMenu);
|
||||
|
||||
// タイトル余白(親)
|
||||
var titleYohakuMenu = new ToolStripMenuItem()
|
||||
{
|
||||
Name = "TitleYohakuMenu",
|
||||
Text = "余白",
|
||||
};
|
||||
titleMenu.DropDownItems.Add(titleYohakuMenu);
|
||||
|
||||
// 余白設定パネル
|
||||
titleYohakuMenu.DropDownItems.Add(CreateYohakuPanelMenu());
|
||||
|
||||
// 仕切り線
|
||||
MainContextMenu.Items.Add(new ToolStripSeparator());
|
||||
|
||||
// バージョン表示メニュー(表示のみ)
|
||||
_versionMenu =
|
||||
new ToolStripMenuItem()
|
||||
{
|
||||
Name = "VersionMenu",
|
||||
Text = "バージョン情報",
|
||||
};
|
||||
MainContextMenu.Items.Add(_versionMenu);
|
||||
|
||||
//titleMenu.DropDownItems.Add(CreateYohakuPanelMenu());
|
||||
//MainContextMenu.Items.Add(CreateYohakuPanelMenu());
|
||||
|
||||
// 実験!✨✨✨
|
||||
|
||||
//// NumericUpDownを生成して設定
|
||||
//NumericUpDown numericUpDown = new NumericUpDown();
|
||||
//numericUpDown.Minimum = 0;
|
||||
//numericUpDown.Maximum = 100;
|
||||
//numericUpDown.Value = 10;
|
||||
//numericUpDown.Width = 60; // メニュー内で邪魔にならない幅に調整
|
||||
//// ToolStripControlHostでラップしてメニューに追加
|
||||
//ToolStripControlHost host = new ToolStripControlHost(numericUpDown);
|
||||
//MainContextMenu.Items.Add(host); // または menuStrip1.Items.Add(host);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 余白調整パネルメニュー作成
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private ToolStripControlHost CreateYohakuPanelMenu()
|
||||
{
|
||||
// 1. 土台となるパネル(縦方向にコントロールを並べる)
|
||||
TableLayoutPanel miniDialog = new TableLayoutPanel();
|
||||
miniDialog.ColumnCount = 2; // 2列のグリッド
|
||||
miniDialog.RowCount = 2; // 3; // 3行
|
||||
miniDialog.AutoSize = true;
|
||||
miniDialog.Padding = new Padding(10); // 周囲に余白を作ってダイアログ感を出す
|
||||
miniDialog.BackColor = Color.FromArgb(240, 240, 240); // ほんのり背景色を変える
|
||||
// 2. コントロール達を作成
|
||||
Label lblX = new Label { Text = "横余白:", AutoSize = true, Anchor = AnchorStyles.Left };
|
||||
_titleLabelYohakuHorizonNumeric = new NumericUpDown
|
||||
{
|
||||
Name = "TitleLabelYohakuHorizonNumeric",
|
||||
Width = 60,
|
||||
TextAlign = HorizontalAlignment.Right,
|
||||
};
|
||||
_titleLabelYohakuHorizonNumeric.ValueChanged += (sender, e) =>
|
||||
{
|
||||
TitleLabel.Padding = new Padding(
|
||||
(int)_titleLabelYohakuHorizonNumeric.Value,
|
||||
TitleLabel.Padding.Top,
|
||||
(int)_titleLabelYohakuHorizonNumeric.Value,
|
||||
TitleLabel.Padding.Bottom);
|
||||
// 🔥🌊INI書きはFormClosingで行う!
|
||||
};
|
||||
Label lblY = new Label { Text = "縦余白:", AutoSize = true, Anchor = AnchorStyles.Left };
|
||||
_titleLabelYohakuVarticalNumeric = new NumericUpDown
|
||||
{
|
||||
Name = "TitleLabelYohakuVarticalNumeric",
|
||||
Width = 60,
|
||||
TextAlign = HorizontalAlignment.Right,
|
||||
};
|
||||
_titleLabelYohakuVarticalNumeric.ValueChanged += (sender, e) =>
|
||||
{
|
||||
TitleLabel.Padding = new Padding(
|
||||
TitleLabel.Padding.Left,
|
||||
(int)_titleLabelYohakuVarticalNumeric.Value,
|
||||
TitleLabel.Padding.Right,
|
||||
(int)_titleLabelYohakuVarticalNumeric.Value);
|
||||
// 🔥🌊INI書きはFormClosingで行う!
|
||||
};
|
||||
//CheckBox chkAuto = new CheckBox { Text = "自動調整", AutoSize = true };
|
||||
// 3. グリッドパネルに綺麗に配置
|
||||
miniDialog.Controls.Add(lblX, 0, 0);
|
||||
miniDialog.Controls.Add(_titleLabelYohakuHorizonNumeric, 1, 0);
|
||||
miniDialog.Controls.Add(lblY, 0, 1);
|
||||
miniDialog.Controls.Add(_titleLabelYohakuVarticalNumeric, 1, 1);
|
||||
//// チェックボックスは2列分ぶち抜きで配置
|
||||
//miniDialog.Controls.Add(chkAuto, 0, 2);
|
||||
//miniDialog.SetColumnSpan(chkAuto, 2);
|
||||
// 4. メニューにホストする
|
||||
//ToolStripControlHost dialogHost = new ToolStripControlHost(miniDialog);
|
||||
//MainContextMenu.Items.Add(dialogHost);
|
||||
|
||||
// 開くときの処理
|
||||
var tssh = new ToolStripControlHost(miniDialog);
|
||||
tssh.OwnerChanged += (sender, e) =>
|
||||
{
|
||||
// 親となるメニュー(ToolStripDropDown)を取得
|
||||
if (tssh.Owner is ToolStripDropDown parentMenu)
|
||||
{
|
||||
// 親の「開く直前イベント」に、自分のメソッドをこっそり登録する!
|
||||
parentMenu.Opening -= ParentMenu_Opening; // 二重登録防止
|
||||
parentMenu.Opening += ParentMenu_Opening;
|
||||
}
|
||||
};
|
||||
return tssh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 親メニュー開くときに追加する処理
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ParentMenu_Opening(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
//// フォントを親に合わせる(階層深いと反映されないため)
|
||||
//_titleLabelYohakuHorizonNumeric.Font =
|
||||
// _titleLabelYohakuVarticalNumeric.Font =
|
||||
// MainContextMenu.Font;
|
||||
// パネルの合わせ、再レイアウト(パネルが階層奥深くだと、なぜか反映されていなかったりする)
|
||||
var parent = _titleLabelYohakuHorizonNumeric.Parent;
|
||||
if (parent != null)
|
||||
{
|
||||
parent.Font = MainContextMenu.Font;
|
||||
parent.PerformLayout();
|
||||
}
|
||||
|
||||
// タイトルラベルの現在の余白をNumericUpDownに設定
|
||||
_titleLabelYohakuHorizonNumeric.Value = TitleLabel.Padding.Left;
|
||||
_titleLabelYohakuVarticalNumeric.Value = TitleLabel.Padding.Top;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// メニュー項目追加
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
/// <param name="onCheckedChanged"></param>
|
||||
/// <returns></returns>
|
||||
protected ToolStripMenuItem AddCheckMenuItem(
|
||||
int index,
|
||||
string text,
|
||||
string name,
|
||||
bool defaultValue,
|
||||
Action<bool> onCheckedChanged = null)
|
||||
{
|
||||
var item = new ToolStripMenuItem(text);
|
||||
|
||||
// チェックボックスとして機能する
|
||||
item.CheckOnClick = true;
|
||||
|
||||
item.Name = name;
|
||||
|
||||
// 3. CheckedChanged イベントをここで一括で仕込む!
|
||||
item.CheckedChanged += (sender, e) =>
|
||||
{
|
||||
var mi = (ToolStripMenuItem)sender;
|
||||
|
||||
// チェック値をINI保存
|
||||
IniHelper.WriteBoolValue(null, this.Name, mi.Name, mi.Checked);
|
||||
|
||||
// イベントプロシージャ(あるとき)
|
||||
onCheckedChanged?.Invoke(mi.Checked);
|
||||
};
|
||||
|
||||
MainContextMenu.Items.Insert(index, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
public enum PoiAlign
|
||||
{
|
||||
Left,
|
||||
Right,
|
||||
Center,
|
||||
}
|
||||
|
||||
private DataGridViewContentAlignment GetDgvAlign(PoiAlign align)
|
||||
{
|
||||
switch (align)
|
||||
{
|
||||
case PoiAlign.Left: return DataGridViewContentAlignment.MiddleLeft;
|
||||
case PoiAlign.Center: return DataGridViewContentAlignment.MiddleCenter;
|
||||
case PoiAlign.Right: return DataGridViewContentAlignment.MiddleRight;
|
||||
default: return DataGridViewContentAlignment.MiddleLeft;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 列追加
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="align"></param>
|
||||
protected void AddColumn(string name, string text, PoiAlign align = PoiAlign.Left)
|
||||
{
|
||||
var col = new DataGridViewTextBoxColumn()
|
||||
{
|
||||
Name = name,
|
||||
HeaderText = text,
|
||||
ReadOnly = true,
|
||||
};
|
||||
col.DefaultCellStyle.Alignment = GetDgvAlign(align);
|
||||
MainDgv.Columns.Add(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
using ClosedXML.Excel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace KssSmaPlaLib.Forms
|
||||
{
|
||||
public static class DataGridViewExporter
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// DataGridView の「可視列・可視行のみ」を Excel へエクスポートします。
|
||||
/// 列順は DisplayIndex 順/ヘッダー付き/自動調整/簡易罫線付き。
|
||||
/// </summary>
|
||||
public static void ExportVisibleToExcel(
|
||||
DataGridView dgv,
|
||||
string filePath,
|
||||
string sheetName = "Export")
|
||||
{
|
||||
if (dgv == null) throw new ArgumentNullException(nameof(dgv));
|
||||
if (string.IsNullOrWhiteSpace(filePath)) throw new ArgumentException("filePath is required.", nameof(filePath));
|
||||
|
||||
// 可視列のみ、DisplayIndex順に並べ替え
|
||||
var visibleCols = dgv.Columns
|
||||
.Cast<DataGridViewColumn>()
|
||||
.Where(c => c.Visible)
|
||||
.OrderBy(c => c.DisplayIndex)
|
||||
.ToList();
|
||||
|
||||
// 可視行のみ(新規行除外)
|
||||
var visibleRows = dgv.Rows
|
||||
.Cast<DataGridViewRow>()
|
||||
.Where(r => r.Visible && !r.IsNewRow)
|
||||
.ToList();
|
||||
|
||||
using (var wb = new XLWorkbook())
|
||||
{
|
||||
var ws = wb.Worksheets.Add(string.IsNullOrWhiteSpace(sheetName) ? "Sheet1" : sheetName);
|
||||
|
||||
int row = 1;
|
||||
int col = 1;
|
||||
|
||||
// ヘッダー行
|
||||
foreach (var c in visibleCols)
|
||||
{
|
||||
ws.Cell(row, col).Value = c.HeaderText ?? c.Name;
|
||||
// すこし見やすく
|
||||
ws.Cell(row, col).Style.Font.Bold = true;
|
||||
ws.Cell(row, col).Style.Fill.BackgroundColor = XLColor.LightGray;
|
||||
ws.Cell(row, col).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
|
||||
col++;
|
||||
}
|
||||
|
||||
// データ行
|
||||
row = 2;
|
||||
foreach (var r in visibleRows)
|
||||
{
|
||||
col = 1;
|
||||
foreach (var c in visibleCols)
|
||||
{
|
||||
var cell = r.Cells[c.Index];
|
||||
var val = cell.Value;
|
||||
|
||||
if (val == null || val == DBNull.Value)
|
||||
{
|
||||
ws.Cell(row, col).Clear(); // 空セル(文字列""よりこちらが自然)
|
||||
}
|
||||
else
|
||||
{
|
||||
// ValueType を優先し、なければ実オブジェクトの型で判定
|
||||
var vt = cell.ValueType ?? val.GetType();
|
||||
|
||||
if (vt == typeof(int) || vt == typeof(long) || vt == typeof(short) || vt == typeof(byte))
|
||||
{
|
||||
ws.Cell(row, col).Value = Convert.ToInt64(val); // 長整数に寄せると安全
|
||||
// 必要なら桁区切りなど: ws.Cell(row, col).Style.NumberFormat.Format = "#,##0";
|
||||
}
|
||||
else if (vt == typeof(decimal))
|
||||
{
|
||||
ws.Cell(row, col).Value = Convert.ToDecimal(val);
|
||||
// 書式例: ws.Cell(row, col).Style.NumberFormat.Format = "#,##0.####";
|
||||
}
|
||||
else if (vt == typeof(double) || vt == typeof(float))
|
||||
{
|
||||
ws.Cell(row, col).Value = Convert.ToDouble(val);
|
||||
}
|
||||
else if (vt == typeof(DateTime))
|
||||
{
|
||||
ws.Cell(row, col).Value = Convert.ToDateTime(val);
|
||||
// 例: ws.Cell(row, col).Style.DateFormat.Format = "yyyy-mm-dd hh:mm";
|
||||
}
|
||||
else if (vt == typeof(TimeSpan))
|
||||
{
|
||||
// Excelは TimeSpan を日数として扱うので適宜書式を
|
||||
var ts = (TimeSpan)val;
|
||||
ws.Cell(row, col).Value = ts;
|
||||
ws.Cell(row, col).Style.NumberFormat.Format = "[h]:mm:ss";
|
||||
}
|
||||
else if (vt == typeof(bool))
|
||||
{
|
||||
ws.Cell(row, col).Value = Convert.ToBoolean(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
// それ以外は文字列にフォールバック(トリム等はお好みで)
|
||||
ws.Cell(row, col).Value = val.ToString();
|
||||
}
|
||||
}
|
||||
col++;
|
||||
}
|
||||
row++;
|
||||
}
|
||||
|
||||
//// データ行
|
||||
//row = 2;
|
||||
//foreach (var r in visibleRows)
|
||||
//{
|
||||
// col = 1;
|
||||
// foreach (var c in visibleCols)
|
||||
// {
|
||||
// object val = r.Cells[c.Index].Value;
|
||||
// // Excel側でよく見えるように値をそのままセット
|
||||
// ws.Cell(row, col).Value = val == null ? string.Empty : val.ToString();
|
||||
// col++;
|
||||
// }
|
||||
// row++;
|
||||
//}
|
||||
|
||||
// テーブルっぽく罫線&自動調整
|
||||
var lastRow = row - 1;
|
||||
var lastCol = visibleCols.Count;
|
||||
if (lastCol > 0 && lastRow > 0)
|
||||
{
|
||||
var rng = ws.Range(1, 1, lastRow, lastCol);
|
||||
rng.Style.Border.OutsideBorder = XLBorderStyleValues.Thin;
|
||||
rng.Style.Border.InsideBorder = XLBorderStyleValues.Thin;
|
||||
rng.SetAutoFilter(); // フィルターもあると便利
|
||||
ws.Columns(1, lastCol).AdjustToContents();
|
||||
}
|
||||
|
||||
// 保存
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
|
||||
wb.SaveAs(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SaveFileDialog 付きの簡便版。UIからサクッと呼び出す用。
|
||||
/// </summary>
|
||||
public static void ExportVisibleToExcelWithDialog(DataGridView dgv, string defaultFileName = "export.xlsx")
|
||||
{
|
||||
using (var sfd = new SaveFileDialog()
|
||||
{
|
||||
Filter = "Excel Workbook (*.xlsx)|*.xlsx",
|
||||
FileName = defaultFileName,
|
||||
OverwritePrompt = true,
|
||||
AddExtension = true
|
||||
})
|
||||
{
|
||||
if (sfd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
ExportVisibleToExcel(dgv, sfd.FileName);
|
||||
MessageBox.Show("Excelにエクスポートしました。", "完了", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace KssSmaPlaLib.Forms
|
||||
{
|
||||
public static class DatePickerHelper
|
||||
{
|
||||
public static DateTime? ShowDateDialog(
|
||||
DateTime? defaultDate = null,
|
||||
string title = "日付を選択してください")
|
||||
{
|
||||
// 1. その場限りのフォームを作成
|
||||
using (Form form = new Form())
|
||||
{
|
||||
DateTimePicker dtp = new DateTimePicker();
|
||||
Button btnOk = new Button();
|
||||
|
||||
// フォームの設定
|
||||
form.Text = title;
|
||||
form.Size = new System.Drawing.Size(240, 120);
|
||||
form.FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||
form.StartPosition = FormStartPosition.CenterParent;
|
||||
form.MaximizeBox = false;
|
||||
form.MinimizeBox = false;
|
||||
|
||||
// DateTimePickerの設定
|
||||
dtp.Location = new System.Drawing.Point(10, 10);
|
||||
dtp.Size = new System.Drawing.Size(200, 20);
|
||||
dtp.Format = DateTimePickerFormat.Short;
|
||||
|
||||
// ★ ここで初期値をセット!
|
||||
// 引数がnullなら今日の値を、あればその値をセットします。
|
||||
dtp.Value = defaultDate ?? DateTime.Today;
|
||||
|
||||
// OKボタンの設定
|
||||
btnOk.Text = "OK";
|
||||
btnOk.DialogResult = DialogResult.OK; // これを押すとフォームが閉じる
|
||||
btnOk.Location = new System.Drawing.Point(135, 45);
|
||||
form.AcceptButton = btnOk; // EnterキーでOK
|
||||
|
||||
// コントロールを追加
|
||||
form.Controls.Add(dtp);
|
||||
form.Controls.Add(btnOk);
|
||||
|
||||
// 2. ダイアログとして表示
|
||||
if (form.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
return dtp.Value; // 選択された日付を返す
|
||||
}
|
||||
}
|
||||
return null; // キャンセルされた場合
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,726 @@
|
||||
using KssSmaPlaLib.Commons;
|
||||
using KssSmaPlaLib.Forms.ContextMenuFunction;
|
||||
using KssSmaPlaLib.Ini;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace KssSmaPlaLib.Forms
|
||||
{
|
||||
public class DgvHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 汎用的な初期化
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void Initialize(DataGridView dgv)
|
||||
{
|
||||
// 行選択
|
||||
dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
|
||||
// 行ヘッダ消去
|
||||
dgv.RowHeadersVisible = false;
|
||||
|
||||
// 編集不可
|
||||
dgv.ReadOnly = true;
|
||||
|
||||
// ユーザ操作制限
|
||||
dgv.AllowUserToAddRows = false;
|
||||
dgv.AllowUserToDeleteRows = false;
|
||||
dgv.AllowUserToOrderColumns = false;
|
||||
dgv.AllowUserToResizeColumns = true;
|
||||
dgv.AllowUserToResizeRows = false;
|
||||
|
||||
// 列ヘッダはセンタリング
|
||||
dgv.ColumnHeadersDefaultCellStyle.Alignment=DataGridViewContentAlignment.MiddleCenter;
|
||||
|
||||
//// ソート用余白を消す
|
||||
//dgv.ColumnHeadersDefaultCellStyle.Padding = new Padding(0);
|
||||
|
||||
// セル内余白(上下左右)をゼロに
|
||||
dgv.DefaultCellStyle.Padding = new Padding(0);
|
||||
|
||||
// 行高さの自動調整
|
||||
dgv.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
|
||||
|
||||
// ダブルバッファ(プロパティが隠れている)
|
||||
var type = typeof(DataGridView);
|
||||
var prop = type.GetProperty("DoubleBuffered",
|
||||
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
||||
prop.SetValue(dgv, true, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 列ヘッダのソート用余白を消す
|
||||
/// ※列が確定してからCallすること
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
//public static void ClearColumnHeaderSortYohaku(DataGridView dgv)
|
||||
//{
|
||||
// // 列ヘッダの幅にソート用の幅は不要
|
||||
// //foreach (DataGridViewColumn col in dgv.Columns) col.SortMode = DataGridViewColumnSortMode.NotSortable;
|
||||
|
||||
// // 何をやってもダメなので、テキストの先頭に余白入れます!👉ダメ!orz
|
||||
// //const string YOHAKU = " ";
|
||||
// //foreach (DataGridViewColumn col in dgv.Columns) col.HeaderText = YOHAKU + col.HeaderText;
|
||||
//}
|
||||
|
||||
// どちらのDTOでも使える共通バインド関数
|
||||
public static void BindListWithAttributeHeaders<T>(
|
||||
DataGridView grid,
|
||||
IList<T> source,
|
||||
bool isForce = false)
|
||||
{
|
||||
// 強制でないとき、データソースありなら何もしない
|
||||
if (!(grid.DataSource is null) && !isForce) return;
|
||||
|
||||
// データバインド完了後にヘッダー等を属性で上書き
|
||||
grid.DataBindingComplete += (_, __) => ApplyAttributeHeaders<T>(grid);
|
||||
|
||||
// 「とりあえず ToString() で文字列表示」したい場合の統一フォーマット
|
||||
grid.CellFormatting += (_, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// AutoGenerateColumnsだと各セルの Value はプロパティ値になります
|
||||
// ここで ToString() 統一(nullは空文字に)
|
||||
if (e.Value == null) { e.Value = string.Empty; e.FormattingApplied = true; return; }
|
||||
// 文化依存や日付/数値の既定書式を崩したくなければコメントアウト推奨
|
||||
if (!(e.Value is bool) &&
|
||||
string.IsNullOrEmpty(grid.Columns[e.ColumnIndex].DefaultCellStyle.Format))
|
||||
{
|
||||
e.Value = e.Value.ToString();
|
||||
e.FormattingApplied = true;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
};
|
||||
|
||||
grid.AutoGenerateColumns = true;
|
||||
|
||||
// 変更通知を効かせたい場合は BindingList に包む
|
||||
var bindingList = source is BindingList<T> bl ? bl : new BindingList<T>(source);
|
||||
|
||||
// BindingSource 経由が安定
|
||||
var bs = new BindingSource { DataSource = bindingList };
|
||||
grid.DataSource = bs;
|
||||
}
|
||||
|
||||
private const string KEY_NAME_DISPLAY_NAME_CSV = "DisplayNameCsv";
|
||||
|
||||
/// <summary>
|
||||
/// プライベートな子関数
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="grid"></param>
|
||||
public static void ApplyAttributeHeaders<T>(DataGridView grid)
|
||||
{
|
||||
// 編集した表示名
|
||||
var csv = IniHelper.ReadValue(null, grid.Parent.Name + "." + grid.Name, KEY_NAME_DISPLAY_NAME_CSV);
|
||||
|
||||
var props = TypeDescriptor.GetProperties(typeof(T))
|
||||
.Cast<PropertyDescriptor>()
|
||||
.ToDictionary(p => p.Name);
|
||||
|
||||
foreach (DataGridViewColumn col in grid.Columns)
|
||||
{
|
||||
var key = col.DataPropertyName ?? col.Name;
|
||||
if (key is null) continue;
|
||||
|
||||
if (props.TryGetValue(key, out var pd))
|
||||
{
|
||||
// タグに入れておく(PropertyDescriptor型)
|
||||
col.Tag = pd;
|
||||
|
||||
// 列ヘッダーを [DisplayName] に
|
||||
col.HeaderText = pd.DisplayName;
|
||||
|
||||
// 表示名を登録されてたら、置き換える
|
||||
var editName = StringUxer.GetStringByIndexFormCsv(csv,col.Index,string.Empty);
|
||||
if (!string.IsNullOrEmpty(editName)) col.HeaderText = editName;
|
||||
|
||||
// 文字寄せ
|
||||
var alignment =
|
||||
(col.HeaderText.IndexOf("[R]") >= 0 ? DataGridViewContentAlignment.MiddleRight :
|
||||
(col.HeaderText.IndexOf("[C]") >= 0 ? DataGridViewContentAlignment.MiddleCenter :
|
||||
DataGridViewContentAlignment.MiddleLeft));
|
||||
col.DefaultCellStyle.Alignment = alignment;
|
||||
col.HeaderText = col.HeaderText.Replace("[L]", "").Replace("[C]", "").Replace("[R]", "");
|
||||
|
||||
// [Browsable(false)] の列は非表示(AutoGenerateでも列が立つ場合の保険)
|
||||
var browsableAttr = pd.Attributes.OfType<BrowsableAttribute>().FirstOrDefault();
|
||||
if (browsableAttr != null && !browsableAttr.Browsable)
|
||||
{
|
||||
col.Visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 読み取り専用属性の尊重
|
||||
col.ReadOnly = pd.IsReadOnly;
|
||||
|
||||
// 便利系:ソートを自動に
|
||||
// col.SortMode = DataGridViewColumnSortMode.Automatic;
|
||||
|
||||
// 必要なら列幅の初期値
|
||||
// col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const string INI_KEY_COL_WIDTH_CSV = "ColWidthCsv";
|
||||
|
||||
/// <summary>
|
||||
/// 列幅保存(FormのFormClosingにてCall)
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvSaveColWidth(DataGridView dgv)
|
||||
{
|
||||
var section = dgv.Parent.Name + "." + dgv.Name;
|
||||
var list = new List<int>();
|
||||
foreach(DataGridViewColumn col in dgv.Columns) list.Add(col.Width);
|
||||
IniHelper.WriteValue(null, section, INI_KEY_COL_WIDTH_CSV, string.Join(",", list));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 列幅復元(FormのコンストラクタにてCall)
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvLoadColWidth(DataGridView dgv)
|
||||
{
|
||||
var section = dgv.Parent.Name + "." + dgv.Name;
|
||||
var list = IniHelper.ReadValue(null, section,INI_KEY_COL_WIDTH_CSV).Split(',').ToList();
|
||||
foreach (DataGridViewColumn col in dgv.Columns)
|
||||
{
|
||||
if (list.Count - 1 < col.Index) break;
|
||||
if (!int.TryParse(list[col.Index], out int val)) break;
|
||||
col.Width = val;
|
||||
}
|
||||
}
|
||||
|
||||
private const string INI_KEY_FONT_CSV = "Font";
|
||||
|
||||
public static void DgvSelectFont(Form form, DataGridView dgv)
|
||||
{
|
||||
if (!FontUxer.SelectFont(form, form.Name, dgv.Name + ".Font", dgv.DefaultCellStyle.Font, out var font)) return;
|
||||
DgvSetFontFromFont(dgv, font);
|
||||
DgvSaveFontToIni(dgv);
|
||||
}
|
||||
|
||||
|
||||
public static void DgvSetFontFromFont(DataGridView dgv, Font font)
|
||||
{
|
||||
var font2 = new Font(font.Name, font.Size, font.Bold ? FontStyle.Bold : FontStyle.Regular);
|
||||
dgv.DefaultCellStyle.Font = font2;
|
||||
dgv.ColumnHeadersDefaultCellStyle.Font = font2;
|
||||
dgv.AutoResizeRows();
|
||||
}
|
||||
|
||||
public static void DgvSaveFontToIni(DataGridView dgv)
|
||||
{
|
||||
var fontCsv =
|
||||
dgv.ColumnHeadersDefaultCellStyle.Font.Name + "," +
|
||||
dgv.ColumnHeadersDefaultCellStyle.Font.Size.ToString() + "," +
|
||||
dgv.ColumnHeadersDefaultCellStyle.Font.Bold.ToString();
|
||||
IniHelper.WriteValue(null, dgv.Parent.Name + "." + dgv.Name, INI_KEY_FONT_CSV, fontCsv);
|
||||
}
|
||||
|
||||
public static void DgvLoadFontFromIni(DataGridView dgv)
|
||||
{
|
||||
var defaultFontCsv =
|
||||
dgv.ColumnHeadersDefaultCellStyle.Font.Name + "," +
|
||||
dgv.ColumnHeadersDefaultCellStyle.Font.Size.ToString() + "," +
|
||||
dgv.ColumnHeadersDefaultCellStyle.Font.Bold.ToString();
|
||||
var iniFontCsv = IniHelper.ReadValue(null, dgv.Parent.Name + "." + dgv.Name, INI_KEY_FONT_CSV, defaultFontCsv);
|
||||
var fontItems = iniFontCsv.Split(',');
|
||||
if (fontItems.Length != 3) fontItems = defaultFontCsv.Split(',');
|
||||
if (float.TryParse(fontItems[1], out var size) == false) size = dgv.ColumnHeadersDefaultCellStyle.Font.Size;
|
||||
if (bool.TryParse(fontItems[2], out var bold) == false) bold = dgv.ColumnHeadersDefaultCellStyle.Font.Bold;
|
||||
var font = new Font(fontItems[0], size, bold ? FontStyle.Bold : FontStyle.Regular);
|
||||
dgv.DefaultCellStyle.Font = font;
|
||||
dgv.ColumnHeadersDefaultCellStyle.Font = font;
|
||||
dgv.AutoResizeRows();
|
||||
}
|
||||
|
||||
private const string KEY_NAME_DISPLAY_INDEX_CSV = "DisplayIndexCsv";
|
||||
private const string KEY_NAME_COLUMN_VISIBLE_CSV = "ColumnVisibleCsv";
|
||||
|
||||
/// <summary>
|
||||
/// INIの列表示順をDGVに反映
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void SetColumnDisplayIndexFromIni(DataGridView dgv)
|
||||
{
|
||||
// 表示順(DisplayIndex)の設定
|
||||
var csv = IniHelper.ReadValue(null, dgv.Parent.Name + "." + dgv.Name, KEY_NAME_DISPLAY_INDEX_CSV);
|
||||
if (string.IsNullOrEmpty(csv)) return;
|
||||
var items = csv.Split(',');
|
||||
if (items.Length != dgv.Columns.Count) return;
|
||||
List<int> displayIndexList = new List<int>();
|
||||
foreach ( var item in items) displayIndexList.Add(int.Parse(item));
|
||||
for (var cnt = 0; cnt < dgv.Columns.Count; cnt++)
|
||||
{
|
||||
var index = displayIndexList.IndexOf(cnt);
|
||||
dgv.Columns[index].DisplayIndex = cnt;
|
||||
}
|
||||
|
||||
// 列の表示/非表示の設定
|
||||
csv = IniHelper.ReadValue(null, dgv.Parent.Name + "." + dgv.Name, KEY_NAME_COLUMN_VISIBLE_CSV);
|
||||
if (string.IsNullOrEmpty(csv)) return;
|
||||
items = csv.Split(',');
|
||||
if (items.Length != dgv.Columns.Count) return;
|
||||
List<bool> visibleList = new List<bool>();
|
||||
foreach (var item in items) visibleList.Add(bool.TryParse(item, out var boolValue) ? boolValue : true);
|
||||
for (var cnt = 0; cnt < dgv.Columns.Count; cnt++)
|
||||
{
|
||||
dgv.Columns[cnt].Visible = visibleList[cnt];
|
||||
}
|
||||
}
|
||||
|
||||
public static void MoveRow(DataGridView dgv, int rowIndex, bool moveUp)
|
||||
{
|
||||
// 移動先のインデックスを計算
|
||||
int targetIndex = moveUp ? rowIndex - 1 : rowIndex + 1;
|
||||
|
||||
// 範囲チェック(一番上より上、または一番下より下には行かない)
|
||||
if (targetIndex < 0 || targetIndex >= dgv.Rows.Count - (dgv.AllowUserToAddRows ? 1 : 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 選択状態などを保持したい場合の準備
|
||||
DataGridViewRow row = dgv.Rows[rowIndex];
|
||||
|
||||
// 一旦削除して挿入し直す
|
||||
dgv.Rows.RemoveAt(rowIndex);
|
||||
dgv.Rows.Insert(targetIndex, row);
|
||||
|
||||
// 移動後の行を選択状態にする(ユーザー体験向上)
|
||||
dgv.ClearSelection();
|
||||
dgv.Rows[targetIndex].Selected = true;
|
||||
dgv.CurrentCell = dgv.Rows[targetIndex].Cells[0];
|
||||
}
|
||||
|
||||
private const string INI_KEY_DGV_ROW_HEADER_HEIGHT = "DgvRowHeaderHeight";
|
||||
|
||||
/// <summary>
|
||||
/// ヘッダ行の高さ保存
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvSaveHeaderHeight(DataGridView dgv)
|
||||
{
|
||||
var section = dgv.Parent.Name + "." + dgv.Name;
|
||||
IniHelper.WriteValue(null, section, INI_KEY_DGV_ROW_HEADER_HEIGHT, dgv.ColumnHeadersHeight.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ヘッダ行の高さロード
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvLoadHeaderHeight(DataGridView dgv)
|
||||
{
|
||||
var section = dgv.Parent.Name + "." + dgv.Name;
|
||||
var str = IniHelper.ReadValue(null, section, INI_KEY_DGV_ROW_HEADER_HEIGHT, dgv.ColumnHeadersHeight.ToString());
|
||||
dgv.ColumnHeadersHeight = int.TryParse(str, out var intValue) ? intValue : dgv.ColumnHeadersHeight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 非表示列の再表示
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvRedispAllColumn(DataGridView dgv)
|
||||
{
|
||||
foreach (DataGridViewColumn col in dgv.Columns) col.Visible = true;
|
||||
}
|
||||
|
||||
private const string INI_KEY_COL_VISIBLE_CSV = "ColVisibleCsv";
|
||||
|
||||
/// <summary>
|
||||
/// 列の表示非表示を保存
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvSaveColVisible(DataGridView dgv)
|
||||
{
|
||||
var section = dgv.Parent.Name + "." + dgv.Name;
|
||||
var list = new List<bool>();
|
||||
foreach (DataGridViewColumn col in dgv.Columns) list.Add(col.Visible);
|
||||
IniHelper.WriteValue(null, section, INI_KEY_COL_VISIBLE_CSV, string.Join(",", list));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 列の表示非表示をロード
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvLoadColVisible(DataGridView dgv)
|
||||
{
|
||||
var section = dgv.Parent.Name + "." + dgv.Name;
|
||||
var list = IniHelper.ReadValue(null, section, INI_KEY_COL_VISIBLE_CSV).Split(',').ToList();
|
||||
foreach (DataGridViewColumn col in dgv.Columns)
|
||||
{
|
||||
if (list.Count - 1 < col.Index) break;
|
||||
if (!bool.TryParse(list[col.Index], out bool val)) break;
|
||||
col.Visible = val;
|
||||
}
|
||||
}
|
||||
|
||||
private const string INI_KEY_COL_DISPLAY_INDEX_CSV = "ColDisplayIndexCsv";
|
||||
|
||||
/// <summary>
|
||||
/// 列の表示順インデックスを保存
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvSaveColDisplayIndex(DataGridView dgv)
|
||||
{
|
||||
var section = dgv.Parent.Name + "." + dgv.Name;
|
||||
var list = new List<string>();
|
||||
foreach (DataGridViewColumn col in dgv.Columns) list.Add($"{col.Name}={col.DisplayIndex}");
|
||||
IniHelper.WriteValue(null, section, INI_KEY_COL_DISPLAY_INDEX_CSV, string.Join(",", list));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 列の表示順インデックスをロード
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvLoadColDisplayIndex(DataGridView dgv)
|
||||
{
|
||||
var section = dgv.Parent.Name + "." + dgv.Name;
|
||||
var list = IniHelper.ReadValue(null, section, INI_KEY_COL_DISPLAY_INDEX_CSV).Split(',').ToList();
|
||||
if (list.Count == 1 && string.IsNullOrEmpty(list[0])) return;
|
||||
Dictionary<int,string> dic = new Dictionary<int,string>();
|
||||
foreach (var str in list)
|
||||
{
|
||||
dic.Add(int.Parse(str.Split('=')[1]), str.Split('=')[0]);
|
||||
}
|
||||
|
||||
// DisplayIndexは小さい方から設定しないと崩れる
|
||||
foreach (var di in dic.Keys.OrderBy(m => m))
|
||||
{
|
||||
dgv.Columns[dic[di]].DisplayIndex = di;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 列幅の自動調整
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvColumnWidthAutoAdjust(DataGridView dgv)
|
||||
{
|
||||
dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 行高さの自動調整
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvRowHeightAutoAdjust(DataGridView dgv)
|
||||
{
|
||||
dgv.AutoResizeRows(DataGridViewAutoSizeRowsMode.AllCells);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 列固定
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvColumnFix(DataGridView dgv)
|
||||
{
|
||||
if (dgv.CurrentCell == null) return;
|
||||
|
||||
// 1. 今クリックした列の「見た目の位置」を取得
|
||||
int targetDisplayIndex = dgv.CurrentCell.OwningColumn.DisplayIndex;
|
||||
|
||||
// 2. いったん全列の固定を解除(これをしないとエラーになる場合がある)
|
||||
DgvColumnFixKaijo(dgv);
|
||||
|
||||
// 3. 見た目の位置(DisplayIndex)が、ターゲット以下の列をすべて固定!
|
||||
// ※DisplayIndexの小さい順(左側から順)にFrozenをかけていくのがコツ
|
||||
var targetColumns = dgv.Columns.Cast<DataGridViewColumn>()
|
||||
.OrderBy(c => c.DisplayIndex);
|
||||
|
||||
foreach (var col in targetColumns)
|
||||
{
|
||||
if (col.DisplayIndex <= targetDisplayIndex)
|
||||
{
|
||||
col.Frozen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 列固定解除
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvColumnFixKaijo(DataGridView dgv)
|
||||
{
|
||||
// 2. いったん全列の固定を解除(これをしないとエラーになる場合がある)
|
||||
foreach (DataGridViewColumn col in dgv.Columns)
|
||||
{
|
||||
col.Frozen = false;
|
||||
}
|
||||
}
|
||||
|
||||
private const string INI_KEY_COL_FROZEN_CSV = "ColFrozenCsv";
|
||||
|
||||
/// <summary>
|
||||
/// 列の固定を保存
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvSaveColFrozen(DataGridView dgv)
|
||||
{
|
||||
var section = dgv.Parent.Name + "." + dgv.Name;
|
||||
var list = new List<bool>();
|
||||
foreach (DataGridViewColumn col in dgv.Columns) list.Add(col.Frozen);
|
||||
IniHelper.WriteValue(null, section, INI_KEY_COL_FROZEN_CSV, string.Join(",", list));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 列の固定をロード
|
||||
/// </summary>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvLoadColFrozen(DataGridView dgv)
|
||||
{
|
||||
var section = dgv.Parent.Name + "." + dgv.Name;
|
||||
var list = IniHelper.ReadValue(null, section, INI_KEY_COL_FROZEN_CSV).Split(',').ToList();
|
||||
foreach (DataGridViewColumn col in dgv.Columns)
|
||||
{
|
||||
if (list.Count - 1 < col.Index) break;
|
||||
if (!bool.TryParse(list[col.Index], out bool val)) break;
|
||||
col.Frozen = val;
|
||||
}
|
||||
}
|
||||
|
||||
private const string INI_KEY_DGV_HEADER_BACK_COLOR = "DgvHeaderBackColor";
|
||||
|
||||
/// <summary>
|
||||
/// ヘッダ背景色選択
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="dgv"></param>
|
||||
public static void DgvSelectHeaderBackColor(Form form, DataGridView dgv)
|
||||
{
|
||||
using (ColorDialog cd = new ColorDialog())
|
||||
{
|
||||
// 今の色を初期選択にしておく
|
||||
cd.Color = dgv.ColumnHeadersDefaultCellStyle.BackColor;
|
||||
|
||||
if (cd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
// 1. フォームの背景色を即時変更
|
||||
dgv.ColumnHeadersDefaultCellStyle.BackColor = cd.Color;
|
||||
|
||||
// 文字色を計算して算出し設定
|
||||
dgv.ColumnHeadersDefaultCellStyle.ForeColor = ColorHelper.GetContrastColor(dgv.ColumnHeadersDefaultCellStyle.BackColor);
|
||||
|
||||
// 2. 🔥 Colorを16進数(#RRGGBB)に変換してINIに書き込み
|
||||
string colorHex = ColorTranslator.ToHtml(cd.Color);
|
||||
IniHelper.WriteValue(null, form.Name, INI_KEY_DGV_HEADER_BACK_COLOR, colorHex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ヘッダ背景色(名前でマッチした列のみ)選択
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="dgv"></param>
|
||||
/// <param name="colNamePattern"></param>
|
||||
/// <param name="iniKey"></param>
|
||||
public static void DgvSelectHeaderBackColorWithNameMatch(Form form, DataGridView dgv, string colNamePattern, string iniKey)
|
||||
{
|
||||
// マッチする列を探し、現在の色を採取
|
||||
Color? color = null;
|
||||
foreach (DataGridViewColumn col in dgv.Columns)
|
||||
{
|
||||
if (StringUxer.WildcardMatch(col.Name, colNamePattern))
|
||||
{
|
||||
color = col.HeaderCell.Style.BackColor;
|
||||
}
|
||||
}
|
||||
if (color == null)
|
||||
{
|
||||
MessageBox.Show(form, $"パターンにマッチする列なし[パターン:{colNamePattern}]");
|
||||
return;
|
||||
}
|
||||
|
||||
using (ColorDialog cd = new ColorDialog())
|
||||
{
|
||||
// 今の色を初期選択にしておく
|
||||
cd.Color = (Color)color;
|
||||
|
||||
if (cd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
var backColor = cd.Color;
|
||||
// 文字色を計算して算出し設定
|
||||
var foreColor = ColorHelper.GetContrastColor(backColor);
|
||||
|
||||
// DGVに反映
|
||||
foreach (DataGridViewColumn col in dgv.Columns)
|
||||
{
|
||||
if (StringUxer.WildcardMatch(col.Name, colNamePattern))
|
||||
{
|
||||
col.HeaderCell.Style.BackColor = backColor;
|
||||
col.HeaderCell.Style.ForeColor = foreColor;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 🔥 Colorを16進数(#RRGGBB)に変換してINIに書き込み
|
||||
string colorHex = ColorTranslator.ToHtml(cd.Color);
|
||||
IniHelper.WriteValue(null, form.Name, iniKey, colorHex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ヘッダ背景色をINIから取得して設定
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
public static void DgvSetHeaderBackColorFromIni(Form form, DataGridView dgv)
|
||||
{
|
||||
var colorHex = IniHelper.ReadValue(null, form.Name, INI_KEY_DGV_HEADER_BACK_COLOR, ColorTranslator.ToHtml(dgv.ColumnHeadersDefaultCellStyle.BackColor));
|
||||
dgv.ColumnHeadersDefaultCellStyle.BackColor = ColorTranslator.FromHtml(colorHex);
|
||||
// 文字色を計算して算出し設定
|
||||
dgv.ColumnHeadersDefaultCellStyle.ForeColor = ColorHelper.GetContrastColor(dgv.ColumnHeadersDefaultCellStyle.BackColor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ヘッダ背景色をINIから取得して設定(名前マッチング)
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="dgv"></param>
|
||||
/// <param name="colNamePattern"></param>
|
||||
/// <param name="iniKey"></param>
|
||||
public static void DgvSetHeaderBackColorFromIniWithNameMatch(Form form, DataGridView dgv, string colNamePattern, string iniKey)
|
||||
{
|
||||
// マッチする列を探し、現在の色を採取
|
||||
Color? color = null;
|
||||
foreach (DataGridViewColumn col in dgv.Columns)
|
||||
{
|
||||
if (StringUxer.WildcardMatch(col.Name, colNamePattern))
|
||||
{
|
||||
color = col.HeaderCell.Style.BackColor;
|
||||
}
|
||||
}
|
||||
if (color == null)
|
||||
{
|
||||
MessageBox.Show(form, $"パターンにマッチする列なし[パターン:{colNamePattern}]");
|
||||
return;
|
||||
}
|
||||
|
||||
// INIから取得
|
||||
var colorHex = IniHelper.ReadValue(null, form.Name, iniKey, ColorTranslator.ToHtml((Color)color));
|
||||
var backColor = ColorTranslator.FromHtml(colorHex);
|
||||
var foreColor = ColorHelper.GetContrastColor(backColor);
|
||||
|
||||
// マッチする列に設定
|
||||
foreach (DataGridViewColumn col in dgv.Columns)
|
||||
{
|
||||
if (StringUxer.WildcardMatch(col.Name, colNamePattern))
|
||||
{
|
||||
col.HeaderCell.Style.BackColor = backColor;
|
||||
col.HeaderCell.Style.ForeColor = foreColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public const string TSV_PATH = @".\@@@DGV@@@.tsv";
|
||||
|
||||
/// <summary>
|
||||
/// DGVデータTSV保存
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="dgv"></param>
|
||||
public static void SaveGridDataToTsv(Form form, DataGridView dgv)
|
||||
{
|
||||
var path = TSV_PATH.Replace("@@@DGV@@@", $"{form.Name}.{dgv.Name}");
|
||||
try
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(path, false, Encoding.UTF8))
|
||||
{
|
||||
foreach (DataGridViewRow row in dgv.Rows)
|
||||
{
|
||||
// 新規行(入力用の空行)はスキップ
|
||||
if (row.IsNewRow) continue;
|
||||
|
||||
// 各セルの値をタブで結合
|
||||
var cells = row.Cells.Cast<DataGridViewCell>().Select(c => c.Value?.ToString() ?? "");
|
||||
sw.WriteLine(string.Join("\t", cells));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("DGVのTSV保存に失敗しました: " + ex.Message);
|
||||
}
|
||||
}
|
||||
public static void LoadGridDataToTsv(Form form, DataGridView dgv)
|
||||
{
|
||||
var path = TSV_PATH.Replace("@@@DGV@@@", $"{form.Name}.{dgv.Name}");
|
||||
if (!File.Exists(path)) return;
|
||||
try
|
||||
{
|
||||
dgv.Rows.Clear();
|
||||
string[] lines = File.ReadAllLines(path, Encoding.UTF8);
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line)) continue;
|
||||
|
||||
// タブで分割して行を追加
|
||||
string[] values = line.Split('\t');
|
||||
dgv.Rows.Add(values);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("DGVのTSVによる復元に失敗しました: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SearchGrid(
|
||||
DataGridView dgv,
|
||||
string searchText,
|
||||
bool forward)
|
||||
{
|
||||
if (string.IsNullOrEmpty(searchText)) return;
|
||||
|
||||
int rowCount = dgv.RowCount;
|
||||
int colCount = dgv.ColumnCount;
|
||||
|
||||
// 現在のセルの位置を取得(選択されていなければ 0,0 から)
|
||||
int startRow = dgv.CurrentCell?.RowIndex ?? 0;
|
||||
int startCol = dgv.CurrentCell?.ColumnIndex ?? 0;
|
||||
|
||||
// 全セルをフラットなインデックスとして考えて計算
|
||||
int totalCells = rowCount * colCount;
|
||||
int startIndex = (startRow * colCount) + startCol;
|
||||
|
||||
for (int i = 1; i < totalCells; i++)
|
||||
{
|
||||
// forwardがtrueならプラス、falseならマイナス方向にずらす
|
||||
int offset = forward ? i : -i;
|
||||
int nextIndex = (startIndex + offset + totalCells) % totalCells;
|
||||
|
||||
int r = nextIndex / colCount;
|
||||
int c = nextIndex % colCount;
|
||||
|
||||
DataGridViewCell cell = dgv[c, r];
|
||||
|
||||
if (cell.Value != null && cell.Value.ToString().Contains(searchText))
|
||||
{
|
||||
dgv.CurrentCell = cell;
|
||||
return; // 見つかったら終了
|
||||
}
|
||||
}
|
||||
|
||||
MessageBox.Show("他には見つかりませんでしたにゃ!🐾");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
using KssSmaPlaLib.Ini;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace KssSmaPlaLib.Forms
|
||||
{
|
||||
public static class FormHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// フォームのコンストラクタで行う処理集
|
||||
/// </summary>
|
||||
/// <param name="frm"></param>
|
||||
public static void FormConstructorProc(Form frm)
|
||||
{
|
||||
frm.KeyPreview = true;
|
||||
FormHelper.SetTitle(frm);
|
||||
foreach (var control in frm.Controls)
|
||||
{
|
||||
if (control is DataGridView)
|
||||
{
|
||||
// DGVで行う共通処理
|
||||
var dgv = control as DataGridView;
|
||||
dgv.Dock = DockStyle.Fill;
|
||||
dgv.AllowUserToResizeRows = false;
|
||||
dgv.AllowUserToAddRows = false;
|
||||
dgv.AllowUserToDeleteRows = false;
|
||||
dgv.AllowUserToOrderColumns = false;
|
||||
dgv.AllowUserToResizeColumns = true;
|
||||
dgv.AllowUserToResizeRows = false;
|
||||
dgv.ReadOnly = true;
|
||||
dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
dgv.RowHeadersVisible = false;
|
||||
dgv.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
|
||||
// 列ヘッダのユーザによるソートを無効化する
|
||||
foreach (DataGridViewColumn col in dgv.Columns) col.SortMode = DataGridViewColumnSortMode.NotSortable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォームのロードで行う処理集
|
||||
/// </summary>
|
||||
/// <param name="frm"></param>
|
||||
/// <param name="isDgvColAutoFit"></param>
|
||||
public static void FormLoadProc(Form frm, ContextMenuStrip[] menus, bool isDgvColAutoFit = false)
|
||||
{
|
||||
FormHelper.LoadFormBounds(frm);
|
||||
foreach (var control in frm.Controls)
|
||||
{
|
||||
if (control is DataGridView)
|
||||
{
|
||||
// DGVで行う共通処理
|
||||
var dgv = control as DataGridView;
|
||||
DgvHelper.DgvLoadColVisible(dgv);
|
||||
DgvHelper.DgvLoadColDisplayIndex(dgv);
|
||||
DgvHelper.DgvLoadColFrozen(dgv);
|
||||
if (isDgvColAutoFit)
|
||||
{
|
||||
DgvHelper.DgvColumnWidthAutoAdjust(dgv);
|
||||
}
|
||||
else
|
||||
{
|
||||
DgvHelper.DgvLoadColWidth(dgv);
|
||||
}
|
||||
DgvHelper.DgvLoadFontFromIni(dgv);
|
||||
}
|
||||
}
|
||||
foreach (var menu in menus)
|
||||
{
|
||||
ContextMenuHelper.SetFont(frm, menu);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォーム閉じるときの処理集
|
||||
/// </summary>
|
||||
/// <param name="frm"></param>
|
||||
public static void FormClosingProc(Form frm)
|
||||
{
|
||||
FormHelper.SaveFormBounds(frm);
|
||||
foreach (var control in frm.Controls)
|
||||
{
|
||||
if (control is DataGridView)
|
||||
{
|
||||
// DGVで行う共通処理
|
||||
var dgv = control as DataGridView;
|
||||
DgvHelper.DgvSaveColVisible(dgv);
|
||||
DgvHelper.DgvSaveColDisplayIndex(dgv);
|
||||
DgvHelper.DgvSaveColFrozen(dgv);
|
||||
DgvHelper.DgvSaveColWidth(dgv);
|
||||
DgvHelper.DgvSaveFontToIni(dgv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const string INI_KEY_RESTORE_BOUNDS_CSV = "RestoreBoundsCsv";
|
||||
|
||||
/// <summary>
|
||||
/// フォームのバウンズ保存
|
||||
/// ※フォームのClosingイベントでCallしてください。
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
public static void SaveFormBounds(Form form)
|
||||
{
|
||||
var csv = string.Empty;
|
||||
if (form.WindowState == FormWindowState.Maximized || form.WindowState == FormWindowState.Minimized)
|
||||
{
|
||||
csv = $"{form.RestoreBounds.Width},{form.RestoreBounds.Height},{form.RestoreBounds.Top},{form.RestoreBounds.Left},{form.WindowState == FormWindowState.Maximized}";
|
||||
}
|
||||
else
|
||||
{
|
||||
csv = $"{form.Bounds.Width},{form.Bounds.Height},{form.Bounds.Top},{form.Bounds.Left},{form.WindowState == FormWindowState.Maximized}";
|
||||
}
|
||||
IniHelper.WriteValue(null, form.Name, INI_KEY_RESTORE_BOUNDS_CSV, csv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォームのバウンズ復元
|
||||
/// ※フォームのLoadイベントでCallしてください。
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
public static void LoadFormBounds(Form form)
|
||||
{
|
||||
var csv = IniHelper.ReadValue(null, form.Name, INI_KEY_RESTORE_BOUNDS_CSV);
|
||||
if (string.IsNullOrEmpty(csv)) return;
|
||||
var items = csv.Split(',');
|
||||
if (items.Length != 5) return;
|
||||
if (!int.TryParse(items[0], out var width)) return;
|
||||
if (!int.TryParse(items[1], out var height)) return;
|
||||
if (!int.TryParse(items[2], out var top)) return;
|
||||
if (!int.TryParse(items[3], out var left)) return;
|
||||
if (!bool.TryParse(items[4], out var isMaximum)) return;
|
||||
|
||||
form.Bounds = new System.Drawing.Rectangle(left, top, width, height);
|
||||
if (isMaximum) form.WindowState = FormWindowState.Maximized;
|
||||
}
|
||||
|
||||
private const string KEY_NAME_TITLE = "Title";
|
||||
|
||||
/// <summary>
|
||||
/// タイトル設定(INI優先)
|
||||
/// ※フォームのコンストラクタでCallしてください
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
public static void SetTitle(Form form)
|
||||
{
|
||||
form.Text = IniHelper.ReadValue(null, form.Name, KEY_NAME_TITLE, form.Text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// フォームの画面キャプチャを取得し画像ファイルに保存する
|
||||
/// </summary>
|
||||
/// <param name="form"></param>
|
||||
/// <param name="bitmapFilePath"></param>
|
||||
public static void GetCaptureAndSaveBitmap(Form form, string bitmapFilePath)
|
||||
{
|
||||
// フォームと同じサイズのBitmapを作成
|
||||
Bitmap bitmap = new Bitmap(form.Width, form.Height);
|
||||
|
||||
// Bitmapにフォームの内容を描画
|
||||
form.DrawToBitmap(bitmap, new Rectangle(0, 0, form.Width, form.Height));
|
||||
|
||||
// 画像ファイルとして保存
|
||||
bitmap.Save(bitmapFilePath, System.Drawing.Imaging.ImageFormat.Jpeg);
|
||||
|
||||
// リソースの解放
|
||||
bitmap.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace KssSmaPlaLib.Forms
|
||||
{
|
||||
public static class ToastNotifier
|
||||
{
|
||||
private const int WS_EX_NOACTIVATE = 0x08000000;
|
||||
private const int WS_EX_TOPMOST = 0x00000008;
|
||||
|
||||
//public static void Show(Form owner, string message, Color backColor, int durationMs = 3000)
|
||||
//{
|
||||
// // 1. フォームの基本設定
|
||||
// Form toast = new Form
|
||||
// {
|
||||
// FormBorderStyle = FormBorderStyle.None,
|
||||
// StartPosition = FormStartPosition.Manual,
|
||||
// BackColor = backColor,
|
||||
// ShowInTaskbar = false,
|
||||
// TopMost = true,
|
||||
// Size = new Size(300, 60),
|
||||
// Opacity = 0,
|
||||
// Enabled = false // トースト自体は操作不能にしておく
|
||||
// };
|
||||
// Label lbl = new Label
|
||||
// {
|
||||
// Text = message,
|
||||
// ForeColor = Color.White,
|
||||
// Font = new Font("MS UI Gothic", 10, FontStyle.Bold),
|
||||
// Dock = DockStyle.Fill,
|
||||
// TextAlign = ContentAlignment.MiddleCenter
|
||||
// };
|
||||
// toast.Controls.Add(lbl);
|
||||
// // オーナーの右下に配置
|
||||
// toast.Location = new Point(
|
||||
// owner.Location.X + owner.Width - toast.Width - 20,
|
||||
// owner.Location.Y + owner.Height - toast.Height - 20
|
||||
// );
|
||||
// // 2. タイマーでアニメーションを管理
|
||||
// Timer timer = new Timer { Interval = 10 };
|
||||
// DateTime startTime = DateTime.Now;
|
||||
// timer.Tick += (s, e) =>
|
||||
// {
|
||||
// double elapsed = (DateTime.Now - startTime).TotalMilliseconds;
|
||||
// if (elapsed < 200) // 最初の0.2秒でフェードイン
|
||||
// {
|
||||
// toast.Opacity = elapsed / 200.0;
|
||||
// }
|
||||
// else if (elapsed < 200 + durationMs) // 指定時間はそのまま
|
||||
// {
|
||||
// toast.Opacity = 1.0;
|
||||
// }
|
||||
// else if (elapsed < 200 + durationMs + 200) // 最後の0.2秒でフェードアウト
|
||||
// {
|
||||
// toast.Opacity = 1.0 - (elapsed - (200 + durationMs)) / 200.0;
|
||||
// }
|
||||
// else // 終了処理
|
||||
// {
|
||||
// timer.Stop();
|
||||
// timer.Dispose();
|
||||
// toast.Close();
|
||||
// toast.Dispose();
|
||||
// }
|
||||
// };
|
||||
// // 3. 表示開始(ここを通った瞬間にメソッドは終了し、呼び出し元に戻ります)
|
||||
// toast.Show();
|
||||
// timer.Start();
|
||||
//}
|
||||
|
||||
//public static async Task ShowAsync(Form owner, string message, Color backColor, int durationMs = 3000)
|
||||
//{
|
||||
// // 1. フォームの作成
|
||||
// using (var toast = new Form
|
||||
// {
|
||||
// FormBorderStyle = FormBorderStyle.None,
|
||||
// StartPosition = FormStartPosition.Manual,
|
||||
// BackColor = backColor,
|
||||
// ShowInTaskbar = false,
|
||||
// TopMost = true,
|
||||
// Size = new Size(300, 60),
|
||||
// Opacity = 0
|
||||
// })
|
||||
// {
|
||||
// // フォーカスを奪わないための設定(WinAPIをラップしたCreateParamsの上書き)
|
||||
// // ※簡易的にリフレクションで設定するか、Formを継承したクラスを作るのが定石です
|
||||
// Label lbl = new Label
|
||||
// {
|
||||
// Text = message,
|
||||
// ForeColor = Color.White,
|
||||
// Font = new Font("MS UI Gothic", 10, FontStyle.Bold),
|
||||
// Dock = DockStyle.Fill,
|
||||
// TextAlign = ContentAlignment.MiddleCenter
|
||||
// };
|
||||
// toast.Controls.Add(lbl);
|
||||
// toast.Location = new Point(
|
||||
// owner.Location.X + owner.Width - toast.Width - 20,
|
||||
// owner.Location.Y + owner.Height - toast.Height - 20
|
||||
// );
|
||||
// // 表示(フォーカスを奪わずに表示)
|
||||
// toast.Show();
|
||||
// // フォーカスが移るのを防ぐための念押し(Activateさせない)
|
||||
// // 2. アニメーション(async/await の真骨頂)
|
||||
// for (int i = 0; i < 10; i++) { toast.Opacity += 0.1; await Task.Delay(10); }
|
||||
// await Task.Delay(durationMs);
|
||||
// for (int i = 0; i < 10; i++) { toast.Opacity -= 0.1; await Task.Delay(10); }
|
||||
// toast.Close();
|
||||
// }
|
||||
//}
|
||||
|
||||
public static async Task ShowAsync(Form owner, string message, Color backColor, int durationMs = 3000)
|
||||
{
|
||||
// 【重要】SignalRなどの別スレッドから呼ばれても安全なように、UIスレッドへ強制バトンタッチ
|
||||
if (owner.InvokeRequired)
|
||||
{
|
||||
owner.BeginInvoke(new Action(() => { _ = ShowAsync(owner, message, backColor, durationMs); }));
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. フォームの作成(usingは使わず、Closeに任せる)
|
||||
// フォーカスを奪わない(WS_EX_NOACTIVATE = 0x08000000)を仕込んだカスタムフォームをその場で定義
|
||||
var toast = new NoActivateForm
|
||||
{
|
||||
FormBorderStyle = FormBorderStyle.None,
|
||||
StartPosition = FormStartPosition.Manual,
|
||||
BackColor = backColor,
|
||||
ShowInTaskbar = false,
|
||||
TopMost = true,
|
||||
Size = new Size(300, 60),
|
||||
Opacity = 0
|
||||
};
|
||||
|
||||
Label lbl = new Label
|
||||
{
|
||||
Text = message,
|
||||
ForeColor = Color.White,
|
||||
Font = new Font("MS UI Gothic", 10, FontStyle.Bold),
|
||||
Dock = DockStyle.Fill,
|
||||
TextAlign = ContentAlignment.MiddleCenter
|
||||
};
|
||||
toast.Controls.Add(lbl);
|
||||
|
||||
// 右下のベストポジションに配置(オーナーフォーム基準)
|
||||
toast.Location = new Point(
|
||||
owner.Location.X + owner.Width - toast.Width - 20,
|
||||
owner.Location.Y + owner.Height - toast.Height - 20
|
||||
);
|
||||
|
||||
// 表示(フォーカスを絶対に奪わない)
|
||||
toast.Show();
|
||||
|
||||
// 2. アニメーション(async/await の真骨頂!)
|
||||
for (int i = 0; i < 10; i++) { toast.Opacity += 0.1; await Task.Delay(10); }
|
||||
|
||||
await Task.Delay(durationMs);
|
||||
|
||||
for (int i = 0; i < 10; i++) { toast.Opacity -= 0.1; await Task.Delay(10); }
|
||||
|
||||
// 閉じると同時に、WinFormsが自動でメモリを綺麗に解放(Dispose)してくれます
|
||||
toast.Close();
|
||||
}
|
||||
}
|
||||
|
||||
// 【職人技】フォーカスを絶対に奪わないフォーム(CreateParamsの上書き)
|
||||
public class NoActivateForm : Form
|
||||
{
|
||||
protected override CreateParams CreateParams
|
||||
{
|
||||
get
|
||||
{
|
||||
CreateParams cp = base.CreateParams;
|
||||
cp.ExStyle |= 0x08000000; // WS_EX_NOACTIVATE(クリックしてもフォーカスが移らない魔法のフラグ)
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user