夜雨聆风学习资料网

ARTICLE · 1149482

《Excel 同一单元格塞多图,还在一张张手动拖?这款Python原创工具,一键搞定超省心》

《Excel 同一单元格塞多图,还在一张张手动拖?这款Python原创工具,一键搞定超省心》

“带你横跨办公自动化的数据江海”

@摸鱼

前言

关于摸鱼

(

ABOUT MOYU

)

闻道有先后,术业有专攻。

各位大佬朋友们好!

~我依旧是你们的老朋友摸鱼~

在职场摸爬滚打的这十多年里,我用Python悄悄干了不少“正事”——不知不觉攒下了一整套办公自动化的实用项目技巧。自2025年10月初创立了公众号 「码海听潮」 ,初衷很简单:把重复的劳动交给代码,把摸鱼的时间留给生活。

目前已经吭哧吭哧更新了近170篇原创文章,每一篇都是实操干货,不讲虚的,只聊怎么用代码真正解放双手,帮大家早点下班、准点摸鱼!

好了,多了不说,少了不唠,今天给大佬们分享一款本人原创的【Excel一个单元格插入多张图片工具】。经常做资料整理、图片归档Excel中的朋友,大概都遇到过类似的麻烦:一般表格插图都是一格一张,可实际工作中图片往往有多张,数量还不确定,一格一张太占列,表格既不好看也不好查。要是能把所有图片都塞进一个单元格,就能省下大量空间。但手动一张张插入实在太折腾——找图、调尺寸、排整齐,一个单元格就得花上好几分钟,几百上千张更是噩梦。

今天这款工具,正是为了解决这份尴尬。它能自动识别添加的图片,读取 Excel 当前选区或手动指定单元格,支持横向 / 纵向排列、自适应或固定尺寸、自定义间距、自动调整行高列宽,还能跳过已有图片的格子,逐格按数量分配插入,多出的图片也会提示未使用,方便后续做资料整理和表格美化。

《该办公工具成品展示:》

《该办公工具操作演示视频:》

关注
重播 分享 赞

《该办公工具核心功能亮点:》

