#Time:2022/01/16
# Author:Xiaohong
#功能:Python 更改目录下 目录及文件的 顺序命名,并列出目录内容
# 项目的文件结构方式:
# 1. PyQt5 UI 文件: ChangeFileName.ui
# 2. PyQt5 UI 文件转换生成的 PY 文件: ChangeFileName_Ui.py
# 3. PyQt5 UI 文件对应的 Class 文件: ChangeFileName_Class.py
# 4. 通用的消息显示 文件(在ChangeFileName_Class.py 中被调用): FangMessage.py
# 5. 定制的TableWidget,支持拖拉操作(在ChangeFileName.ui被引用):
TableWidgetDragDropRows.py
# 6. 主文件(调用各种类): Tools_Main.py
效果图如下: 目录原始的文件名:
运行后的文件名(以0X 为前缀,顺序命名):
程式的运行界面:
源程式:ChangeFileName_Ui.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'd:\vscode_2020\QtTools\QtTools\ChangeFileName.ui'
#
# Created by: PyQt5 UI code generator 5.15.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ChangeFileName(object):
def setupUi(self, ChangeFileName):
ChangeFileName.setObjectName("ChangeFileName")
ChangeFileName.resize(689, 590)
self.pb_dirFilename = QtWidgets.QPushButton(ChangeFileName)
self.pb_dirFilename.setGeometry(QtCore.QRect(20, 40, 251, 23))
self.pb_dirFilename.setObjectName("pb_dirFilename")
self.tableWidget_file = TableWidgetDragDropRows(ChangeFileName)
self.tableWidget_file.setGeometry(QtCore.QRect(20, 90, 611, 451))
self.tableWidget_file.setObjectName("tableWidget_file")
self.tableWidget_file.setColumnCount(2)
self.tableWidget_file.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget_file.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget_file.setHorizontalHeaderItem(1, item)
self.pb_up = QtWidgets.QPushButton(ChangeFileName)
self.pb_up.setGeometry(QtCore.QRect(640, 100, 41, 201))
self.pb_up.setObjectName("pb_up")
self.pb_down = QtWidgets.QPushButton(ChangeFileName)
self.pb_down.setGeometry(QtCore.QRect(640, 330, 41, 211))
self.pb_down.setObjectName("pb_down")
self.pb_change = QtWidgets.QPushButton(ChangeFileName)
self.pb_change.setGeometry(QtCore.QRect(210, 550, 131, 23))
self.pb_change.setObjectName("pb_change")
self.pb_exit = QtWidgets.QPushButton(ChangeFileName)
self.pb_exit.setGeometry(QtCore.QRect(450, 550, 141, 23))
self.pb_exit.setObjectName("pb_exit")
self.label = QtWidgets.QLabel(ChangeFileName)
self.label.setGeometry(QtCore.QRect(220, 10, 251, 21))
font = QtGui.QFont()
font.setFamily("隶书")
font.setPointSize(16)
self.label.setFont(font)
self.label.setObjectName("label")
self.label_2 = QtWidgets.QLabel(ChangeFileName)
self.label_2.setGeometry(QtCore.QRect(20, 14, 121, 16))
self.label_2.setObjectName("label_2")
self.label_3 = QtWidgets.QLabel(ChangeFileName)
self.label_3.setGeometry(QtCore.QRect(580, 20, 101, 16))
self.label_3.setObjectName("label_3")
self.lineEdit_pre = QtWidgets.QLineEdit(ChangeFileName)
self.lineEdit_pre.setGeometry(QtCore.QRect(67, 548, 41, 20))
self.lineEdit_pre.setInputMethodHints(QtCore.Qt.ImhUppercaseOnly)
self.lineEdit_pre.setObjectName("lineEdit_pre")
self.label_4 = QtWidgets.QLabel(ChangeFileName)
self.label_4.setGeometry(QtCore.QRect(30, 550, 31, 16))
self.label_4.setObjectName("label_4")
self.spinBox_pre_len = QtWidgets.QSpinBox(ChangeFileName)
self.spinBox_pre_len.setGeometry(QtCore.QRect(150, 550, 42, 22))
self.spinBox_pre_len.setProperty("value", 4)
self.spinBox_pre_len.setObjectName("spinBox_pre_len")
self.label_5 = QtWidgets.QLabel(ChangeFileName)
self.label_5.setGeometry(QtCore.QRect(120, 550, 31, 16))
self.label_5.setObjectName("label_5")
self.lineEdit_dir_path = QtWidgets.QLineEdit(ChangeFileName)
self.lineEdit_dir_path.setGeometry(QtCore.QRect(20, 67, 491, 20))
self.lineEdit_dir_path.setStyleSheet("background-color: rgb(255, 170, 255);")
self.lineEdit_dir_path.setObjectName("lineEdit_dir_path")
self.pushButton_list = QtWidgets.QPushButton(ChangeFileName)
self.pushButton_list.setGeometry(QtCore.QRect(520, 65, 75, 23))
self.pushButton_list.setObjectName("pushButton_list")
self.retranslateUi(ChangeFileName)
self.pb_exit.clicked.connect(ChangeFileName.close)
QtCore.QMetaObject.connectSlotsByName(ChangeFileName)
def retranslateUi(self, ChangeFileName):
_translate = QtCore.QCoreApplication.translate
ChangeFileName.setWindowTitle(_translate("ChangeFileName", "Form"))
self.pb_dirFilename.setText(_translate("ChangeFileName", "选择要重命名的目录路径"))
item = self.tableWidget_file.horizontalHeaderItem(0)
item.setText(_translate("ChangeFileName", "文件名"))
item = self.tableWidget_file.horizontalHeaderItem(1)
item.setText(_translate("ChangeFileName", "文件夹或文件名"))
self.pb_up.setText(_translate("ChangeFileName", "Up"))
self.pb_down.setText(_translate("ChangeFileName", "Down"))
self.pb_change.setText(_translate("ChangeFileName", "更名"))
self.pb_exit.setText(_translate("ChangeFileName", "结束"))
self.label.setText(_translate("ChangeFileName", "重命名目录下的文件名"))
self.label_2.setText(_translate("ChangeFileName", "ChangeFileName_*.py"))
self.label_3.setText(_translate("ChangeFileName", "ver. 20220109_1"))
self.label_4.setText(_translate("ChangeFileName", "前缀"))
self.label_5.setText(_translate("ChangeFileName", "长度"))
self.pushButton_list.setText(_translate("ChangeFileName", "列出目录"))
from TableWidgetDragDropRows import TableWidgetDragDropRows
ChangeFileName_Class.py:
import sys, os
import datetime
import time
import traceback
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtWidgets import (
QApplication,
QMainWindow,
QDialog,
QSplashScreen,
QToolButton,
QToolTip,
QWidget,
QMessageBox,
QAction,
QFileDialog,
QPushButton,
)
from PyQt5.QtWidgets import (
QTableWidget,
QProgressBar,
QLineEdit,
QComboBox,
QFrame,
QTableWidgetItem,
QStatusBar,
)
from PyQt5.QtGui import (
QIntValidator,
QDoubleValidator,
QPixmap,
QRegExpValidator,
QColor,
QBrush,
QIcon,
)
from PyQt5.QtCore import QRegExp, QThread, QSize
from PyQt5.QtCore import QDate, QDateTime, QTime, QDir
import ChangeFileName_Ui as ChangeFileName
from FangMessage import FangMessage
# class FangMessage(QMessageBox):
# def __init__(self, parent=None):
# super(FangMessage, self).__init__(parent)
# def runY(self, Title, message, YMessage):
# self.setWindowTitle(Title)
# self.setText(message)
# self.addButton(QPushButton(YMessage), QMessageBox.YesRole)
# self.exec_()
# def runYN(self, Title, message, YMessage, NMessage):
# self.setWindowTitle(Title)
# self.setText(message)
# self.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
# buttonY = self.button(QMessageBox.Yes)
# buttonY.setText(YMessage)
# buttonN = self.button(QMessageBox.No)
# buttonN.setText(NMessage)
# self.exec_()
# if self.clickedButton() == buttonY:
# return 'Y'
# else:
# return 'N'
class ChangeFileName_class(QWidget, ChangeFileName.Ui_ChangeFileName):
def __init__(self, parent=None):
super().__init__()
self.child = ChangeFileName.Ui_ChangeFileName()
self.child.setupUi(self)
self.child.pb_dirFilename.clicked.connect(self.Choose_dir)
self.child.pb_up.clicked.connect(self.file_up)
self.child.pb_down.clicked.connect(self.file_down)
self.child.pb_change.clicked.connect(self.changeFilename)
self.child.pushButton_list.clicked.connect(self.list_comment)
# self.child.lineEdit_pre.set
self.SetTableWidgetHeaderWidth()
self.child.tableWidget_file.horizontalHeader().setStyleSheet(
"QHeaderView::section{background-color:lightblue;color: black;padding-left: 4px;border: 1px solid#6c6c6c;}"
)
self.child.tableWidget_file.verticalHeader().setHidden(False) # 垂直表头标签 关闭
def SetTableWidgetHeaderWidth(self):
HeaderLabels = ['Name', '文件夹或文件名']
# 设置列标签
self.child.tableWidget_file.setHorizontalHeaderLabels(HeaderLabels)
# 设置 表格为 整行选中
self.child.tableWidget_file.setSelectionBehavior(
QtWidgets.QAbstractItemView.SelectRows
)
# 设置 表格为 根据内容自适应 的伸缩模式
self.child.tableWidget_file.horizontalHeader().setSectionResizeMode(
# QtWidgets.QHeaderView.Stretch
QtWidgets.QHeaderView.ResizeToContents
)
self.child.tableWidget_file.setDragEnabled(True)
self.child.tableWidget_file.setAcceptDrops(True)
# self.child.tableWidget_file.horizontalHeader().setSectionResizeMode(
# QtWidgets.QHeaderView.ResizeToContents
# )
# 设置 表格为 禁止编辑
# self.child.tableWidget_file.setEditTriggers(
# QtWidgets.QAbstractItemView.NoEditTriggers
# )
def Choose_dir(self):
pass
dir_choose = QFileDialog.getExistingDirectory(self, '选择要重命名的文件夹')
print(dir_choose)
self.child.lineEdit_dir_path.setText(dir_choose)
self.child.lineEdit_dir_path.setReadOnly(True)
data_row = []
dirs = os.listdir(dir_choose)
for dir in dirs:
data_col = []
if os.path.isdir(dir_choose + '\\' + dir) == False: # 代表是文件
data_col.append('文件')
if os.path.isdir(dir_choose + '\\' + dir) == True: # 代表是文件夹
data_col.append('文件夹')
data_col.append(dir)
data_row.append(data_col)
# print(data_row)
self.ListFileName(data_row)
def ListFileName(self, data_row):
try:
dataResult = data_row
rowCount = len(dataResult)
self.child.tableWidget_file.setRowCount(rowCount)
for rowIndex in range(len(dataResult)):
newItem = QtWidgets.QTableWidgetItem(str(dataResult[rowIndex][0]))
newItem.setTextAlignment(QtCore.Qt.AlignLeft) # 居中
if str(dataResult[rowIndex][0]) == '文件夹':
newItem.setForeground(QBrush(QColor(255, 0, 0)))
self.child.tableWidget_file.setItem(rowIndex, 0, newItem)
newItem = QtWidgets.QTableWidgetItem(str(dataResult[rowIndex][1]))
newItem.setTextAlignment(QtCore.Qt.AlignLeft) # 居中
self.child.tableWidget_file.setItem(rowIndex, 1, newItem)
except:
traceback.print_exc()
def file_up(self):
pass
# print('Cur Row:')
v_cur_row = self.child.tableWidget_file.currentRow()
# print(v_cur_row)
if v_cur_row == 0: # 代表已经是第一行
pass
else:
v_curr_row_value = []
v_up_row_value = []
v_curr_row_value.append(
self.child.tableWidget_file.item(v_cur_row, 0).text()
)
v_curr_row_value.append(
self.child.tableWidget_file.item(v_cur_row, 1).text()
)
v_up_row_value.append(
self.child.tableWidget_file.item(v_cur_row - 1, 0).text()
)
v_up_row_value.append(
self.child.tableWidget_file.item(v_cur_row - 1, 1).text()
)
# print(v_up_row_value)
# print(v_curr_row_value)
# 向上写一行纪录
newItem = QtWidgets.QTableWidgetItem(str(v_curr_row_value[0]))
newItem.setTextAlignment(QtCore.Qt.AlignLeft) # 居中
if str(v_curr_row_value[0]) == '文件夹':
newItem.setForeground(QBrush(QColor(255, 0, 0)))
self.child.tableWidget_file.setItem(v_cur_row - 1, 0, newItem)
newItem = QtWidgets.QTableWidgetItem(str(v_curr_row_value[1]))
newItem.setTextAlignment(QtCore.Qt.AlignLeft) # 居中
self.child.tableWidget_file.setItem(v_cur_row - 1, 1, newItem)
# 向下写一行纪录
newItem = QtWidgets.QTableWidgetItem(str(v_up_row_value[0]))
newItem.setTextAlignment(QtCore.Qt.AlignLeft) # 居中
if str(v_up_row_value[0]) == '文件夹':
newItem.setForeground(QBrush(QColor(255, 0, 0)))
self.child.tableWidget_file.setItem(v_cur_row, 0, newItem)
newItem = QtWidgets.QTableWidgetItem(str(v_up_row_value[1]))
newItem.setTextAlignment(QtCore.Qt.AlignLeft) # 居中
self.child.tableWidget_file.setItem(v_cur_row, 1, newItem)
# 选中上一行
self.child.tableWidget_file.selectRow(v_cur_row - 1)
# 向下移动
def file_down(self):
pass
print('Cur Row:')
v_cur_row = self.child.tableWidget_file.currentRow()
v_row_count = self.child.tableWidget_file.rowCount()
# print(v_row_count)
if v_cur_row == v_row_count - 1: # 代表已经是最后一行
pass
else:
v_curr_row_value = []
v_down_row_value = []
v_curr_row_value.append(
self.child.tableWidget_file.item(v_cur_row, 0).text()
)
v_curr_row_value.append(
self.child.tableWidget_file.item(v_cur_row, 1).text()
)
v_down_row_value.append(
self.child.tableWidget_file.item(v_cur_row + 1, 0).text()
)
v_down_row_value.append(
self.child.tableWidget_file.item(v_cur_row + 1, 1).text()
)
# print(v_down_row_value)
# print(v_curr_row_value)
# 向下写一行纪录
newItem = QtWidgets.QTableWidgetItem(str(v_curr_row_value[0]))
newItem.setTextAlignment(QtCore.Qt.AlignLeft) # 居中
if str(v_curr_row_value[0]) == '文件夹':
newItem.setForeground(QBrush(QColor(255, 0, 0)))
self.child.tableWidget_file.setItem(v_cur_row + 1, 0, newItem)
newItem = QtWidgets.QTableWidgetItem(str(v_curr_row_value[1]))
newItem.setTextAlignment(QtCore.Qt.AlignLeft) # 居中
self.child.tableWidget_file.setItem(v_cur_row + 1, 1, newItem)
# 向上写一行纪录
newItem = QtWidgets.QTableWidgetItem(str(v_down_row_value[0]))
newItem.setTextAlignment(QtCore.Qt.AlignLeft) # 居中
if str(v_down_row_value[0]) == '文件夹':
newItem.setForeground(QBrush(QColor(255, 0, 0)))
self.child.tableWidget_file.setItem(v_cur_row, 0, newItem)
newItem = QtWidgets.QTableWidgetItem(str(v_down_row_value[1]))
newItem.setTextAlignment(QtCore.Qt.AlignLeft) # 居中
self.child.tableWidget_file.setItem(v_cur_row, 1, newItem)
# 选中下一行
self.child.tableWidget_file.selectRow(v_cur_row + 1)
def changeFilename(self):
import os
v_dir = self.child.lineEdit_dir_path.text()
v_pre = self.child.lineEdit_pre.text()
v_pre_len = int(self.child.spinBox_pre_len.text())
if len(v_dir) == 0:
FangMessage1 = FangMessage()
FangMessage1.runY('错误', "没有选中目录", '我再检查')
# QMessageBox.warning(self, "警告", "没有选中目录")
return
if v_pre_len < 2:
FangMessage1 = FangMessage()
FangMessage1.runY('错误', "前缀长度不能小于2", '我再检查')
# QMessageBox.warning(self, "警告", "前缀长度不能小于2")
return
if v_pre_len <= len(v_pre):
FangMessage1 = FangMessage()
FangMessage1.runY('错误', "前缀" + v_pre + '的长度大于设定的前缀长度', '我再检查')
# QMessageBox.warning(self, "警告", "前缀" + v_pre + '的长度大于设定的前缀长度')
return
if len(v_pre) == 0:
FangMessage1 = FangMessage()
FangMessage1.runYN('错误', "前缀没有填入,将全部以流水号填充,是否继续?", '我再检查', '我已了解,继续重命名')
# QMessageBox.warning(self, "警告", "前缀没有填入,将全部以流水号填充,是否继续?")
# 开始重命名
# 先取得tableWidget_file 的纪录数
v_row_cnt = self.child.tableWidget_file.rowCount()
print(v_row_cnt)
for i in range(0, v_row_cnt):
try:
# 拼写 前缀 字母
v_pre_tmp = v_pre + str((i + 1)).zfill(v_pre_len - len(v_pre)) + "_"
# print(v_pre_tmp)
# 取得 tableWidget_file 内的 文件夹 或文件名
v_name_tmp = self.child.tableWidget_file.item(i, 1).text()
v_name_org = v_dir + "\\" + v_name_tmp
v_name_now = v_dir + "\\" + v_pre_tmp + v_name_tmp
# print("1:"+v_name_org)
# print("2:"+v_name_now)
os.rename(v_name_org, v_name_now)
except:
traceback.print_exc()
self.child.lineEdit_dir_path.setText("")
self.child.lineEdit_pre.setText("")
FangMessage1 = FangMessage()
FangMessage1.runY('成功', '成功的 重命名目录及文件', 'OK')
def list_comment(self):
# 列出目录下的内容
v_dir = self.child.lineEdit_dir_path.text()
if len(v_dir) == 0:
FangMessage1 = FangMessage()
FangMessage1.runY('错误', "没有选中目录", '我再检查')
return
dirs = os.listdir(v_dir)
path1, dir = os.path.split(v_dir)
now = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))
print(now)
# 生成文本文件
txt_name = v_dir + '\\' + dir + now + '的内容.txt'
with open(txt_name, 'w') as f1:
f1.write(now)
f1.write('\n')
for dir in dirs:
f1.write(dir)
f1.write('\n')
f1.write('=============================')
FangMessage1 = FangMessage()
FangMessage1.runY('成功', '成功的 列出目录下的内容', 'OK')
FangMessage.py
from PyQt5.QtWidgets import (
QApplication,
QMainWindow,
QDialog,
QSplashScreen,
QToolButton,
QToolTip,
QWidget,
QMessageBox,
QAction,
QFileDialog,
QPushButton,
)
# 自定义消息框, 引用方法
# FangMessage1=FangMessage()
# FangMessage1.runY('错误','汇率不能为空','我再补入')
# if FangMessage1.runYN('警告',"是否要删除 {} 月份的汇率".format(v_yyyymm),'我要删除','误操作,不删除')=='Y':
class FangMessage(QMessageBox):
def __init__(self, parent=None):
super(FangMessage, self).__init__(parent)
def runY(self, Title, message, YMessage):
self.setWindowTitle(Title)
self.setText(message)
self.addButton(QPushButton(YMessage), QMessageBox.YesRole)
self.exec_()
def runYN(self, Title, message, YMessage, NMessage):
self.setWindowTitle(Title)
self.setText(message)
self.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
buttonY = self.button(QMessageBox.Yes)
buttonY.setText(YMessage)
buttonN = self.button(QMessageBox.No)
buttonN.setText(NMessage)
self.exec_()
if self.clickedButton() == buttonY:
return 'Y'
else:
return 'N'
TableWidgetDragDropRows.py
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import (
QTableWidget,
QProgressBar,
QLineEdit,
QComboBox,
QFrame,
QTableWidgetItem,
QStatusBar,
QAbstractItemView,
)
class TableWidgetDragDropRows(QTableWidget):
'''TableWidgetDragDropRows
支持在各个QTableWidget之间拖放行的QTableWidget自定义扩展类
Extends:
QTableWidget
'''
def __init__(self, parent):
super().__init__(parent)
self.setDragEnabled(True)
self.setAcceptDrops(True)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection)
self.setDragDropOverwriteMode(False)
self.last_drop_row = None
def dropMimeData(self, row, col, mimeData, action):
'''dropMimeData
复写此方法以获取要插入的行的索引
Arguments:
row {int} -- 所在行的索引
col {int} -- 所在列的索引
mimeData {str} -- mimeData
action {str} -- action
Returns:
bool -- 操作成功与否
'''
self.last_drop_row = row
return True
def dropEvent(self, event):
'''dropEvent
拖放的放事件
Arguments:
event {object} -- 事件对象
'''
# 将从中移动所选行的QTableWidget
sender = event.source()
# 默认dropEvent方法触发带有参数的dropMimeData(我们感兴趣的是行索引)。
super().dropEvent(event)
# 现在我们直到要在哪里插入所选的行了
dropRow = self.last_drop_row
selectedRows = sender.getselectedRowsFast()
# 在目标 TableWidget 的插入行中 分配 接收 所需的空间
for _ in selectedRows:
self.insertRow(dropRow)
# 如果发送者和接收者是同一个,那么,在创建新的空行之后,所选的行可能会更改它们的位置
# 0 代表不变动位置, 条件是: a. 从另一个 TableWidget 控件 转移过来 b. 在同一个空间,但是从上方 拉到 下方
sel_rows_offsets = [
0 if self != sender or srow < dropRow else len(selectedRows)
for srow in selectedRows
]
selectedRows = [
row + offset for row, offset in zip(selectedRows, sel_rows_offsets)
]
# print(selectedRows)
# 复制所选的行的内容到空行中
for i, srow in enumerate(selectedRows):
for j in range(self.columnCount()):
item = sender.item(srow, j)
if item:
source = QTableWidgetItem(item)
self.setItem(dropRow + i, j, source)
# 删除所选的行
for srow in reversed(selectedRows):
sender.removeRow(srow)
event.accept()
# 检查哪几行被选中,并拖拉
def getselectedRowsFast(self):
selectedRows = []
for item in self.selectedItems():
# print(item.row())
if item.row() not in selectedRows:
selectedRows.append(item.row())
selectedRows.sort()
return selectedRows