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)