🐶
PowerShellでドラッグアンドドロップしたい
おっさんは引数指定メンドクセーんですよ
ってわけでとりあえずドラッグアンドドロップ用GUIの実装を簡単にしましょー
うん、つまりよくあるコレっすわ
本題
20250103 実は今日誤爆して前の投稿にコレぶっ込んだんだが、きっとバレてねえハズだっ
20250113 親ウィンドウを取ろうとする無駄な努力を止めて普通にZオーダー先頭に移動に
引数 | 説明 |
---|---|
Title | タイトルです |
Message | メッセージです 改行できます |
FileFilter | D&D可能なファイル名です 拡張子だけって意外に使いづらいんで正規表現でファイル名全体をマッチします |
FileList | 初期リストです args突っ込んでやればバッチ起動時のファイルリストをD&Dしたことにできます |
function ShowFileListDialog {
param (
[Parameter(Mandatory = $true)] [string] $Title,
[Parameter(Mandatory = $true)] [string] $Message,
[Parameter(Mandatory = $false)] [string] $FileFilter = ".*",
[Parameter(Mandatory = $false)] [string[]] $FileList
)
begin {}
process {
# フォーム生成
$frmMain = New-Object System.Windows.Forms.Form -Property @{
Text = $Title # タイトル
StartPosition = 'CenterScreen' # 表示位置
Size = New-Object System.Drawing.Size(480,320)
Padding = New-Object System.Windows.Forms.Padding(5)
}
$tlpMain = New-Object System.Windows.Forms.TableLayoutPanel -Property @{
Dock = [System.Windows.Forms.DockStyle]::Fill
RowCount = 2
}
$pnlBody = New-Object System.Windows.Forms.Panel -Property @{
Dock = [System.Windows.Forms.DockStyle]::Fill
}
$lblDD = New-Object System.Windows.Forms.Label -Property @{
Dock = [System.Windows.Forms.DockStyle]::Top
Text = $Message
AutoSize = $true
TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
}
$lbxDD = New-Object System.Windows.Forms.ListBox -Property @{
Dock = [System.Windows.Forms.DockStyle]::Fill
AllowDrop = $true
}
$pnlTail = New-Object System.Windows.Forms.Panel -Property @{
Dock = [System.Windows.Forms.DockStyle]::Fill
}
$btnOK = New-Object System.Windows.Forms.Button -Property @{
Dock = [System.Windows.Forms.DockStyle]::Right
Size = New-Object System.Drawing.Size(128, 0) # ボタン巾のみ指定可能
Text = "OK"
UseVisualStyleBackColor = $true
DialogResult = [Windows.Forms.DialogResult]::OK
}
$btnCancel = New-Object System.Windows.Forms.Button -Property @{
Dock = [System.Windows.Forms.DockStyle]::Right
Size = New-Object System.Drawing.Size(128, 0) # ボタン巾のみ指定可能
Text = "Cancel"
UseVisualStyleBackColor = $true
DialogResult = [Windows.Forms.DialogResult]::Cancel
}
$null = $pnlBody.Controls.Add($lbxDD)
$null = $pnlBody.Controls.Add($lblDD)
$null = $pnlTail.Controls.Add($btnOK)
$null = $pnlTail.Controls.Add($btnCancel)
$null = $tlpMain.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100)))
$null = $tlpMain.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 50))) # ボタン高さはコレ
$null = $tlpMain.Controls.Add($pnlBody, 0, 0)
$null = $tlpMain.Controls.Add($pnlTail, 0, 1)
$null = $frmMain.Controls.Add($tlpMain)
$null = $frmMain.Add_Load({
$frmMain.BringToFront()
})
$null = $lbxDD.Add_DragEnter({
$_.Effect = "All"
})
$null = $lbxDD.Add_DragDrop({
AddFileList $lbxDD $_.Data.GetData("FileDrop") $FileFilter
})
$null = $lbxDD.Add_KeyDown({
if ($_.KeyCode -eq "Delete") {
[array]::Reverse($lbxDD.SelectedIndices) | ForEach-Object {
[void]$lbxDD.Items.RemoveAt($_)
}
}
})
# フォーム表示
if ($null -ne $FileList) {
AddFileList $lbxDD $FileList $FileFilter
}
$frmMain.AcceptButton = $btnOK
$frmMain.CancelButton = $btnCancel
$null = $frmMain.ShowDialog()
return @($frmMain.DialogResult, $lbxDD.Items)
}
end {}
}
# FileListDialog用ファイルリスト生成
function local:AddFileList([System.Windows.Forms.ListBox] $ListBox, [string[]] $FilePaths, [string] $FileFilter) {
foreach ($FilePath in $FilePaths) {
if (Test-Path -LiteralPath $FilePath) {
if ([System.IO.Directory]::Exists($FilePath)) {
$ChildFilePaths = @()
@(Get-ChildItem -LiteralPath $FilePath -File -Recurse) | ForEach-Object {
$ChildFilePaths += $_.FullName
}
AddFileList $ListBox $ChildFilePaths $FileFilter
} else {
if ([System.IO.Path]::GetFileName($FilePath) -match $FileFilter) {
if ($ListBox.Items -notcontains $FilePath) {
[void]$ListBox.Items.Add($FilePath)
}
}
}
}
}
}
使い方
引数全部が入力ファイルとかゆー状況ならこんな感じにすればいいんじゃなかろーか
※バッチ経由でPowerShell呼ぶとかなら結構ある状況のハズ
機能としてリストしたものの対象から削除したい場合はDelキーで消せるとか
フォルダぶっ込んだら再帰的にファイル名を登録とかも用意してあります
一応だけど-FileListは初期リストで-FileFilterはファイル名への正規表現ね?
$ret = ShowFileListDialog `
-Title "タイトル" `
-Message "対象ファイルをドラッグ&ドロップしてください" `
-FileList $args `
-FileFilter "\.(txt)$"
if ($ret[0] -eq "OK") {
foreach($elm in $ret[1]) {
# なんか処理
}
}
蛇足
コレだけだとアレなのでちょっとした実行オプションをつけたやつも用意
現実的にはコッチのほうが使うだろーなぁきっと
引数 | 説明 |
---|---|
Title | タイトルです |
Message | メッセージです 改行できます |
FileFilter | D&D可能なファイル名です 拡張子だけって意外に使いづらいんで正規表現でファイル名全体をマッチします |
FileList | 初期リストです args突っ込んでやればバッチ起動時のファイルリストをD&Dしたことにできます |
Options | オプションです ほんの少しだけ違う挙動を組み込みたい時用のアレ |
function ShowFileListDialogWithOption {
param (
[Parameter(Mandatory = $true)] [string] $Title,
[Parameter(Mandatory = $true)] [string] $Message,
[Parameter(Mandatory = $false)] [string] $FileFilter = ".*",
[Parameter(Mandatory = $false)] [string[]] $FileList,
[Parameter(Mandatory = $false)] [string[]] $Options
)
begin {}
process {
# フォーム生成
$frmMain = New-Object System.Windows.Forms.Form -Property @{
Text = $Title # タイトル
StartPosition = 'CenterScreen' # 表示位置
Size = New-Object System.Drawing.Size(480,320)
Padding = New-Object System.Windows.Forms.Padding(5)
}
$tlpMain = New-Object System.Windows.Forms.TableLayoutPanel -Property @{
Dock = [System.Windows.Forms.DockStyle]::Fill
RowCount = 2
}
$pnlBody = New-Object System.Windows.Forms.Panel -Property @{
Dock = [System.Windows.Forms.DockStyle]::Fill
}
$lblDD = New-Object System.Windows.Forms.Label -Property @{
Dock = [System.Windows.Forms.DockStyle]::Top
Text = $Message
AutoSize = $true
TextAlign = [System.Drawing.ContentAlignment]::MiddleLeft
}
$lbxDD = New-Object System.Windows.Forms.ListBox -Property @{
Dock = [System.Windows.Forms.DockStyle]::Fill
AllowDrop = $true
}
$grpOpt = New-Object System.Windows.Forms.GroupBox -Property @{
Dock = [System.Windows.Forms.DockStyle]::Right
Text = "Options"
AutoSize = $true
Padding = New-Object System.Windows.Forms.Padding(5)
}
$flpOpt = New-Object System.Windows.Forms.FlowLayoutPanel -Property @{
Dock = [System.Windows.Forms.DockStyle]::Fill
AutoSize = $true
FlowDirection = [System.Windows.Forms.FlowDirection]::TopDown
}
$Checked = $true
$Options | ForEach-Object {
$rdoOpt = New-Object System.Windows.Forms.RadioButton -Property @{
Text = $_
Checked = $Checked
AutoSize = $true
}
$flpOpt.Controls.Add($rdoOpt)
$Checked = $false
}
$pnlTail = New-Object System.Windows.Forms.Panel -Property @{
Dock = [System.Windows.Forms.DockStyle]::Fill
}
$btnOK = New-Object System.Windows.Forms.Button -Property @{
Dock = [System.Windows.Forms.DockStyle]::Right
Size = New-Object System.Drawing.Size(128, 0) # ボタン巾のみ指定可能
Text = "OK"
UseVisualStyleBackColor = $true
DialogResult = [Windows.Forms.DialogResult]::OK
}
$btnCancel = New-Object System.Windows.Forms.Button -Property @{
Dock = [System.Windows.Forms.DockStyle]::Right
Size = New-Object System.Drawing.Size(128, 0) # ボタン巾のみ指定可能
Text = "Cancel"
UseVisualStyleBackColor = $true
DialogResult = [Windows.Forms.DialogResult]::Cancel
}
$null = $pnlBody.Controls.Add($lbxDD)
$null = $pnlBody.Controls.Add($lblDD)
$null = $pnlBody.Controls.Add($grpOpt)
$null = $grpOpt.Controls.Add($flpOpt)
$null = $pnlTail.Controls.Add($btnOK)
$null = $pnlTail.Controls.Add($btnCancel)
$null = $tlpMain.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100)))
$null = $tlpMain.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 50))) # ボタン高さはコレ
$null = $tlpMain.Controls.Add($pnlBody, 0, 0)
$null = $tlpMain.Controls.Add($pnlTail, 0, 1)
$null = $frmMain.Controls.Add($tlpMain)
$null = $frmMain.Add_Load({
$frmMain.BringToFront()
})
$null = $lbxDD.Add_DragEnter({
$_.Effect = "All"
})
$null = $lbxDD.Add_DragDrop({
AddFileList $lbxDD $_.Data.GetData("FileDrop") $FileFilter
})
$null = $lbxDD.Add_KeyDown({
if ($_.KeyCode -eq "Delete") {
[array]::Reverse($lbxDD.SelectedIndices) | ForEach-Object {
[void]$lbxDD.Items.RemoveAt($_)
}
}
})
# フォーム表示
if ($null -ne $FileList) {
$null = AddFileList $lbxDD $FileList $FileFilter
}
$frmMain.AcceptButton = $btnOK
$frmMain.CancelButton = $btnCancel
$null = $frmMain.ShowDialog()
return @($frmMain.DialogResult, $lbxDD.Items, ($flpOpt.Controls | Where-Object {$_.Checked -eq $true} | Select-Object -ExpandProperty Text))
}
end {}
}
こいつの呼び出しは一応こんな感じ
$ret = ShowFileListDialog `
-Title "タイトル" `
-Message "対象ファイルをドラッグ&ドロップしてください" `
-FileList $args `
-FileFilter "\.(txt)$" `
-Options @("aaa","bbb")
if ($ret[0] -eq "OK") {
foreach($elm in $ret[1]) {
$ret[2] # 選択したオプションの文字列
}
}
Discussion