01

 亮点一:一格多图,节省空间

        • 支持在同一个单元格内插入多张图片,横向 / 纵向自动排列,不再一图占一列,表格更紧凑、更美观、更好查阅。

        02

         亮点二:多种排列与尺寸模式

            • 支持横向排列、纵向排列;支持按单元格自适应,也支持固定尺寸;固定模式下还可设置图片间距、保持宽高比,灵活适配不同表格需求。

            03

            亮点三:智能适配单元格

            • 可读取 Excel 当前选区,也可手动指定目标单元格;固定模式下支持自动调整行高列宽,让图片刚好容纳、不留多余空隙。

            《该办公工具代码展示:》

            下面,我就奉上python代码让各位大佬见识一下,什么叫"传统文化"遇上"赛博效率"

             import sysfrom PyQt6.QtWidgets import (    QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton,    QLabel, QListWidget, QListWidgetItem, QFileDialog, QComboBox,    QMessageBox, QTableWidget, QTableWidgetItem, QHeaderView,    QProgressBar, QAbstractItemView, QGroupBox,    QSpinBox, QDoubleSpinBox, QCheckBox, QSizePolicy)from PyQt6.QtCore import Qt# ---------- 主窗口 ----------class MainWindow(QWidget):    def __init__(self):        super().__init__()        self.setWindowTitle("Excel同一个单元格插入多张图片 (欢迎关注微信公众号:码海听潮)")        self.setFixedSize(750, 650)        self.file_paths = []        self.worker = None        self._active_sheet_name = None        self._build_ui()    def _build_ui(self):        root = QVBoxLayout(self)        root.setSpacing(8)        root.setContentsMargins(10, 10, 10, 10)        # ---- 1. 图片选择 ----        root.addWidget(QLabel("<b>1. 选择图片(按文件名自然排序)</b>"))        row1 = QHBoxLayout()        self.btn_add = QPushButton("添加图片…")        self.btn_clear = QPushButton("清空")        self.btn_add.clicked.connect(self.on_add_files)        self.btn_clear.clicked.connect(self.on_clear_files)        row1.addWidget(self.btn_add)        row1.addWidget(self.btn_clear)        row1.addStretch()        root.addLayout(row1)        self.list_files = QListWidget()        self.list_files.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)        self.list_files.setMaximumHeight(110)        root.addWidget(self.list_files)        # ---- 2. 排列方向 + 尺寸 ----        box_layout = QGroupBox("2. 排列方式与尺寸")        v2 = QVBoxLayout(box_layout)        v2.setSpacing(6)        row_dir = QHBoxLayout()        row_dir.addWidget(QLabel("排列方向:"))        self.cmb_orientation = QComboBox()        self.cmb_orientation.addItem("横向排列 (H)", "horizontal")        self.cmb_orientation.addItem("纵向排列 (V)", "vertical")        row_dir.addWidget(self.cmb_orientation)        row_dir.addStretch()        v2.addLayout(row_dir)        row_size = QHBoxLayout()        row_size.addWidget(QLabel("尺寸模式:"))        self.cmb_size_mode = QComboBox()        self.cmb_size_mode.addItem("按单元格自适应", "auto")        self.cmb_size_mode.addItem("固定尺寸", "fixed")        row_size.addWidget(self.cmb_size_mode)        row_size.addStretch()        v2.addLayout(row_size)        # 固定尺寸参数容器:固定高度策略,显隐不挤压上下间距        self.fixed_widget = QWidget()        self.fixed_widget.setSizePolicy(            QSizePolicy.Policy.Preferred,            QSizePolicy.Policy.Fixed        )        v_fixed = QVBoxLayout(self.fixed_widget)        v_fixed.setContentsMargins(0, 0, 0, 0)        v_fixed.setSpacing(6)        row_fixed = QHBoxLayout()        row_fixed.addWidget(QLabel("   宽 (px):"))        self.sp_w = QSpinBox()        self.sp_w.setRange(0, 5000)        self.sp_w.setValue(120)        row_fixed.addWidget(self.sp_w)        row_fixed.addWidget(QLabel("高 (px):"))        self.sp_h = QSpinBox()        self.sp_h.setRange(0, 5000)        self.sp_h.setValue(120)        row_fixed.addWidget(self.sp_h)        row_fixed.addStretch()        v_fixed.addLayout(row_fixed)        row_opts = QHBoxLayout()        self.chk_keep_ratio = QCheckBox("保持宽高比(只填一边时生效)")        self.chk_keep_ratio.setChecked(False)        row_opts.addWidget(self.chk_keep_ratio)        row_opts.addWidget(QLabel("  间距(磅):"))        self.sp_gap = QDoubleSpinBox()        self.sp_gap.setRange(0.0, 50.0)        self.sp_gap.setSingleStep(0.5)        self.sp_gap.setValue(2.0)        row_opts.addWidget(self.sp_gap)        row_opts.addStretch()        v_fixed.addLayout(row_opts)        row_adjust = QHBoxLayout()        self.chk_row = QCheckBox("自动调整行高")        self.chk_col = QCheckBox("自动调整列宽")        self.chk_row.setChecked(True)        self.chk_col.setChecked(True)        row_adjust.addWidget(self.chk_row)        row_adjust.addWidget(self.chk_col)        row_adjust.addStretch()        v_fixed.addLayout(row_adjust)        v2.addWidget(self.fixed_widget)        self.cmb_size_mode.currentIndexChanged.connect(self._on_size_mode_change)        self._on_size_mode_change()        root.addWidget(box_layout)        # ---- 3. 单元格配置 ----        root.addWidget(QLabel("<b>3. 目标单元格与每格图片数量(已有的格子会自动跳过)</b>"))        row3 = QHBoxLayout()        self.btn_get_selection = QPushButton("读取 Excel 当前选区")        self.btn_get_selection.clicked.connect(self.on_read_selection)        self.btn_add_row = QPushButton("手动添加一行")        self.btn_add_row.clicked.connect(lambda: self._append_row("", ""))        self.btn_del_row = QPushButton("删除选中行")        self.btn_del_row.clicked.connect(self.on_del_row)        row3.addWidget(self.btn_get_selection)        row3.addWidget(self.btn_add_row)        row3.addWidget(self.btn_del_row)        row3.addStretch()        root.addLayout(row3)        self.table = QTableWidget(0, 2)        self.table.setHorizontalHeaderLabels(["单元格 (如 A1)", "该格图片数量"])        h = self.table.horizontalHeader()        h.setSectionResizeMode(0, QHeaderView.ResizeMode.Interactive)        h.setSectionResizeMode(1, QHeaderView.ResizeMode.Interactive)        h.setStretchLastSection(False)        self.table.setColumnWidth(0, 550)        self.table.setColumnWidth(1, 200)        self.table.setMinimumHeight(120)        self.table.setMaximumHeight(200)        root.addWidget(self.table, stretch=0)        # ---- 4. 执行 ----        self.progress = QProgressBar()        self.progress.setValue(0)        root.addWidget(self.progress)        row4 = QHBoxLayout()        self.btn_run = QPushButton("开始插入")        self.btn_run.setStyleSheet("font-weight:bold; padding:6px 16px;")        self.btn_run.clicked.connect(self.on_run)        row4.addStretch()        row4.addWidget(self.btn_run)        row4.addStretch()        root.addLayout(row4)        root.addStretch(1)    def _on_size_mode_change(self):        fixed = self.cmb_size_mode.currentData() == "fixed"        self.fixed_widget.setVisible(fixed)    @staticmethod    def _get_address(cell):        try:            addr = cell.Address            if callable(addr):                return addr(False, False)            else:                return str(addr).replace("$", "")        except Exception:            return ""    def on_add_files(self):        files, _ = QFileDialog.getOpenFileNames(            self, "选择图片", "",            "图片文件 (*.jpg *.jpeg *.png *.gif *.bmp *.tif *.tiff *.webp);;所有文件 (*.*)"        )        if not files:            return        all_paths = list({*self.file_paths, *files})        self.file_paths = natural_sort(all_paths)        self._refresh_list()    def on_clear_files(self):        self.file_paths = []        self._refresh_list()    def _refresh_list(self):        self.list_files.clear()        for p in self.file_paths:            self.list_files.addItem(QListWidgetItem(p))    def on_read_selection(self):        pass    def on_del_row(self):        rows = sorted({i.row() for i in self.table.selectedIndexes()}, reverse=True)        for r in rows:            self.table.removeRow(r)    def _append_row(self, addr, count):        r = self.table.rowCount()        self.table.insertRow(r)        self.table.setItem(r, 0, QTableWidgetItem(str(addr)))        self.table.setItem(r, 1, QTableWidgetItem(str(count)))    def on_run(self):        passdef main():    app = QApplication(sys.argv)    w = MainWindow()    w.show()    sys.exit(app.exec())if __name__ == "__main__":    main()

            这款「Excel同一个单元格插入多张图片工具」,可自动完成原需手动找图、逐张调尺寸、逐格对位、反复拖拽排列、再一张张检查是否漏插错序的一整天归档工作。从面对几百上千张图片、一格要塞多张、逐张点开、反复核对的繁琐与崩溃,到只需添加图片、指定目标单元格、选好排列与尺寸、一键启动,工具即可自动排序、自动跳过已有图片的格子、自动横向或纵向排列、自动调整行高列宽、自动逐格按数量插入并居中摆放,还能实时显示进度、完成后汇总结果,全程无需人工干预,终于解放了双手和时间!

            大佬们也可以举一反三,参照上面的代码思路根据自己工作中的实际情况来具体问题具体分析,实现自己定制化的需求。

            《该办公工具的应用场景:》

              1. 产品图归档

              一个产品对应多张图片(主图、细节图、包装图等),需要塞进同一单元格。按产品编号整理好图片文件名,批量插入后表格整洁紧凑,方便业务、运营、仓管查阅。

              2. 资料整理与学习归档

              收集的截图、参考图、素材图,按类别或编号放进 Excel 对应行,一格多图展示,比一图一列更省空间,也方便按主题浏览。

              3. 人员 / 档案管理

              员工照片、证件照、证书扫描件等,一人一行、一格多图,横向或纵向排列,档案表既美观又便于核对。

              4. 房源 / 车辆 / 商品清单

              房产、二手车、二手商品等信息表,每行一个标的,多角度图片统一插进一个单元格,表格不被图片撑散,展示更清晰。

              结语

              当Python遇见办公,牛马打工人终于笑出了猪叫声

              【职场人必看】每天早上一睁眼,想到又要面对:

              1.📊 堆积如山的Excel表格

              2.📑 机械重复的复制粘贴

              3.✍️ 永远改不完的各类文档

              4.诸如此类的更多........

              是不是连Ctrl+Alt+Delete的心都有了?别慌!别急,摸鱼这位“职场外挂”已经带着Python代码来拯救你了!

              另外,本文的代码和打包好的 exe 已同步上传至 NAS 私有云盘。有需要的大佬请私信摸鱼,仅需9.9 元进群即可获取下载链接,链接统一放在群公告里。目前公众号九成以上的文章资源都已上传 NAS 云盘,仅群内大佬可免费下载!

              最后,臣无大佬,无以至今日;大佬无臣,无以摸大鱼。感谢各位大佬看到最后。码字不易,摸鱼更不易,还望抬抬贵手,关注、点赞、转发、评论四连走起。大佬们每一下支持,都是摸鱼下次继续更新原创干货的动力!

              相关学习资料