Lately, I've been messing around with the alarm status table in my spare time for fun, and in doing so, I've developed a way to produce larger checkboxes. In reality, it's just a simple overlay that adjusts the row height and column width to accommodate whatever size checkbox is specified and then paints the larger checkboxes over the originals. Listeners are used to repaint the checkboxes whenever they are clicked or when the table model changes as a result of filtering, sorting, or alarm state changes.
The checkbox size is specified in the second line of the script, and it can be set to any integer. Below is a picture that depicts the result. Four alarm status tables of equal size are staggered on top of each other. The bottom table is original and does not have the customization applied. The next three tables have specified checkboxes of size 25, 50, and 80 respectively.
Here is a short video that illustrates how the modification looks when scrolling and sorting :
This script adds listeners to the table, so it shouldn't be activated from a place that could fire more than once. My recommendation is to use the parent window's internalFrameOpened event handler. Here is the source code:
Source Code:
alarmStatusTable = system.gui.getParentWindow(event).getComponentForPath('Root Container.Alarm Status Table') #From the parent window's internalFrameOpened event handler
checkboxSize = 50
from javax.swing import JTable, JLabel, ImageIcon, OverlayLayout
from javax.swing.table import DefaultTableModel, DefaultTableCellRenderer, TableCellEditor
from javax.swing.event import TableModelListener
from java.awt import Color, Font, Dimension, BasicStroke, Graphics
from java.awt.event import MouseAdapter, MouseEvent
from java.awt.image import BufferedImage
from com.jidesoft.grid import JideTable
from com.jidesoft.swing import TristateCheckBox
class CheckboxRenderer(DefaultTableCellRenderer):
def __init__(self):
self.setSelected = False
def getTableCellRendererComponent(self, table, value, isSelected, hasFocus, row, column):
self.setEnabled(table.isEnabled())
self.setForeground(table.getForeground())
self.setBackground(table.getBackground())
if value == True:
self.setSelected = True
else:
self.setSelected = False
return self
def paintComponent(self, g):
if self.setSelected:
checkedBox = g.create()
checkedBox.setColor(Color.blue)
checkedBox.fillRoundRect(0, 0, self.getWidth()-1, self.getHeight()-1, 8, 8)
checkedBox.setColor(Color(214,214,214))
checkedBox.drawRoundRect(0, 0, self.getWidth()-1, self.getHeight()-1, 8, 8)
checkedBox.setStroke(BasicStroke(int(.14*float(checkboxSize))))
checkedBox.drawLine((int(.16*float(checkboxSize))), int(float(checkboxSize)*.5), int(.3*checkboxSize), (checkboxSize - int(.16*float(checkboxSize))))
checkedBox.drawLine(int(.3*checkboxSize), (checkboxSize - int(.16*float(checkboxSize))), (checkboxSize - int(.16*float(checkboxSize))), (int(.16*float(checkboxSize))))
checkedBox.dispose()
else:
uncheckedBox = g.create()
uncheckedBox.setColor(Color(214,214,214))
uncheckedBox.fillRoundRect(0, 0, self.getWidth()-1, self.getHeight()-1, 8, 8)
uncheckedBox.setColor(Color.black)
uncheckedBox.drawRoundRect(0, 0, self.getWidth()-1, self.getHeight()-1, 8, 8)
uncheckedBox.dispose()
class LabelMouseListener(MouseAdapter):
def mouseClicked(self, event):
checkboxModel = getTable('checkbox').getModel()
checked = False
unchecked = False
triStateCheckbox = getTriStateCheckbox(alarmStatusTable)
triStateCheckbox.doClick()
class TableChangeListener(TableModelListener):
def tableChanged(self, event):
if not alarmStatusTable.multiSelect:
return
mainModel = event.source
checkboxModel = getTable('checkbox').getModel()
overlayModel = getTable('overlay').getModel()
triStateCheckBox = getTriStateCheckbox(alarmStatusTable)
bigTriStateCheckbox = getBigCheckbox(alarmStatusTable)
if overlayModel.rowCount < checkboxModel.rowCount:
for row in range(overlayModel.rowCount, checkboxModel.rowCount):
overlayModel.addRow([False])
for row in range(overlayModel.rowCount):
overlayModel.setValueAt(checkboxModel.getValueAt(row, 0), row, 0)
else:
for row in range(overlayModel.rowCount):
if row < checkboxModel.rowCount:
overlayModel.setValueAt(checkboxModel.getValueAt(row, 0), row, 0)
else:
for deletedRow in range(checkboxModel.rowCount, overlayModel.rowCount):
overlayModel.removeRow(checkboxModel.rowCount)
if triStateCheckBox.getState() == 0:
bigTriStateCheckbox.setIcon(setUnchecked())
elif triStateCheckBox.getState() == 1:
bigTriStateCheckbox.setIcon(setChecked())
else:
bigTriStateCheckbox.setIcon(setPartialChecked())
class TableMouseListener(MouseAdapter):
def __init__(self, table):
self.table = table
def mousePressed(self, event):
if event.getButton() == MouseEvent.BUTTON1:
point = event.getPoint()
row = self.table.rowAtPoint(point)
if row != -1:
checkboxModel = getTable('checkbox').getModel()
modifiedTable = self.table
if checkboxModel.getValueAt(modifiedTable.convertRowIndexToModel(row), 0):
checkboxModel.setValueAt(False, modifiedTable.convertRowIndexToModel(row), 0)
else:
checkboxModel.setValueAt(True, modifiedTable.convertRowIndexToModel(row), 0)
class BooleanEditor(TableCellEditor):
def getTableCellEditorComponent(self, table, value, isSelected, row, column):
checkboxModel = getTable('checkbox').getModel()
if value:
table.getModel().setValueAt(False, row, column)
checkboxModel.setValueAt(False, row, column)
else:
table.getModel().setValueAt(True, row, column)
checkboxModel.setValueAt(True, row, column)
def isCellEditable(self, event):
return True
def setCheckboxOverlay(checkboxTable):
checkboxModel = checkboxTable.getModel()
overlayModel = DefaultTableModel()
checkBoxOverlay = JTable(overlayModel)
checkBoxOverlay.setPreferredScrollableViewportSize(checkboxTable.getPreferredScrollableViewportSize())
overlayModel.addColumn([])
for row in range(checkboxModel.rowCount):
overlayModel.addRow([checkboxModel.getValueAt(row, 0)])
checkBoxOverlay.getColumnModel().getColumn(0).setCellRenderer(CheckboxRenderer())
checkBoxOverlay.getColumnModel().getColumn(0).setCellEditor(BooleanEditor())
return checkBoxOverlay
def getTable(tableType):#Retrieves a fresh jTable instance from the alarmStatusTable
def tableSearch(tableType, alarmStatusTable):
if alarmStatusTable.componentCount > 0:
for component in alarmStatusTable.getComponents():
if 'AlarmStatusTable$1' in str(component.__class__) and tableType == 'main':
return component
elif 'JideTable' in str(component.__class__) and tableType == 'checkbox':
return component
elif 'JTable' in str(component.__class__) and tableType == 'overlay':
return component
else:
table = tableSearch(tableType, component)
if table is not None:
return table
return None
return tableSearch(tableType, alarmStatusTable)
def initializeTable():
checkboxTable = getTable('checkbox')
mainTable = getTable('main')
checkboxViewport = checkboxTable.getParent()
checkboxTable.visible = False
checkBoxOverlay = setCheckboxOverlay(checkboxTable)
overlayModel = checkBoxOverlay.getModel()
checkboxTable.getParent().getParent().add(checkboxTable)
checkboxViewport.add(checkBoxOverlay)
checkBoxscrollPane = checkBoxOverlay.getParent().getParent()
checkBoxViewport = checkBoxOverlay.getParent()
checkBoxscrollPane.setPreferredSize(Dimension(checkboxSize, checkBoxscrollPane.getPreferredSize().height))
checkBoxViewport.setPreferredSize(Dimension(checkboxSize, checkBoxViewport.getPreferredSize().height))
checkBoxOverlay.setRowHeight(checkboxSize)
mainTable.setRowHeight(checkboxSize)
mainTable.getTableHeader().setPreferredSize(Dimension(mainTable.getTableHeader().getPreferredSize().width, checkboxSize))
checkBoxOverlay.setShowGrid(True)
checkBoxOverlay.setGridColor(Color.black)
mainTable = getTable('main')
modelListener = TableChangeListener()
mainTable.getModel().addTableModelListener(modelListener)
triStateCheckbox = getTriStateCheckbox(alarmStatusTable)
bigTriStateCheckbox = JLabel()
bigTriStateCheckbox.name = 'bigCheckBox'
bigTriStateCheckbox.setIcon(setUnchecked())
parent = triStateCheckbox.getParent()
parent.setLayout(OverlayLayout(parent))
parent.remove(triStateCheckbox)
parent.add(bigTriStateCheckbox)
parent.add(triStateCheckbox)
listener = LabelMouseListener()
bigTriStateCheckbox.addMouseListener(listener)
def getTriStateCheckbox(component):
if component.componentCount > 0:
for component in component.getComponents():
if isinstance(component, TristateCheckBox):
return component
else:
triStateCheckbox = getTriStateCheckbox(component)
if triStateCheckbox is not None:
return triStateCheckbox
return None
def getBigCheckbox(component):
if component.componentCount > 0:
for component in component.getComponents():
if component.name == 'bigCheckBox':
return component
else:
triStateCheckbox = getBigCheckbox(component)
if triStateCheckbox is not None:
return triStateCheckbox
return None
def setUnchecked():
uncheckedImage = BufferedImage(checkboxSize, checkboxSize, BufferedImage.TYPE_INT_ARGB)
uncheckedBox = uncheckedImage.createGraphics()
uncheckedBox.setColor(Color(214,214,214))
uncheckedBox.fillRoundRect(0, 0, checkboxSize-1, checkboxSize-1, 8, 8)
uncheckedBox.setColor(Color.black)
uncheckedBox.drawRoundRect(0, 0, checkboxSize-1, checkboxSize-1, 8, 8)
uncheckedBox.dispose()
uncheckedIcon = ImageIcon(uncheckedImage)
return uncheckedIcon
def setChecked():
checkedImage = BufferedImage(checkboxSize, checkboxSize, BufferedImage.TYPE_INT_ARGB)
checkedBox = checkedImage.createGraphics()
checkedBox.setColor(Color.blue)
checkedBox.fillRoundRect(0, 0, checkboxSize-1, checkboxSize-1, 8, 8)
checkedBox.setColor(Color(214,214,214))
checkedBox.drawRoundRect(0, 0, checkboxSize-1, checkboxSize-1, 8, 8)
checkedBox.setStroke(BasicStroke(int(.14*float(checkboxSize))))
checkedBox.drawLine((int(.16*float(checkboxSize))), int(float(checkboxSize)*.5), int(.3*checkboxSize), (checkboxSize - int(.16*float(checkboxSize))))
checkedBox.drawLine(int(.3*checkboxSize), (checkboxSize - int(.16*float(checkboxSize))), (checkboxSize - int(.16*float(checkboxSize))), (int(.16*float(checkboxSize))))
checkedBox.dispose()
checkedIcon = ImageIcon(checkedImage)
return checkedIcon
def setPartialChecked():
checkedImage = BufferedImage(checkboxSize, checkboxSize, BufferedImage.TYPE_INT_ARGB)
checkedBox = checkedImage.createGraphics()
checkedBox.setColor(Color.blue)
checkedBox.fillRoundRect(0, 0, checkboxSize-1, checkboxSize-1, 8, 8)
checkedBox.setColor(Color(214,214,214))
checkedBox.drawRoundRect(0, 0, checkboxSize-1, checkboxSize-1, 8, 8)
checkedBox.setStroke(BasicStroke(int(.14*float(checkboxSize))))
checkedBox.drawLine(int(.16*float(checkboxSize)), int(float(checkboxSize)*.5), (checkboxSize - int(.16*float(checkboxSize))), int(float(checkboxSize)*.5))
checkedBox.dispose()
checkedIcon = ImageIcon(checkedImage)
return checkedIcon
initializeTable()
I've tested this script with more than 1100 active alarms, and it worked quite well: