Power Table - Dropdown Configuration

I hate to say this, but I was clicking around on the dropdown contemplating ways to depict selection [see post 24] when I observed a pretty significant bug in the onMouseClick extension function script from post 6, and I went down the rabbit hole again to fix it.

The problem was that if the user clicked on the same cell three times, or if the user clicked on something outside of the table, and then, clicked on the same cell, the scrollpane would revert back to its smaller size. This is because the cell maintains focus, and consequently, the extension function doesn't fire during the subsequent clicks.

To fix this, I ended up reworking the script for a popup menu listener, and putting the listener directly on the JComboBox itself from the configureEditor extension function. I do believe that this script is a finished product as far as controlling the dropdown width goes. I put a pretty good load on the table, and clicked it relentlessly, and so far, I haven't been able to get this to mess up.

Here is the result:

Here is the updated script:
#def configureEditor(self, colIndex, colName):
	from javax.swing import JComboBox, JScrollPane
	from java.awt import Dimension
	from java.awt.font import FontRenderContext, TextLayout
	from java.awt import Font
	from javax.swing.event import PopupMenuListener
	class DropdownListener(PopupMenuListener):
		def popupMenuWillBecomeVisible(self, event):
			def setSizes(dropdown):
				dropdown.setMaximumSize(Dimension(2*dropdownWidth, 2*dropdown.getPreferredSize().height))
				dropdown.setMinimumSize(Dimension(dropdownWidth, dropdown.getPreferredSize().height))
				dropdown.setPreferredSize(Dimension(dropdownWidth, dropdown.getPreferredSize().height))
			comboBox = event.source
			dropdown = comboBox.getUI().getAccessibleChild(comboBox, 0)
			dropdownFont = dropdown.font
			items = [
				comboBox.renderer.getListCellRendererComponent(dropdown.getList(), comboBox.model.getElementAt(row), -1, False, False).getText()
				for row in xrange(comboBox.model.size)
			]
			widestItem = max(items, key=len)
			dropdownWidth = int(TextLayout('&'*len(widestItem), dropdownFont, FontRenderContext(None, False, False)).bounds.width)
			setSizes(dropdown)
			defaultScrollpane = next((component for component in dropdown.getComponents() if isinstance(component, JScrollPane)), None)
			viewport = defaultScrollpane.viewport
			dropdown.remove(defaultScrollpane)
			replacementScrollPane = JScrollPane()
			replacementScrollPane.setViewport(viewport)
			dropdown.add(replacementScrollPane)
			setSizes(replacementScrollPane)
		def popupMenuWillBecomeInvisible(self, event):
			pass
		def popupMenuCanceled(self, event):
			pass
	def setListener():
		if self.data.rowCount > 0 and hasattr(self.table.getCellEditor(0, colIndex), 'component'):
			editorComponent = self.table.getCellEditor(0, colIndex).component
			if isinstance(editorComponent, JComboBox):
				for listener in editorComponent.popupMenuListeners:
					editorComponent.removePopupMenuListener(listener)
				editorComponent.addPopupMenuListener(DropdownListener())
	system.util.invokeLater(setListener)

Note: To use this, it should be placed at the top of the configureEditor extension function before any return statements. The original onMouseClick script should be deleted and not used.

In case it is useful for clarification or understanding, here is the test window I used to develop this:
testWindow.zip (29.5 KB)

6 Likes