private JComponent createWorkPanel() {

		stringModel = new ViewStringsTableModel(tool);

		threadedTablePanel = new GhidraThreadedTablePanel<>(stringModel, 1000);
		table = threadedTablePanel.getTable();
		table.setPreferredScrollableViewportSize(new Dimension(350, 150));
		table.getSelectionModel().addListSelectionListener(e -> notifyContextChanged());

		stringModel.addTableModelListener(e -> {
			int rowCount = stringModel.getRowCount();
			int unfilteredCount = stringModel.getUnfilteredRowCount();

			setSubTitle("%d items%s".formatted(rowCount,
				rowCount != unfilteredCount ? " (of " + unfilteredCount + ")" : ""));
		});

		stringModel.addThreadedTableModelListener(new ThreadedTableModelListener() {

			@Override
			public void loadingStarted() {
				// ignore
			}

			@Override
			public void loadingFinished(boolean wasCancelled) {
				// loadingFinished gets called when the table is empty
				// and then when it finishes loading.
				// Only de-queue the delayedProgramLocation if we have records in the model.
				if (stringModel.getRowCount() != 0) {
					ProgramLocation delayedProgLoc = delayedShowProgramLocation.getAndSet(null);
					if (delayedProgLoc != null) {
						doShowProgramLocation(delayedProgLoc);
					}
				}
			}

			@Override
			public void loadPending() {
				// ignore
			}
		});
		TableColumn stringRepCol = table.getColumnModel()
				.getColumn(ViewStringsTableModel.COLUMNS.STRING_REP_COL.ordinal());

		stringRepCol.setCellEditor(new StringRepCellEditor());

		table.installNavigation(tool);

		filterPanel = new GhidraTableFilterPanel<>(table, stringModel);
		JPanel panel = new JPanel(new BorderLayout());
		panel.add(threadedTablePanel, BorderLayout.CENTER);
		panel.add(filterPanel, BorderLayout.SOUTH);

		String namePrefix = "Defined Strings";
		table.setAccessibleNamePrefix(namePrefix);
		filterPanel.setAccessibleNamePrefix(namePrefix);

		return panel;
	}
Provider for the defined strings table.
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/ViewStringsProvider.java