增加批量打开

This commit is contained in:
ww-rm
2025-02-27 00:04:57 +08:00
parent de4916acf4
commit 2784ec4955
5 changed files with 330 additions and 50 deletions

View File

@@ -1,4 +1,4 @@
namespace SpineViewer.src
namespace SpineViewer
{
partial class BatchOpenSpineDialog
{
@@ -28,12 +28,208 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "SkelBatchSelectForm";
panel = new Panel();
tableLayoutPanel1 = new TableLayoutPanel();
label3 = new Label();
comboBox_Version = new ComboBox();
tableLayoutPanel2 = new TableLayoutPanel();
button_Ok = new Button();
button_Cancel = new Button();
listBox_FilePath = new ListBox();
button_SelectSkel = new Button();
label_Tip = new Label();
openFileDialog_Skel = new OpenFileDialog();
label4 = new Label();
panel.SuspendLayout();
tableLayoutPanel1.SuspendLayout();
tableLayoutPanel2.SuspendLayout();
SuspendLayout();
//
// panel
//
panel.Controls.Add(tableLayoutPanel1);
panel.Dock = DockStyle.Fill;
panel.Location = new Point(0, 0);
panel.Name = "panel";
panel.Padding = new Padding(50, 15, 50, 10);
panel.Size = new Size(1126, 449);
panel.TabIndex = 1;
//
// tableLayoutPanel1
//
tableLayoutPanel1.ColumnCount = 2;
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
tableLayoutPanel1.Controls.Add(label4, 0, 0);
tableLayoutPanel1.Controls.Add(label3, 0, 3);
tableLayoutPanel1.Controls.Add(comboBox_Version, 1, 3);
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 4);
tableLayoutPanel1.Controls.Add(listBox_FilePath, 0, 2);
tableLayoutPanel1.Controls.Add(button_SelectSkel, 0, 1);
tableLayoutPanel1.Controls.Add(label_Tip, 1, 1);
tableLayoutPanel1.Dock = DockStyle.Fill;
tableLayoutPanel1.Location = new Point(50, 15);
tableLayoutPanel1.Name = "tableLayoutPanel1";
tableLayoutPanel1.RowCount = 5;
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.RowStyles.Add(new RowStyle());
tableLayoutPanel1.Size = new Size(1026, 424);
tableLayoutPanel1.TabIndex = 1;
//
// label3
//
label3.Anchor = AnchorStyles.Right;
label3.AutoSize = true;
label3.Location = new Point(90, 307);
label3.Name = "label3";
label3.Size = new Size(50, 24);
label3.TabIndex = 12;
label3.Text = "版本:";
//
// comboBox_Version
//
comboBox_Version.Anchor = AnchorStyles.Left;
comboBox_Version.DropDownStyle = ComboBoxStyle.DropDownList;
comboBox_Version.FormattingEnabled = true;
comboBox_Version.Location = new Point(146, 303);
comboBox_Version.Name = "comboBox_Version";
comboBox_Version.Size = new Size(182, 32);
comboBox_Version.Sorted = true;
comboBox_Version.TabIndex = 13;
//
// tableLayoutPanel2
//
tableLayoutPanel2.AutoSize = true;
tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink;
tableLayoutPanel2.ColumnCount = 2;
tableLayoutPanel1.SetColumnSpan(tableLayoutPanel2, 4);
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
tableLayoutPanel2.Dock = DockStyle.Bottom;
tableLayoutPanel2.Location = new Point(3, 381);
tableLayoutPanel2.Name = "tableLayoutPanel2";
tableLayoutPanel2.RowCount = 1;
tableLayoutPanel2.RowStyles.Add(new RowStyle());
tableLayoutPanel2.Size = new Size(1020, 40);
tableLayoutPanel2.TabIndex = 11;
//
// button_Ok
//
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
button_Ok.Location = new Point(368, 3);
button_Ok.Margin = new Padding(3, 3, 30, 3);
button_Ok.Name = "button_Ok";
button_Ok.Size = new Size(112, 34);
button_Ok.TabIndex = 7;
button_Ok.Text = "确认";
button_Ok.UseVisualStyleBackColor = true;
button_Ok.Click += button_Ok_Click;
//
// button_Cancel
//
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
button_Cancel.Location = new Point(540, 3);
button_Cancel.Margin = new Padding(30, 3, 3, 3);
button_Cancel.Name = "button_Cancel";
button_Cancel.Size = new Size(112, 34);
button_Cancel.TabIndex = 8;
button_Cancel.Text = "取消";
button_Cancel.UseVisualStyleBackColor = true;
button_Cancel.Click += button_Cancel_Click;
//
// listBox_FilePath
//
tableLayoutPanel1.SetColumnSpan(listBox_FilePath, 2);
listBox_FilePath.Dock = DockStyle.Fill;
listBox_FilePath.FormattingEnabled = true;
listBox_FilePath.ItemHeight = 24;
listBox_FilePath.Location = new Point(3, 97);
listBox_FilePath.Name = "listBox_FilePath";
listBox_FilePath.Size = new Size(1020, 200);
listBox_FilePath.TabIndex = 2;
//
// button_SelectSkel
//
button_SelectSkel.Anchor = AnchorStyles.None;
button_SelectSkel.Location = new Point(3, 57);
button_SelectSkel.Name = "button_SelectSkel";
button_SelectSkel.Size = new Size(137, 34);
button_SelectSkel.TabIndex = 1;
button_SelectSkel.Text = "选择文件...";
button_SelectSkel.UseVisualStyleBackColor = true;
button_SelectSkel.Click += button_SelectSkel_Click;
//
// label_Tip
//
label_Tip.AutoSize = true;
label_Tip.Dock = DockStyle.Fill;
label_Tip.Location = new Point(146, 54);
label_Tip.Name = "label_Tip";
label_Tip.Size = new Size(877, 40);
label_Tip.TabIndex = 0;
label_Tip.Text = "已选择 0 个文件";
label_Tip.TextAlign = ContentAlignment.MiddleLeft;
//
// openFileDialog_Skel
//
openFileDialog_Skel.AddExtension = false;
openFileDialog_Skel.AddToRecent = false;
openFileDialog_Skel.Filter = "skel 文件 (*.skel; *.json)|*.skel;*.json";
openFileDialog_Skel.Multiselect = true;
//
// label4
//
label4.AutoSize = true;
tableLayoutPanel1.SetColumnSpan(label4, 4);
label4.Dock = DockStyle.Fill;
label4.Location = new Point(15, 15);
label4.Margin = new Padding(15);
label4.Name = "label4";
label4.Size = new Size(996, 24);
label4.TabIndex = 14;
label4.Text = "说明批量导入只需要选择skel文件atlas文件需要在同目录下并且与skel文件名相同";
label4.TextAlign = ContentAlignment.MiddleCenter;
//
// BatchOpenSpineDialog
//
AcceptButton = button_Ok;
AutoScaleDimensions = new SizeF(11F, 24F);
AutoScaleMode = AutoScaleMode.Font;
CancelButton = button_Cancel;
ClientSize = new Size(1126, 449);
Controls.Add(panel);
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
Name = "BatchOpenSpineDialog";
ShowIcon = false;
ShowInTaskbar = false;
StartPosition = FormStartPosition.CenterScreen;
Text = "批量打开骨骼";
panel.ResumeLayout(false);
tableLayoutPanel1.ResumeLayout(false);
tableLayoutPanel1.PerformLayout();
tableLayoutPanel2.ResumeLayout(false);
ResumeLayout(false);
}
#endregion
private Panel panel;
private TableLayoutPanel tableLayoutPanel1;
private Label label_Tip;
private ListBox listBox_FilePath;
private Button button_SelectSkel;
private TableLayoutPanel tableLayoutPanel2;
private Button button_Ok;
private Button button_Cancel;
private Label label3;
private ComboBox comboBox_Version;
private OpenFileDialog openFileDialog_Skel;
private Label label4;
}
}

