schrodinger.ui.qt.utils module

Utility functions and classes for working with PyQt

schrodinger.ui.qt.utils.to_float(val)
schrodinger.ui.qt.utils.pluralize_text(noun, count, suffix='s')

Helper function to pluralize simple nouns when necessary

Parameters
  • noun (str) – singular form of the noun

  • count (int) – number of objects noun is describing

  • suffix (str) – letters to add to the word to make the plural form

schrodinger.ui.qt.utils.image_to_string(image)
Parameters

image (QtGui.QImage) – QImage instance

Returns

string representation of the given image

Return type

str

class schrodinger.ui.qt.utils.JobLaunchWaitCursorContext

Bases: object

Context manager for showing a wait cursor while waiting for a job to launch. Times out after 5 seconds.

Should not be used for anything else, as it relies on the code inside of the context running a QEventLoop to not block the single shot timer in __enter__.

__init__()
schrodinger.ui.qt.utils.maestro_required(func, *args, **kwargs)

A decorator for functions that should only be run when inside of Maestro. When run outside of Maestro, the decorated function will be a no-op.

class schrodinger.ui.qt.utils.MaestroPythonBannerManager

Bases: PyQt6.QtCore.QObject

Show one Maestro PythonBanner at a time

bannerClosed

pyqtSignal(*types, name: str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.

modalBannerClosed

pyqtSignal(*types, name: str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.

__init__()
showBanner(widget, is_modal=True, show_close_button=True)

Show widget in a banner in Maestro. Any previously shown banner will be closed.

Parameters
  • widget (QtWidgets.QWidget) – Widget to show in a Maestro banner

  • is_modal (bool) – Whether to show banner as modal. Maestro can only show one modal banner at a time. Multiple non-modal banners can be displayed and they auto-dismiss after a time.

  • show_close_button (bool) – Whether to show graphical close button on the right side of the notification

closeBanner()

Close the currently-shown banner in Maestro.

schrodinger.ui.qt.utils.undo_block()

A context manager for putting all Maestro commands into an undo block, which can also be used as a function decorator.

class schrodinger.ui.qt.utils.LineEditWithSampleText(*args, **kwargs)

Bases: PyQt6.QtWidgets.QLineEdit

A line edit that uses sample text to determine its horizontal size hint.

Note

You may need to change the horizontal size policy of this line edit depending on your usage. If you’re using the sample data to make sure the line edit is wide enough, keep the size policy at its default setting of Expanding. If you’re using the sample data to make sure the line edit isn’t too wide, you’ll likely need to change the size policy to Preferred. Note that the size policy change can be done through Designer if desired.

__init__(*args, **kwargs)
setSampleText(sample_text, enlarge=0.2)

Specify the sample data used to set the horizontal size hint

Parameters
  • sample_text (str) – The sample text

  • enlarge (float) – The sample data will be widened by this percent so that there’s extra width in the line edit. Defaults to 0.2 (or a 20% increase)

sizeHint(self) QSize
schrodinger.ui.qt.utils.checkStructurePrep(st, parent=None)

Make sure that the specified structure passes a force field check (i.e. has hydrogens, proper bond orders, and atomic charges). If it doesn’t, prompt the user to run the Protein Preparation Workflow. Launch the Prep Workflow if requested.

Parameters
  • st (schrodinger.structure.Structure) – The structure to check

  • parent (PyQt5.QtWidgets.QWidget) – The widget that should be the parent of the Protein Prep dialog

Returns

True if the structure passes the force field check. False otherwise.

Return type

bool

exception schrodinger.ui.qt.utils.ErrorForDialog

Bases: Exception

An exception that will be caught by catch_error_for_dialog. This exception should be raised with the error message to display to the user. If raised without an error message, then no error dialog will be displayed. (This assumes that the user has already been notified of the error in another way, e.g., a question dialog.)

schrodinger.ui.qt.utils.catch_error_for_dialog(func, self, *args, **kwargs)

A decorator that catches ErrorForDialog exceptions and displays the exception message in an error dialog.

class schrodinger.ui.qt.utils.BorderlessPopUpFrame(parent=None, ui=None)

Bases: PyQt6.QtWidgets.QFrame

Class for creating borderless popup frames that have a flat close button style. Additional widgets can be added to the frame’s self.ui.vertical_layout to customize the frame.

__init__(parent=None, ui=None)
Parameters
  • parent (QtWidgets.QWidget) – parent to attach widget to.

  • ui (module) – UI form to use for this widget. Must define a QFrame and have a QPushButton widget named close_btn. If None, will use the default form for this frame.

schrodinger.ui.qt.utils.join_images(pic1, pic2, side_by_side=True)

Given two QPictures, join them into one image either side by side, or one below the other. If either image is smaller than the other, the smaller one will be centered accordingly.

Parameters
  • pic1 (QtGui.QImage or QtGui.QPicture) – the first picture to place into the larger image

  • pic2 (QtGui.QImage or QtGui.QPicture) – the second picture to place into the larger image

  • side_by_side (bool) – whether to place the two pictures side by side, or one below the other.

Returns

the final constructed image.

Return type

QtGui.QImage

class schrodinger.ui.qt.utils.ButtonAcceptsFocusMixin(*args, **kwargs)

Bases: object

A mixin to ensure that a button takes focus when it’s pressed. This forces any open table delegates to lose focus, which triggers the data to be committed. This won’t happen by default with QPushButtons on Mac and with QToolButtons on all platforms. (See PANEL-1113.)

__init__(*args, **kwargs)
class schrodinger.ui.qt.utils.AcceptsFocusPushButton(*args, **kwargs)

Bases: schrodinger.ui.qt.utils.ButtonAcceptsFocusMixin, PyQt6.QtWidgets.QPushButton

schrodinger.ui.qt.utils.wrap_qt_tag(text)

Returns text wrapped in the <qt> tag. Used to create rich-text tooltips.

schrodinger.ui.qt.utils.wrap_html_tag(text, html_tag='qt')

Returns text wrapped in a custom html tag.

schrodinger.ui.qt.utils.add_widget_to_menu(widget, menu=None)

Add widget as an action to menu.

Example with button:

btn = QtWidgets.QPushButton()
popup_widget = QtWidgets.QLabel("This text pops up from a button")
menu = add_widget_to_menu(popup_widget)
btn.setMenu(menu)

Example with menu:

menu = QtWidgets.QMenu()
popup_widget = QtWidgets.QLabel("This text appears as a menu action")
add_widget_to_menu(popup_widget, menu)
Parameters
  • widget (QtWidgets.QWidget) – The widget to show as a menu action

  • menu (QtWidgets.QMenu or NoneType) – The menu to show the widget in. If None, a new menu will be created.

Returns

The menu

Return type

QtWidgets.QMenu

schrodinger.ui.qt.utils.update_widget_style(widget)

Utility function to update widget style. When user applies stylesheet widget does not update immediately unless user explicitly calls polish()/unpolish on widget.

Parameters

widget – The widget to be updated.

schrodinger.ui.qt.utils.traverse_model_rows(model, parent=<PyQt6.QtCore.QModelIndex object>)

Traverse the rows of a model, including children (e.g. for a QTreeView)

Parameters
  • model (QtCore.QAbstractItemModel) – Item model

  • parent (QtCore.QModelIndex) – Parent index to start traversal

Returns

All row indices

Return type

generator(QtCore.QModelIndex)

schrodinger.ui.qt.utils.linux_setVisible_positioning_workaround(obj, super_obj, set_visible)

Call this from the setVisible method of a QWidget that needs to reappear in the same location it was last hidden from. This works around a bug on Linux where the widget fails to correctly set its position. To use add the following code to the widget class:

if sys.platform.startswith(“linux”):
def setVisible(self, set_visible):
qt_utils.linux_setVisible_positioning_workaround(self, super(),

set_visible)

Parameters
  • obj (QWidget) – the widget that needs to be positioned correctly on Linux. This is generally “self” in the calling method.

  • super_obj (QWidget proxy) – the return value of super() from the calling method

  • set_visible (bool) – whether to set it visible or invisible

schrodinger.ui.qt.utils.get_widgets_in_layout(layout, recursive=True)
schrodinger.ui.qt.utils.hide_layout_elements(layout: PyQt6.QtWidgets.QBoxLayout, remove_spacers: bool = True)

Recursively hide all widgets in the layout. Permanently remove spacers from the layout if remove_spacers is True.

schrodinger.ui.qt.utils.add_items_to_glayout(glayout, items)

Add the specified items to a grid layout.

Parameters

items (list[list[Union[QtWidgets.QWidget, QtWidgets.QLayout, None]]]) – List of lists of items to add to the layout, or None to leave a gap in that position

schrodinger.ui.qt.utils.show_job_launch_failure_dialog(err_msg, parent=None)

Show dialog for informing the user of the reason why job failed to launch.

Parameters
  • err_msg (str) – The message passed to the JobLaunchFailure constructor

  • parent (QWidget or None) – Optional parent for the dialog.

class schrodinger.ui.qt.utils.HeaderViewWithMenuIndicator(parent=None)

Bases: PyQt6.QtWidgets.QHeaderView

A horizontal header view that shows a down arrow indicator on hover for a context menu.

Variables
  • _MENU_INDICATOR_WIDTH (float) – width of the menu indicator.

  • _MENU_INDICATOR_HEIGHT – height of the menu indicator.

  • _MENU_INDICATOR_RIGHT_MARGIN – margin to the right of the menu indicator.

  • _MENU_INDICATOR_PERCENTAGE – relative depth of the menu indicator from the parent rectangle.

  • contextMenuIndicatorClicked (QtCore.pyqtSignal) –

    emitted when their is a left mouse button click on the context menu indicator. Emitted with:

    • position of the event.

contextMenuIndicatorClicked

pyqtSignal(*types, name: str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

types is normally a sequence of individual types. Each type is either a type object or a string that is the name of a C++ type. Alternatively each type could itself be a sequence of types each describing a different overloaded signal. name is the optional C++ name of the signal. If it is not specified then the name of the class attribute that is bound to the signal is used. revision is the optional revision of the signal that is exported to QML. If it is not specified then 0 is used. arguments is the optional sequence of the names of the signal’s arguments.

__init__(parent=None)
getMenuIndicatorRect(parent_rect)

Returns a rectangle at the right bottom corner of the parent rectangle.

Parameters

parent_rect (QtCore.QRect) – parent rectangle.

Returns

bounding rectangle of the visual indicator.

Return type

QtCore.QRect

paintSection(painter, rect, logical_index)

Overrides QHeaderView.paintSection. Calls the parent method to paint the section and paints a down arrow at the right bottom edge of the section on hover.

mouseMoveEvent(event)

Overrides QHeaderView.mouseMoveEvent. Updates the current hover section index and calls super method on all received events.

leaveEvent(event)

Overrides QWidget.leaveEvent. Updates the current hover section index and calls super method on all received events.

mousePressEvent(event)

Overrides QHeaderView.mousePressEvent. Emits contextMenuIndicatorClicked signal when their is a left button press in the menu indicator bounding rectangle and calls super method on all received events

schrodinger.ui.qt.utils.get_view_item_options(view: PyQt6.QtWidgets.QAbstractItemView) PyQt6.QtWidgets.QStyleOptionViewItem

Retrieve the view item options for the provided table/tree view. This function will work under both Qt 5 and Qt 6.

schrodinger.ui.qt.utils.combo_find_data(combo: PyQt6.QtWidgets.QComboBox, data, role: PyQt6.QtCore.Qt.ItemDataRole = ItemDataRole.UserRole, *, error_if_missing: bool = True) int

Get the index of the item containing the specified data in a combo box. Comparisons are done in Python rather than in C++ (as they are in QComboBox.findData) so that Python types without a direct C++ mapping can be compared correctly. Note that in PyQt 6, QComboBox.findData no longer works correctly for enum.Enum data (including enum.IntEnum), so this function should be used instead.

Parameters
  • combo – The combo box to search

  • data – The data to search for

  • role – The role to search

  • error_if_missing – Whether to raise a ValueError if data is not found in combo. If False, -1 will be returned when data is missing.

Raises

ValueError – If the specified data cannot be found and error_if_missing is true.

schrodinger.ui.qt.utils.clear_layout(layout: PyQt6.QtWidgets.QLayout)

Delete and remove all widgets and clear all layouts from the given layout.

Parameters

layout – Layout to remove all items