Add component table plugin for KiCad PCB editor

Shows a sortable table of all board components with columns for
designation, value, library, package, and sheet instance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 16:31:05 +00:00
commit 27b79d38a7
3 changed files with 137 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
import pcbnew
import wx
import wx.lib.mixins.listctrl as listmix
COLUMNS = ['Designation', 'Value', 'Library', 'Package', 'Sheet']
class Sortable_Component_List(wx.ListCtrl, listmix.ColumnSorterMixin):
def __init__(self, parent):
wx.ListCtrl.__init__(
self, parent,
style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES | wx.LC_SINGLE_SEL
)
col_widths = [100, 120, 160, 200, 200]
for i, (col, w) in enumerate(zip(COLUMNS, col_widths)):
self.InsertColumn(i, col, width=w)
self.item_data_map = {}
listmix.ColumnSorterMixin.__init__(self, len(COLUMNS))
def GetListCtrl(self):
return self
def populate(self, rows):
self.DeleteAllItems()
self.item_data_map = {}
for idx, row in enumerate(rows):
item = self.InsertItem(idx, row[0])
for col, val in enumerate(row[1:], start=1):
self.SetItem(idx, col, val)
self.SetItemData(idx, idx)
self.item_data_map[idx] = row
class Component_Table_Dialog(wx.Dialog):
def __init__(self, parent, components):
super().__init__(
parent,
title='Component Table',
size=(850, 550),
style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER
)
sizer = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(self, label=f'{len(components)} component(s) — click column headers to sort')
sizer.Add(label, 0, wx.LEFT | wx.TOP, 8)
self.list_ctrl = Sortable_Component_List(self)
self.list_ctrl.populate(components)
sizer.Add(self.list_ctrl, 1, wx.EXPAND | wx.ALL, 6)
btn_close = wx.Button(self, wx.ID_CLOSE, 'Close')
btn_close.Bind(wx.EVT_BUTTON, lambda e: self.Close())
sizer.Add(btn_close, 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.BOTTOM, 8)
self.SetSizer(sizer)
self.Centre()
def _get_sheet(fp):
try:
props = fp.GetProperties()
for key in ('Sheetname', 'Sheet', 'sheet'):
val = props.get(key, '')
if val:
return val
except Exception:
pass
try:
path = str(fp.GetPath())
if path and path != '/':
return path
except Exception:
pass
return '-'
class Component_Table_Action(pcbnew.ActionPlugin):
def defaults(self):
self.name = 'Component Table'
self.category = 'Inspect'
self.description = 'Show a sortable table of all board components'
self.show_toolbar_button = True
self.icon_file_name = ''
def Run(self):
board = pcbnew.GetBoard()
components = []
for fp in sorted(board.GetFootprints(), key=lambda f: f.GetReference()):
ref = fp.GetReference()
value = fp.GetValue()
fpid = fp.GetFPID()
library = str(fpid.GetLibNickname())
package = str(fpid.GetLibItemName())
sheet = _get_sheet(fp)
components.append((ref, value, library, package, sheet))
dlg = Component_Table_Dialog(None, components)
dlg.ShowModal()
dlg.Destroy()
Component_Table_Action().register()