On this page:
Child pages:
Copied from Controls Software Operations Group's page by Tasha Summers
Useful links
Common Practices For PyDM Displays
When creating a display through designer (.ui file) or python (.py file), there are a few things that we as controls software ops support group would like to keep consistent across all displays.
- Buttons that launch other applications should have a related display indicator! This is so the user of the display can easily distinguish between a clickable button writing to some PV through channel access protocols and a related display. The same logic should also be applied to shell commands that launch external displays.
Main screens (files with naming convention {subsystem}_{area}_main.ui and appear as the first layer on LCLSHOME) should include a title as shown in the screenshot below.
Default Python Based PyDM
This block of code can be used to create a basic PyDM screen. This is useful for testing new ideas, creating demonstrations, or as a launch point for new Python script based PyDM user interfaces. You may need to import additional Qt and PyDM widgets, as well as other useful Python packages. The Python packages epics
, functools
, and pandas
are among some frequently used packages.
from qtpy.QtWidgets import (QApplication, QHBoxLayout, QVBoxLayout,
QGridLayout, QLabel, QPushButton,
QFrame, QTableWidget, QLineEdit,
QSpacerItem, QSizePolicy)
from pydm import Display
from pydm.widgets import PyDMLabel, PyDMLineEdit
from pydm.widgets.base import PyDMWidget
from pydm.widgets.related_display_button import PyDMRelatedDisplayButton
class MainWindow(Display):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.main_layout = QVBoxLayout()
self.setLayout(self.main_layout)
Tables are a powerful PyQT tool. Tables are intuitive and organized by nature, in contrast to some of the PyQT Layouts. The geometry of tables lend themselves to programmatic creation using lists and for loops. Widgets can be placed into table cells and easily called on again. It is simple to hide/show entire rows or columns.
## Default PyDM imports
from qtpy.QtWidgets import (QVBoxLayout, QLabel,
QTableWidget)
from pydm import Display
from pydm.widgets import PyDMLabel, PyDMLineEdit
from pydm.widgets.related_display_button import PyDMRelatedDisplayButton
class MainWindow(Display):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.main_layout = QVBoxLayout()
self.setLayout(self.main_layout)
## Make a 4x4 table
table = QTableWidget()
table.setRowCount(4)
table.setColumnCount(4)
## Arbitrary list of n pvs
list_of_pvs = ['pv1', 'pv2', 'pv3', 'pv4']
## Create the widgets that will get inserted in the table
for i in range(table.rowCount()):
pv = list_of_pvs[i]
label = QLabel(pv)
readback = PyDMLabel()
readback.channel = pv
line_edit = PyDMLineEdit()
line_edit.channel = pv
related_display = PyDMRelatedDisplayButton()
related_display.filenames = ['my_file']
## Arbitrary list of n widgets
widgets = [label, readback, line_edit, related_display]
## Add the widgets to the table at position i, j
for j in range(table.columnCount()):
table.setCellWidget(i, j, widgets[j])
## Add the whole table to the main layout
self.main_layout.addWidget(table)
## Grab any widget in the table and do something, for ex.
pv1_label = table.cellWidget(0, 0)
pv1_label.setText('Hello, World!')
## Hide any row
table.hideRow(2)
## Show any row
table.showRow(2)
This widget can be used to open both EDM and PyDM files. To open a designated file, a list of filenames is given. If more than one filename is in the list, a dropdown menu is generated to let the user select which file to open.
Local Channels
Using a local channel to set rules based on macros
As a tool for dynamic displays, macros can be used as PV values to trigger rule events. Create a local variable of the form loc://<my_variable_name>?type=str&init=${my_macro}
by setting the channel field of a PyDM Widget. The varaiable can then be called from the rules editor to dynamically change display properties.
QSplitters
QSplitters are a useful type of frame that allows the user to control the size of child widgets by dragging the boundary between them. These splitters can contain any number of widgets, and even allow the user to collapse widgets. More information on QSplitters can be found here: QSplitter - Qt for Python
In designer, widgets can be added to a splitter using the buttons circled in the picture below. The buttons are only selectable when multiple widgets (that aren't already in a layout) are selected.
The default splitter handle's are difficult to see, so the code below can be added to a stylesheet in order to make them more visible:
QSplitter::handle {
background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5,
radius:0.5, fx:0.5, fy:0.5,
stop:0 rgba(121, 121, 121, 255),
stop:0.3 rgba(121, 121, 121, 255),
stop:0.301 rgba(255, 255, 255, 255),
stop:1 rgba(255, 255, 255, 100));
}