View File

@@ -1,4 +1,5 @@
using System;
using SpineViewer.Spine;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
@@ -8,13 +9,59 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SpineViewer.src
namespace SpineViewer
{
public partial class BatchOpenSpineDialog: Form
public partial class BatchOpenSpineDialog : Form
{
public string[] SkelPaths { get; private set; }
public Spine.Version Version { get; private set; }
public BatchOpenSpineDialog()
{
InitializeComponent();
comboBox_Version.DataSource = VersionHelper.Versions.ToList();
comboBox_Version.DisplayMember = "Value";
comboBox_Version.ValueMember = "Key";
comboBox_Version.SelectedValue = Spine.Version.V38;
}
private void button_SelectSkel_Click(object sender, EventArgs e)
{
if (openFileDialog_Skel.ShowDialog() == DialogResult.OK)
{
listBox_FilePath.Items.Clear();
foreach (var p in openFileDialog_Skel.FileNames)
listBox_FilePath.Items.Add(Path.GetFullPath(p));
label_Tip.Text = $"已选择 {listBox_FilePath.Items.Count} 个文件";
}
}
private void button_Ok_Click(object sender, EventArgs e)
{
if (listBox_FilePath.Items.Count <= 0)
{
MessageBox.Show("未选择任何文件", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
foreach (string p in listBox_FilePath.Items)
{
if (!File.Exists(p))
{
MessageBox.Show($"{p}", "skel文件不存在", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
}
SkelPaths = listBox_FilePath.Items.Cast<string>().ToArray();
Version = (Spine.Version)comboBox_Version.SelectedValue;
DialogResult = DialogResult.OK;
}
private void button_Cancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}

View File

@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
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
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>
@@ -26,36 +26,36 @@
<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
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
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
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
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
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
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
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@@ -117,4 +117,7 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="openFileDialog_Skel.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>92, 26</value>
</metadata>
</root>

View File

@@ -73,7 +73,7 @@ namespace SpineViewer.Spine
ImplementationTypes[attr.Version] = type;
}
}
Program.Logger.Debug($"Find Spine implementations: [{string.Join(", ", ImplementationTypes.Keys)}]");
Program.Logger.Debug("Find Spine implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
// 加载 FragmentShader
try

View File

@@ -42,20 +42,20 @@ namespace SpineViewer
index = spines.Count;
var dialog = new OpenSpineDialog();
if (dialog.ShowDialog() == DialogResult.OK)
if (dialog.ShowDialog() != DialogResult.OK)
return;
try
{
try
{
var spine = Spine.Spine.New(dialog.Version, dialog.SkelPath, dialog.AtlasPath);
spines.Insert(index, spine);
listView.Items.Insert(index, new ListViewItem([spine.Name, spine.Version.String()], -1) { ToolTipText = spine.SkelPath });
}
catch (Exception ex)
{
Program.Logger.Error(ex.ToString());
Program.Logger.Error($"Failed to load {dialog.SkelPath} {dialog.AtlasPath}");
MessageBox.Show(ex.ToString(), "骨骼加载失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
var spine = Spine.Spine.New(dialog.Version, dialog.SkelPath, dialog.AtlasPath);
spines.Insert(index, spine);
listView.Items.Insert(index, new ListViewItem([spine.Name, spine.Version.String()], -1) { ToolTipText = spine.SkelPath });
}
catch (Exception ex)
{
Program.Logger.Error(ex.ToString());
Program.Logger.Error("Failed to load {} {}", dialog.SkelPath, dialog.AtlasPath);
MessageBox.Show(ex.ToString(), "骨骼加载失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
@@ -72,7 +72,41 @@ namespace SpineViewer
/// </summary>
public void BatchAdd()
{
throw new NotImplementedException();
var dialog = new BatchOpenSpineDialog();
if (dialog.ShowDialog() != DialogResult.OK)
return;
int totalCount = dialog.SkelPaths.Length;
int errorCount = 0;
var version = dialog.Version;
for (int i = 0; i < totalCount; i++)
{
var skelPath = dialog.SkelPaths[i];
Program.Logger.Info("[{}/{}] loading {}", i + 1, totalCount, skelPath);
try
{
var spine = Spine.Spine.New(version, skelPath);
spines.Add(spine);
listView.Items.Add(new ListViewItem([spine.Name, spine.Version.String()], -1) { ToolTipText = spine.SkelPath });
}
catch (Exception ex)
{
Program.Logger.Error(ex.ToString());
Program.Logger.Error("Failed to load {}", skelPath);
errorCount++;
}
}
if (errorCount > 0)
{
Program.Logger.Warn("Batch load {} successfully, {} failed", totalCount - errorCount, errorCount);
MessageBox.Show($"{totalCount - errorCount}成功,{errorCount}失败", "部分骨骼加载失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
Program.Logger.Info("{} skel loaded successfully", totalCount);
}
}
private void listView_SelectedIndexChanged(object sender, EventArgs e)