Source code for schrodinger.ui.qt.periodictable

"""
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 ElementButton(QtWidgets.QToolButton): """ A toolbutton that is checkable (stays depressed) and is colored. the use of style sheets makes these buttons not only colored, but also square so that the Periodic Table looks like an actual clickable periodic table rather than a collection of rounded buttons. """
[docs] def __init__(self, text, tip, colors): """ Create an ElementButton instance :type text: str :param text: The text of the button :type tip: str :param tip: The button tooltip :type colors: tuple :param colors: The button colors - a two item tuple (normal button color, color when depressed). Should be strings in a color format that Qt style sheets accept. """ QtWidgets.QToolButton.__init__(self) self.setText(text) self.setToolTip(tip) self.setPeriodicStyle(colors) self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.setCheckable(True)
[docs] def setPeriodicStyle(self, colors): """ Set the color and style of the button. The use of a StyleSheet allows the button to be colored and square. :type colors: tuple :param colors: The button colors - a two item tuple (normal button color, color when depressed). Should be strings in a color format that Qt style sheets accept. """ self.setStyleSheet('ElementButton {' 'background-color: ' + colors[0] + ';' 'border-style: outset;' 'border-width: 1px;' 'border-color: grey } ' 'ElementButton:checked {' 'background-color: ' + colors[1] + ';' 'border-style: inset }')
[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 buttonChecked(self, button_id): """ Record the element that was just selected by the user """ if button_id == self.DU_BUTTON_ID and self.dummy_name: self.current_element = self.DU_ELEMENT else: self.current_element = button_id
[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] def getButtonId(self): """ Returns button ID of a selected element. :rtype: int :return: Button ID """ if self.current_element == self.DU_ELEMENT: return self.DU_BUTTON_ID return self.current_element
[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())