Merge branch 'master' of gitlab.psi.ch:cafe/caqtwidgets
This commit is contained in:
Binary file not shown.
Binary file not shown.
14
pvgateway.py
14
pvgateway.py
@@ -96,6 +96,7 @@ class PVGateway(QWidget):
|
||||
notify_unison: bool = False, precision: int = 0,
|
||||
monitor_dbr_time: bool = False):
|
||||
|
||||
|
||||
super().__init__()
|
||||
|
||||
if parent is None:
|
||||
@@ -129,6 +130,10 @@ class PVGateway(QWidget):
|
||||
|
||||
self.color_mode_requested = self.color_mode
|
||||
|
||||
if 'READ' in self.pv_name:
|
||||
print('color mode',self.pv_name, self.color_mode, self.color_mode_requested )
|
||||
|
||||
|
||||
if monitor_callback is not None:
|
||||
self.monitor_callback = monitor_callback
|
||||
else:
|
||||
@@ -176,6 +181,7 @@ class PVGateway(QWidget):
|
||||
self.monitor_id = None
|
||||
self.monitor_dbr_time = monitor_dbr_time
|
||||
self.mutex_post_display = QMutex()
|
||||
self.mutex = QMutex()
|
||||
|
||||
self.precision_user = precision
|
||||
self.has_precision_user = bool(precision)
|
||||
@@ -310,6 +316,7 @@ class PVGateway(QWidget):
|
||||
#The __init__ method of a class is used to initialize new objects,
|
||||
#not create them. As such, it should not return any value.
|
||||
|
||||
|
||||
return #self # used by pvgateway in CAQStripChart
|
||||
|
||||
|
||||
@@ -754,6 +761,7 @@ class PVGateway(QWidget):
|
||||
'''Callback function to be invoked on change of pv value.
|
||||
cafe.getCache and cafe.set operations permitted within callback.
|
||||
'''
|
||||
self.mutex.lock()
|
||||
|
||||
pv_name = pvname
|
||||
pvd = pvdata
|
||||
@@ -785,8 +793,8 @@ class PVGateway(QWidget):
|
||||
else:
|
||||
self.trigger_monitor_float.emit(float(pvd.value[0]), pvd.status,
|
||||
_alarm_severity)
|
||||
|
||||
|
||||
self.mutex.unlock()
|
||||
|
||||
def monitor_start(self):
|
||||
'''Initiate monitor on pv.'''
|
||||
if self.handle > 0:
|
||||
@@ -942,6 +950,8 @@ class PVGateway(QWidget):
|
||||
elif self.qt_object_name == self.PV_DAQ_BS:
|
||||
self.color_mode = self.READBACK_STATIC
|
||||
|
||||
if 'READ' in self.pv_name:
|
||||
print('color mode',self.pv_name, self.color_mode)
|
||||
self._qt_dynamic_property_set(self.color_mode)
|
||||
|
||||
else:
|
||||
|
||||
1910
pvgateway.py:2.9
Normal file
1910
pvgateway.py:2.9
Normal file
File diff suppressed because it is too large
Load Diff
201
pvwidgets.py
201
pvwidgets.py
@@ -1,16 +1,19 @@
|
||||
''' Module with channel access enabled QtWidgets.'''
|
||||
__author__ = 'Jan T. M. Chrin'
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
import collections
|
||||
import numpy as np
|
||||
import re
|
||||
from threading import Lock
|
||||
import time
|
||||
|
||||
|
||||
from sklearn.linear_model import LinearRegression
|
||||
from distutils.version import LooseVersion
|
||||
from functools import reduce as func_reduce
|
||||
|
||||
from qtpy.QtCore import QEventLoop, QPoint, Qt, QThread, QTimer, Signal, Slot
|
||||
from qtpy.QtCore import (QEventLoop, QMutex, QPoint, Qt, QThread, QTimer,
|
||||
Signal, Slot)
|
||||
from qtpy.QtGui import (QCloseEvent, QColor, QCursor, QFont, QFontMetricsF,
|
||||
QIcon, QKeySequence)
|
||||
from qtpy.QtCore import __version__ as QT_VERSION_STR
|
||||
@@ -462,13 +465,13 @@ class CAQMessageButton(QPushButton, PVGateway):
|
||||
self.setFocusPolicy(Qt.StrongFocus)
|
||||
self.setCheckable(True) #Recognizes press and release states
|
||||
|
||||
fm = QFontMetricsF(QFont("Sans Serif", 12))
|
||||
fm = QFontMetricsF(QFont("Sans Serif", 10))
|
||||
qrect = fm.boundingRect(self.suggested_text)
|
||||
|
||||
_width_scaling_factor = 1.0
|
||||
|
||||
self.setText(self.msg_label)
|
||||
self.setFixedHeight((fm.lineSpacing()*2.0))
|
||||
self.setFixedHeight((fm.lineSpacing()*1.8))
|
||||
self.setFixedWidth((qrect.width() * _width_scaling_factor))
|
||||
|
||||
self.qt_property_initial_values(qt_object_name=self.PV_CONTROLLER)
|
||||
@@ -1312,20 +1315,30 @@ class CAQTableWidget(QTableWidget):
|
||||
super().__init__()
|
||||
self.columns_dict = {}
|
||||
_column_dict_value = 0
|
||||
self.columns_dict['PV'] = _column_dict_value
|
||||
if init_column:
|
||||
|
||||
if pv_list_show is not None:
|
||||
if pv_list_show[0]:
|
||||
self.columns_dict['PV'] = _column_dict_value
|
||||
_column_dict_value += 1
|
||||
else:
|
||||
self.columns_dict['PV'] = _column_dict_value
|
||||
_column_dict_value += 1
|
||||
|
||||
if init_column:
|
||||
self.columns_dict['Init'] = _column_dict_value
|
||||
_column_dict_value += 1
|
||||
_column_dict_value += 1
|
||||
|
||||
self.columns_dict['Value'] = _column_dict_value
|
||||
|
||||
if show_timestamp:
|
||||
_column_dict_value += 1
|
||||
self.columns_dict['Timestamp'] = _column_dict_value
|
||||
|
||||
_column_dict_value += 1
|
||||
self.columns_dict['Reconnect'] = _column_dict_value
|
||||
|
||||
self.setWindowModality(Qt.ApplicationModal)
|
||||
self.no_columns = _column_dict_value + 1
|
||||
self.no_columns = _column_dict_value + 1
|
||||
|
||||
self.init_column = init_column
|
||||
|
||||
@@ -1374,9 +1387,13 @@ class CAQTableWidget(QTableWidget):
|
||||
|
||||
_color_mode = [None] * len(self.pv_list)
|
||||
|
||||
if isinstance(color_mode, list):
|
||||
for i in range(0, len(color_mode)):
|
||||
_color_mode[i] = color_mode[i]
|
||||
if color_mode is not None:
|
||||
if isinstance(color_mode, list):
|
||||
for i in range(0, len(color_mode)):
|
||||
_color_mode[i] = color_mode[i]
|
||||
else:
|
||||
for i in range(0, len(_color_mode)):
|
||||
_color_mode[i] = color_mode
|
||||
|
||||
for i in range(0, len(self.pv_list)):
|
||||
|
||||
@@ -1427,7 +1444,8 @@ class CAQTableWidget(QTableWidget):
|
||||
if not self.pv_gateway[i].pv_within_daq_group:
|
||||
self.pv_gateway[i].monitor_start()
|
||||
|
||||
self.update_init_values()
|
||||
if init_column:
|
||||
self.update_init_values()
|
||||
|
||||
self.configure_context_menu()
|
||||
|
||||
@@ -1568,6 +1586,10 @@ class CAQTableWidget(QTableWidget):
|
||||
def update_init_values(self):
|
||||
_start = 0
|
||||
_end = len(self.pv_gateway)
|
||||
if 'Init' in self.columns_dict:
|
||||
_column_no = self.columns_dict['Init']
|
||||
else:
|
||||
return
|
||||
|
||||
for _row in range(_start, _end):
|
||||
_handle = self.pv_gateway[_row].handle
|
||||
@@ -1583,7 +1605,8 @@ class CAQTableWidget(QTableWidget):
|
||||
_f.setPointSize(8)
|
||||
qtwi.setFont(_f)
|
||||
self.setItem(_row, 1, qtwi)
|
||||
self.item(_row, 1).setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
self.item(_row, _column_no).setTextAlignment(Qt.AlignRight |
|
||||
Qt.AlignVCenter)
|
||||
|
||||
|
||||
def configure_widget(self):
|
||||
@@ -1599,8 +1622,10 @@ class CAQTableWidget(QTableWidget):
|
||||
self.resizeColumnsToContents()
|
||||
self.resizeRowsToContents()
|
||||
#self.horizontalHeader().setStretchLastSection(True);
|
||||
self.setColumnWidth(self.columns_dict['PV'], _column_width_pvname)
|
||||
|
||||
if 'PV' in self.columns_dict.keys():
|
||||
self.setColumnWidth(self.columns_dict['PV'], _column_width_pvname)
|
||||
_pv_column = self.columns_dict['PV']
|
||||
|
||||
self.setColumnWidth(self.columns_dict['Value'], _column_width_value)
|
||||
if 'Init' in self.columns_dict.keys():
|
||||
self.setColumnWidth(self.columns_dict['Init'], _column_width_value)
|
||||
@@ -1610,18 +1635,22 @@ class CAQTableWidget(QTableWidget):
|
||||
self.setColumnWidth(self.columns_dict['Reconnect'],
|
||||
_column_width_checkbox)
|
||||
|
||||
_pv_column = self.columns_dict['PV']
|
||||
|
||||
|
||||
for i in range(0, len(self.pv_gateway)):
|
||||
qtwt = QTableWidgetItem(self.pv_list_show[i])
|
||||
f = qtwt.font()
|
||||
f.setPointSize(8)
|
||||
qtwt.setFont(f)
|
||||
istart = 1
|
||||
if 'PV' in self.columns_dict.keys():
|
||||
qtwt = QTableWidgetItem(self.pv_list_show[i])
|
||||
f = qtwt.font()
|
||||
f.setPointSize(8)
|
||||
qtwt.setFont(f)
|
||||
|
||||
self.setItem(i, _pv_column, qtwt)
|
||||
self.item(i, _pv_column).setTextAlignment(Qt.AlignHCenter |
|
||||
Qt.AlignVCenter)
|
||||
for i_column in range(1, self.no_columns-1):
|
||||
self.setItem(i, _pv_column, qtwt)
|
||||
self.item(i, _pv_column).setTextAlignment(Qt.AlignHCenter |
|
||||
Qt.AlignVCenter)
|
||||
else:
|
||||
istart = 0
|
||||
|
||||
for i_column in range(istart, self.no_columns-1):
|
||||
self.setItem(i, i_column, QTableWidgetItem(str("")))
|
||||
self.item(i, i_column).setTextAlignment(Qt.AlignHCenter |
|
||||
Qt.AlignVCenter)
|
||||
@@ -1644,14 +1673,14 @@ class CAQTableWidget(QTableWidget):
|
||||
_f = self.init_value_button.font()
|
||||
_f.setPointSize(8)
|
||||
self.init_value_button.setFont(_f)
|
||||
self.init_value_button.setFixedWidth(80)
|
||||
self.init_value_button.setFixedWidth(64)
|
||||
self.init_value_button.clicked.connect(self.update_init_values)
|
||||
self.init_value_button.setToolTip(
|
||||
("Stores initial, pre-measurement value. Update is also " +
|
||||
"typically executed automatically before new optics are set."))
|
||||
"typically executed automatically before analysis procedure."))
|
||||
_init_layout.addWidget(self.init_value_button)
|
||||
_init_layout.setAlignment(Qt.AlignRight)
|
||||
_init_layout.setContentsMargins(1, 1, 0, 0) #Required
|
||||
_init_layout.setAlignment(Qt.AlignCenter)
|
||||
_init_layout.setContentsMargins(1, 1, 1, 0) #Required
|
||||
self.init_widget.setLayout(_init_layout)
|
||||
self.setCellWidget(len(self.pv_gateway), 1, self.init_widget)
|
||||
|
||||
@@ -1669,10 +1698,10 @@ class CAQTableWidget(QTableWidget):
|
||||
self.restore_value_button.setToolTip(
|
||||
("Restore devices to their pre-measurement values"))
|
||||
_restore_layout.addWidget(self.restore_value_button)
|
||||
_restore_layout.setAlignment(Qt.AlignRight)
|
||||
_restore_layout.setAlignment(Qt.AlignCenter)
|
||||
_restore_layout.setContentsMargins(1, 1, 0, 0)
|
||||
_restore_widget.setLayout(_restore_layout)
|
||||
self.setCellWidget(len(self.pv_gateway), 2, _restore_widget)
|
||||
self.setCellWidget(len(self.pv_gateway), 0, _restore_widget)
|
||||
|
||||
#Do not display no for last row (Reconnect button)
|
||||
_row_digit_last_cell = QTableWidgetItem(str(""))
|
||||
@@ -1689,8 +1718,8 @@ class CAQTableWidget(QTableWidget):
|
||||
f.setPointSize(8)
|
||||
self.reconnect_button.setFixedWidth(100)
|
||||
else:
|
||||
f.setPointSize(6)
|
||||
self.reconnect_button.setFixedWidth(58)
|
||||
f.setPointSize(7) #6
|
||||
self.reconnect_button.setFixedWidth(66) #58
|
||||
|
||||
self.reconnect_button.setFont(f)
|
||||
|
||||
@@ -1712,9 +1741,10 @@ class CAQTableWidget(QTableWidget):
|
||||
self.setCellWidget(len(self.pv_gateway), self.no_columns-1,
|
||||
self.cb_item_all)
|
||||
|
||||
header_item = QTableWidgetItem("Process Variable")
|
||||
|
||||
self.setHorizontalHeaderItem(self.columns_dict['PV'], header_item)
|
||||
if 'PV' in self.columns_dict.keys():
|
||||
header_item = QTableWidgetItem("Process Variable")
|
||||
self.setHorizontalHeaderItem(self.columns_dict['PV'], header_item)
|
||||
|
||||
if 'Init' in self.columns_dict.keys():
|
||||
self.setHorizontalHeaderItem(self.columns_dict['Init'],
|
||||
@@ -1749,9 +1779,13 @@ class CAQTableWidget(QTableWidget):
|
||||
self.setMinimumWidth(_min_table_width)
|
||||
|
||||
for _row in range(0, len(self.pv_gateway)):
|
||||
self.item(_row, _pv_column).setForeground(QColor("#000000"))
|
||||
if 'PV' in self.columns_dict.keys():
|
||||
self.item(_row, _pv_column).setForeground(QColor("#000000"))
|
||||
istart = 1
|
||||
else:
|
||||
istart = 0
|
||||
|
||||
for i_column in range(1, self.no_columns-2):
|
||||
for i_column in range(istart, self.no_columns-2):
|
||||
self.item(_row, i_column).setForeground(QColor("#000000"))
|
||||
self.item(_row, i_column).setTextAlignment(Qt.AlignRight |
|
||||
Qt.AlignVCenter)
|
||||
@@ -1834,16 +1868,16 @@ class CAQTableWidget(QTableWidget):
|
||||
if _prop == self.pv_gateway[_row].READBACK_ALARM:
|
||||
|
||||
if alarm_severity == self.pv_gateway[_row].cyca.SEV_MAJOR:
|
||||
_bgcolor = self.pv_gateway[_row].settings.fgAlarmMajor
|
||||
_bgcolor = self.pv_gateway[_row].fg_alarm_major
|
||||
_fgcolor = "black"
|
||||
elif alarm_severity == self.pv_gateway[_row].cyca.SEV_MINOR:
|
||||
_bgcolor = self.pv_gateway[_row].settings.fgAlarmMinor
|
||||
_bgcolor = self.pv_gateway[_row].fg_alarm_minor
|
||||
_fgcolor = "black"
|
||||
elif alarm_severity == self.pv_gateway[_row].cyca.SEV_INVALID:
|
||||
_bgcolor = self.pv_gateway[_row].settings.fgAlarmInvalid
|
||||
_bgcolor = self.pv_gateway[_row].fg_alarm_invalid
|
||||
_fgcolor = "#777777"
|
||||
else:
|
||||
_bgcolor = self.pv_gateway[_row].settings.fgAlarmNoAlarm
|
||||
_bgcolor = self.pv_gateway[_row].fg_alarm_noalarm
|
||||
_fgcolor = "black"
|
||||
|
||||
#Colors for bg/fg reversed as is the old norm
|
||||
@@ -2455,6 +2489,7 @@ class QNoDockWidget(QDockWidget):
|
||||
class CAQStripChart(PlotWidget):
|
||||
'''Channel access enabled pyqtgraph.PlotWidget'''
|
||||
|
||||
|
||||
def __init__(self, parent=None, pv_list: list = ['PV_NAME_NOT_GIVEN'],
|
||||
monitor_callback=None, pv_within_daq_group: bool = False,
|
||||
color_mode=None, show_units: bool = False, prefix: str = "",
|
||||
@@ -2477,17 +2512,18 @@ class CAQStripChart(PlotWidget):
|
||||
self.val_previous = [None] * self.no_channels
|
||||
|
||||
self.curve = [None] * self.no_channels
|
||||
|
||||
print (self.pv_list, flush=True)
|
||||
|
||||
|
||||
for i in range (0, len(self.pv_list)):
|
||||
self.pv_gateway[i] = PVGateway().__init__(
|
||||
parent, pv_list[i], monitor_callback, pv_within_daq_group,
|
||||
|
||||
self.pv_gateway[i] = PVGateway(
|
||||
parent, self.pv_list[i], monitor_callback, pv_within_daq_group,
|
||||
color_mode, show_units, prefix, suffix,
|
||||
#connect_callback=self.py_connect_callback,
|
||||
connect_triggers=False, notify_freq_hz=notify_freq_hz,
|
||||
monitor_dbr_time = True)
|
||||
|
||||
print(i, pv_list[i], "gateway object", self.pv_gateway[i])
|
||||
|
||||
self.pv_gateway[i].is_initialize_complete()
|
||||
|
||||
|
||||
@@ -2529,8 +2565,8 @@ class CAQStripChart(PlotWidget):
|
||||
|
||||
# Data stuff
|
||||
self._interval = int(sampleinterval*1000)
|
||||
self._bufsize = 9000 #int(timewindow/0.33)
|
||||
self._bufsize2 = 9000 # int(timewindow/1.33)
|
||||
self._bufsize = 10000 #int(timewindow/0.33)
|
||||
self._bufsize2 = 10000 # int(timewindow/1.33)
|
||||
self.databuffer = [None] * self.no_channels
|
||||
self.timebuffer = [None] * self.no_channels
|
||||
self.x = [None] * self.no_channels
|
||||
@@ -2561,13 +2597,37 @@ class CAQStripChart(PlotWidget):
|
||||
if title is not None:
|
||||
self.setTitle(str(title)) #self.pv_gateway[0].pv_name)
|
||||
self.showGrid(x=True, y=True)
|
||||
self.setLabel('left', ylabel, self.pv_gateway[0].units)
|
||||
#self.setLabel('left', ylabel, self.pv_gateway[0].units)
|
||||
self.setLabel('bottom', 'time', 's')
|
||||
self.setBackground((60, 60, 60)) #247, 236, 249))
|
||||
self.setLimits(yMin=-0.11)
|
||||
#self.setLimits(yMin=-0.11)
|
||||
#self.setLimits(yMin=-1, yMax=1)
|
||||
|
||||
ax = pg.AxisItem('left')
|
||||
ax.enableAutoSIPrefix(enable=False)
|
||||
ax.setLabel(ylabel, self.pv_gateway[0].units)
|
||||
ax.setGrid(155)
|
||||
|
||||
ay = pg.AxisItem('bottom')
|
||||
ay.enableAutoSIPrefix(enable=False)
|
||||
ay.setLabel('time', 'min')
|
||||
ay.setGrid(175)
|
||||
|
||||
if 'BPM' in text_label:
|
||||
ax.setTickSpacing(0.2, 0.1)
|
||||
#ax.setRange(-1, 1)
|
||||
#ax.setParentItem(self.graphicsItem())
|
||||
axitems = {}
|
||||
axitems['left'] = ax
|
||||
axitems['bottom'] = ay
|
||||
|
||||
self.setAxisItems(axitems)
|
||||
|
||||
pg.setConfigOption('leftButtonPan', False)
|
||||
|
||||
self.plotItem.setMouseEnabled(y=True) # Only allow zoom in X-axis
|
||||
self.plotItem.setMouseEnabled(x=True) # Only allow zoom in Y-axis
|
||||
|
||||
#(125, 249, 255)
|
||||
if self.pen_color_idx == 0:
|
||||
pen_list = [ (255, 155, 0), (255,255,0), (0, 180, 255) ]
|
||||
@@ -2601,20 +2661,37 @@ class CAQStripChart(PlotWidget):
|
||||
|
||||
@Slot(object, int)
|
||||
def receive_monitor_dbr_time(self, pvdata, alarm_severity):
|
||||
|
||||
#if not self.mutex.tryLock(): #locked():
|
||||
# print("Event locked", pvdata.ts[0], pvdata.ts[1])
|
||||
# return
|
||||
|
||||
|
||||
#self.mutex.lock() #acquire()
|
||||
|
||||
_row = self.pv2item_dict[self.sender()]
|
||||
#print("row, value from pvdata==>", _row, pvdata.value[0], self.pv_gateway[_row].pv_name)
|
||||
|
||||
|
||||
ts_now = pvdata.ts[0] + pvdata.ts[1] * 10**(-9)
|
||||
ts_previous = (self.pvd_previous_list[_row].ts[0] +
|
||||
self.pvd_previous_list[_row].ts[1] * 10**(-9))
|
||||
self.pvd_previous_list[_row].ts[1] * 10**(-9))
|
||||
ts_delta = ts_now - ts_previous
|
||||
|
||||
|
||||
if (pvdata.ts[0] == self.pvd_previous_list[_row].ts[0]) and (
|
||||
pvdata.ts[1] == self.pvd_previous_list[_row].ts[1]):
|
||||
pvdata.show()
|
||||
self.pvd_previous_list[_row].show()
|
||||
#print("SAME TIMESTAMP")
|
||||
#pvdata.show()
|
||||
#self.pvd_previous_list[_row].show()
|
||||
#print("================")
|
||||
#self.mutex.unlock() #release()
|
||||
return
|
||||
|
||||
|
||||
if pvdata.ts[0] < self.pvd_previous_list[_row].ts[0]:
|
||||
print("Funny ts value", self.pv_gateway[_row].pv_name)
|
||||
pvdata.show()
|
||||
#self.mutex.unlock() #release()
|
||||
return
|
||||
|
||||
value = pvdata.value[0]
|
||||
#discard first callbacks
|
||||
#if ts_delta > 2.0:
|
||||
@@ -2630,6 +2707,7 @@ class CAQStripChart(PlotWidget):
|
||||
|
||||
highest_ts = self.timebuffer[0][0] \
|
||||
if self.timebuffer[0][0] is not None else 0
|
||||
|
||||
for i in range(1, len(self.timebuffer)):
|
||||
if self.timebuffer[i][0] is None:
|
||||
continue
|
||||
@@ -2655,9 +2733,10 @@ class CAQStripChart(PlotWidget):
|
||||
# self.curve[row].setData(self.x_shifted[row], self.y[row][idx:])
|
||||
|
||||
self.curve[_row].setData(self.x_shifted[_row], self.y[_row][idx:])
|
||||
self.time_delta[_row] = (
|
||||
pvdata.ts[0] + pvdata.ts[1]*10**(-9)) - self.time_zero[0]
|
||||
|
||||
self.time_delta[_row] = ((
|
||||
pvdata.ts[0] + pvdata.ts[1]*10**(-9)) - self.time_zero[0])/60
|
||||
|
||||
#self.mutex.unlock() #release()
|
||||
#QApplication.processEvents()
|
||||
|
||||
|
||||
|
||||
3461
pvwidgets.py:2.9
Normal file
3461
pvwidgets.py:2.9
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user