"""
A simple periodic table widget that allows the user to select a single element.
Example usage:
self.table_dialog = PeriodicTableDialog(self)
self.table_dialog.exec()
symbol = self.periodic_table_dlg.getSymbol()
Copyright Schrodinger, LLC. All rights reserved.
"""
from schrodinger.infra import mm
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtWidgets
from schrodinger.ui.qt import swidgets
[docs]class PeriodicTableDialog(swidgets.SDialog):
"""
A simple periodic table widget that allows the user to select a single
element.
"""
# Each item in ELEMENTS is (Name, Symbol, Column, Row). Column and Row are
# 0-indexed, and Row is the physical location of the button, not
# necessarily the Periodic Table row - so the lanthanides have a different
# Row value than Lanthanum, for instance
ELEMENTS = [
('Hydrogen', 'H', 0, 0),
('Helium', 'He', 17, 0),
('Lithium', 'Li', 0, 1),
('Beryllium', 'Be', 1, 1),
('Boron', 'B', 12, 1),
('Carbon', 'C', 13, 1),
('Nitrogen', 'N', 14, 1),
('Oxygen', 'O', 15, 1),
('Fluorine', 'F', 16, 1),
('Neon', 'Ne', 17, 1),
('Sodium', 'Na', 0, 2),
('Magnesium', 'Mg', 1, 2),
('Aluminium', 'Al', 12, 2),
('Silicon', 'Si', 13, 2),
('Phosphorus', 'P', 14, 2),
('Sulphur', 'S', 15, 2),
('Chlorine', 'Cl', 16, 2),
('Argon', 'Ar', 17, 2),
('Potassium', 'K', 0, 3),
('Calcium', 'Ca', 1, 3),
('Scandium', 'Sc', 2, 3),
('Titanium', 'Ti', 3, 3),
('Vanadium', 'V', 4, 3),
('Chromium', 'Cr', 5, 3),
('Manganese', 'Mn', 6, 3),
('Iron', 'Fe', 7, 3),
('Cobalt', 'Co', 8, 3),
('Nickel', 'Ni', 9, 3),
('Copper', 'Cu', 10, 3),
('Zinc', 'Zn', 11, 3),
('Gallium', 'Ga', 12, 3),
('Germanium', 'Ge', 13, 3),
('Arsenic', 'As', 14, 3),
('Selenium', 'Se', 15, 3),
('Bromine', 'Br', 16, 3),
('Krypton', 'Kr', 17, 3),
('Rubidium', 'Rb', 0, 4),
('Strontium', 'Sr', 1, 4),
('Yttrium', 'Y', 2, 4),
('Zirconium', 'Zr', 3, 4),
('Niobium', 'Nb', 4, 4),
('Molybdenum', 'Mo', 5, 4),
('Technetium', 'Tc', 6, 4),
('Ruthenium', 'Ru', 7, 4),
('Rhodium', 'Rh', 8, 4),
('Palladium', 'Pd', 9, 4),
('Silver', 'Ag', 10, 4),
('Cadmium', 'Cd', 11, 4),
('Indium', 'In', 12, 4),
('Tin', 'Sn', 13, 4),
('Antimony', 'Sb', 14, 4),
('Tellurium', 'Te', 15, 4),
('Iodine', 'I', 16, 4),
('Xenon', 'Xe', 17, 4),
('Cesium', 'Cs', 0, 5),
('Barium', 'Ba', 1, 5),
('Lanthanum', 'La', 2, 5),
('Cerium', 'Ce', 3, 9),
('Praseodymium', 'Pr', 4, 9),
('Neodymium', 'Nd', 5, 9),
('Promethium', 'Pm', 6, 9),
('Samarium', 'Sm', 7, 9),
('Europium', 'Eu', 8, 9),
('Gadolinium', 'Gd', 9, 9),
('Terbium', 'Tb', 10, 9),
('Dysprosium', 'Dy', 11, 9),
('Holmium', 'Ho', 12, 9),
('Erbium', 'Er', 13, 9),
('Thulium', 'Tm', 14, 9),
('Ytterbium', 'Yb', 15, 9),
('Lutetium', 'Lu', 16, 9),
('Hafnium', 'Hf', 3, 5),
('Tantalum', 'Ta', 4, 5),
('Tungsten', 'W', 5, 5),
('Rhenium', 'Re', 6, 5),
('Osmium', 'Os', 7, 5),
('Iridium', 'Ir', 8, 5),
('Platinum', 'Pt', 9, 5),
('Gold', 'Au', 10, 5),
('Mercury', 'Hg', 11, 5),
('Thallium', 'Tl', 12, 5),
('Lead', 'Pb', 13, 5),
('Bismuth', 'Bi', 14, 5),
('Polonium', 'Po', 15, 5),
('Astatine', 'At', 16, 5),
('Radon', 'Rn', 17, 5),
('Francium', 'Fr', 0, 6),
('Radium', 'Ra', 1, 6),
('Actinium', 'Ac', 2, 6),
('Thorium', 'Th', 3, 10),
('Protactinium', 'Pa', 4, 10),
('Uranium', 'U', 5, 10),
('Neptunium', 'Np', 6, 10),
('Plutonium', 'Pu', 7, 10),
('Americium', 'Am', 8, 10),
('Curium', 'Cm', 9, 10),
('Berkelium', 'Bk', 10, 10),
('Californium', 'Cf', 11, 10),
('Einsteinium', 'Es', 12, 10),
('Fermium', 'Fm', 13, 10),
('Mendelevium', 'Md', 14, 10),
('Nobelium', 'No', 15, 10),
('Lawrencium', 'Lr', 16, 10),
('Rutherfordium', 'Rf', 3, 6),
('Dubnium', 'Db', 4, 6),
('Seaborgium', 'Sg', 5, 6),
('Bohrium', 'Bh', 6, 6),
('Hassium', 'Hs', 7, 6),
('Meitnerium', 'Mt', 8, 6),
('Darmstadtium', 'Ds', 9, 6),
('Roentgenium', 'Rg', 10, 6),
('Copernicium', 'Cn', 11, 6),
('Nihonium', 'Nh', 12, 6),
('Flerovium', 'Fl', 13, 6),
('Moscovium', 'Mc', 14, 6),
('Livermorium', 'Lv', 15, 6),
('Tennessine', 'Ts', 16, 6),
('Oganesson', 'Og', 17, 6)
] # yapf: disable
DU_SYMBOL, DU_ELEMENT, DU_BUTTON_ID = 'DU', -2, 500
[docs] def __init__(self,
parent=None,
default_element=6,
max_element=mm.MMELEMENTS_MAX,
title='Choose Element',
dummy_name=''):
"""
Create a PeriodicTable instance
:type parent: QWidget
:param parent: Dialog's parent.
:type default_element: int
:param default_element: Default selected element.
:type max_element: int
:param max_element: Number of elements displayed in the widget.
:type title: str
:param title: The Dialog window title
:type dummy_name: str
:param show_dummy: Dummy name, if showing of dummy element is desired
"""
self.max_element = max_element
self.dummy_name = dummy_name
swidgets.SDialog.__init__(self, parent, title=title)
self.current_element = default_element
self.button_group.button(default_element).setChecked(True)
[docs] def layOut(self):
"""
Lay out the periodic table
"""
def addButton(number, symbol, name, button_id, colors, row, column):
"""
Add button to self.button_group and self.grid_layout
:type number: int
:param number: Atomic number used in button tip
:type symbol: str
:param symbol: Atom symbol used in button label
:type name: str
:param name: Atom name used in button tip
:type button_id: int
:param button_id: Button ID used in self.button_group
:type colors: tuple(str)
:param colors: Colors when button is unchecked and checked
:type row: int
:param row: Row in the self.grid_layout to place the button
:type column: int
:param column: Column in the self.grid_layout to place the button
"""
tip = str(number) + '\n' + name
but = ElementButton(symbol, tip, colors)
self.button_group.addButton(but)
self.button_group.setId(but, button_id)
self.grid_layout.addWidget(but, row, column)
self.grid_layout = QtWidgets.QGridLayout()
self.grid_layout.setSpacing(0)
self.mylayout.addLayout(self.grid_layout)
self.button_group = QtWidgets.QButtonGroup()
todo = self.ELEMENTS[:self.max_element]
max_row = 0
for atomic_number, element_data in enumerate(todo, 1):
name, symbol, column, row = element_data
max_row = max(max_row, row)
# Each color tuple is (normal, depressed)
if row > 8:
colors = ('#80FF80', '#50CC50')
elif column < 2:
colors = ('#7ADDEE', '#4AAABB')
elif column < 12:
colors = ('#EEBABA', '#CC9999')
else:
colors = ('#EEDD7A', '#CCBB5A')
addButton(atomic_number, symbol, name, atomic_number, colors, row,
column)
if self.dummy_name:
colors = ('#DADADA', '#9B9B9B')
self.grid_layout.addWidget(QtWidgets.QLabel(""), max_row + 1, 0)
addButton(self.DU_ELEMENT, self.dummy_name, self.dummy_name,
self.DU_BUTTON_ID, colors, max_row + 2, 0)
self.button_group.idClicked.connect(self.buttonChecked)
# This puts a space between the main table and the lanthanides
self.grid_layout.addWidget(QtWidgets.QLabel(""), 7, 0)
[docs] def showEvent(self, event):
"""
Reimplemented showEvent event. Checks self.current_button.
:type event: QShowEvent
:param event: Show event.
"""
self.button_group.button(self.getButtonId()).setChecked(True)
return super(PeriodicTableDialog, self).showEvent(event)
[docs] def getElement(self):
"""
Returns atomic number of a selected element.
:rtype: int
:return: Atomic number of a selected element.
"""
return self.current_element
[docs] def getSymbol(self):
"""
Returns symbol of a selected element.
:rtype: str
:return: Symbol of a selected element.
"""
if self.current_element == self.DU_ELEMENT:
return self.DU_SYMBOL
return self.ELEMENTS[self.current_element - 1][1]
[docs]class PeriodicTableDialogSingleClick(PeriodicTableDialog):
"""
This provides a version of the Periodic Table widget that doesn't have
OK/Cancel buttons, and will emit a signal and close itself when an
element is toggled.
"""
elementSelected = QtCore.pyqtSignal(str)
[docs] def __init__(
self,
parent=None,
default_element=6,
max_element=len(PeriodicTableDialog.ELEMENTS), # noqa: M511
title='Choose Element'):
super(PeriodicTableDialogSingleClick,
self).__init__(parent, default_element, max_element, title) #noqa
self.dbb.hide() # Hide the OK/Cancel buttons
self.button_group.idClicked.connect(self.emitElementSelected)
[docs] def emitElementSelected(self, button_index):
element_tuple = PeriodicTableDialog.ELEMENTS[button_index - 1]
element_short = element_tuple[1]
self.elementSelected.emit(element_short)
if __name__ == '__main__':
from schrodinger.ui.qt import style as qtstyle
app = QtWidgets.QApplication([])
qtstyle.apply_styles()
dialog = PeriodicTableDialog()
dialog.exec()
print(dialog.getSymbol(), dialog.getElement())